1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source view_util.vim
5source vim9.vim
6source screendump.vim
7
8func Test_def_basic()
9  def SomeFunc(): string
10    return 'yes'
11  enddef
12  call assert_equal('yes', SomeFunc())
13endfunc
14
15def ReturnString(): string
16  return 'string'
17enddef
18
19def ReturnNumber(): number
20  return 123
21enddef
22
23let g:notNumber = 'string'
24
25def ReturnGlobal(): number
26  return g:notNumber
27enddef
28
29def Test_return_something()
30  assert_equal('string', ReturnString())
31  assert_equal(123, ReturnNumber())
32  assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
33enddef
34
35def Test_missing_return()
36  CheckDefFailure(['def Missing(): number',
37                   '  if g:cond',
38                   '    echo "no return"',
39                   '  else',
40                   '    return 0',
41                   '  endif'
42                   'enddef'], 'E1027:')
43  CheckDefFailure(['def Missing(): number',
44                   '  if g:cond',
45                   '    return 1',
46                   '  else',
47                   '    echo "no return"',
48                   '  endif'
49                   'enddef'], 'E1027:')
50  CheckDefFailure(['def Missing(): number',
51                   '  if g:cond',
52                   '    return 1',
53                   '  else',
54                   '    return 2',
55                   '  endif'
56                   '  return 3'
57                   'enddef'], 'E1095:')
58enddef
59
60let s:nothing = 0
61def ReturnNothing()
62  s:nothing = 1
63  if true
64    return
65  endif
66  s:nothing = 2
67enddef
68
69def Test_return_nothing()
70  ReturnNothing()
71  assert_equal(1, s:nothing)
72enddef
73
74func Increment()
75  let g:counter += 1
76endfunc
77
78def Test_call_ufunc_count()
79  g:counter = 1
80  Increment()
81  Increment()
82  Increment()
83  # works with and without :call
84  assert_equal(4, g:counter)
85  call assert_equal(4, g:counter)
86  unlet g:counter
87enddef
88
89def MyVarargs(arg: string, ...rest: list<string>): string
90  let res = arg
91  for s in rest
92    res ..= ',' .. s
93  endfor
94  return res
95enddef
96
97def Test_call_varargs()
98  assert_equal('one', MyVarargs('one'))
99  assert_equal('one,two', MyVarargs('one', 'two'))
100  assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
101enddef
102
103def MyDefaultArgs(name = 'string'): string
104  return name
105enddef
106
107def MyDefaultSecond(name: string, second: bool  = true): string
108  return second ? name : 'none'
109enddef
110
111def Test_call_default_args()
112  assert_equal('string', MyDefaultArgs())
113  assert_equal('one', MyDefaultArgs('one'))
114  assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
115
116  assert_equal('test', MyDefaultSecond('test'))
117  assert_equal('test', MyDefaultSecond('test', true))
118  assert_equal('none', MyDefaultSecond('test', false))
119
120  CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:')
121  CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: argument 1: type mismatch, expected number but got string')
122enddef
123
124def Test_nested_function()
125  def Nested(arg: string): string
126    return 'nested ' .. arg
127  enddef
128  assert_equal('nested function', Nested('function'))
129
130  CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
131  CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
132
133  CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
134  CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
135  CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
136enddef
137
138func Test_call_default_args_from_func()
139  call assert_equal('string', MyDefaultArgs())
140  call assert_equal('one', MyDefaultArgs('one'))
141  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
142endfunc
143
144def Test_nested_global_function()
145  let lines =<< trim END
146      vim9script
147      def Outer()
148          def g:Inner(): string
149              return 'inner'
150          enddef
151      enddef
152      defcompile
153      Outer()
154      assert_equal('inner', g:Inner())
155      delfunc g:Inner
156      Outer()
157      assert_equal('inner', g:Inner())
158      delfunc g:Inner
159      Outer()
160      assert_equal('inner', g:Inner())
161      delfunc g:Inner
162  END
163  CheckScriptSuccess(lines)
164
165  lines =<< trim END
166      vim9script
167      def Outer()
168          def g:Inner(): string
169              return 'inner'
170          enddef
171      enddef
172      defcompile
173      Outer()
174      Outer()
175  END
176  CheckScriptFailure(lines, "E122:")
177
178  lines =<< trim END
179      vim9script
180      def Func()
181        echo 'script'
182      enddef
183      def Outer()
184        def Func()
185          echo 'inner'
186        enddef
187      enddef
188      defcompile
189  END
190  CheckScriptFailure(lines, "E1073:")
191enddef
192
193def Test_global_local_function()
194  let lines =<< trim END
195      vim9script
196      def g:Func(): string
197          return 'global'
198      enddef
199      def Func(): string
200          return 'local'
201      enddef
202      assert_equal('global', g:Func())
203      assert_equal('local', Func())
204  END
205  CheckScriptSuccess(lines)
206enddef
207
208func TakesOneArg(arg)
209  echo a:arg
210endfunc
211
212def Test_call_wrong_args()
213  call CheckDefFailure(['TakesOneArg()'], 'E119:')
214  call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
215  call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
216  call CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:')
217enddef
218
219" Default arg and varargs
220def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
221  let res = one .. ',' .. two
222  for s in rest
223    res ..= ',' .. s
224  endfor
225  return res
226enddef
227
228def Test_call_def_varargs()
229  call assert_fails('call MyDefVarargs()', 'E119:')
230  assert_equal('one,foo', MyDefVarargs('one'))
231  assert_equal('one,two', MyDefVarargs('one', 'two'))
232  assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
233  CheckDefFailure(['MyDefVarargs("one", 22)'],
234      'E1013: argument 2: type mismatch, expected string but got number')
235  CheckDefFailure(['MyDefVarargs("one", "two", 123)'],
236      'E1013: argument 3: type mismatch, expected string but got number')
237
238  let lines =<< trim END
239      vim9script
240      def Func(...l: list<string>)
241        echo l
242      enddef
243      Func('a', 'b', 'c')
244  END
245  CheckScriptSuccess(lines)
246
247  lines =<< trim END
248      vim9script
249      def Func(...l: list<string>)
250        echo l
251      enddef
252      Func()
253  END
254  CheckScriptSuccess(lines)
255
256  lines =<< trim END
257      vim9script
258      def Func(...l: list<string>)
259        echo l
260      enddef
261      Func(1, 2, 3)
262  END
263  CheckScriptFailure(lines, 'E1013:')
264
265  lines =<< trim END
266      vim9script
267      def Func(...l: list<string>)
268        echo l
269      enddef
270      Func('a', 9)
271  END
272  CheckScriptFailure(lines, 'E1013:')
273
274  lines =<< trim END
275      vim9script
276      def Func(...l: list<string>)
277        echo l
278      enddef
279      Func(1, 'a')
280  END
281  CheckScriptFailure(lines, 'E1013:')
282enddef
283
284let s:value = ''
285
286def FuncOneDefArg(opt = 'text')
287  s:value = opt
288enddef
289
290def FuncTwoDefArg(nr = 123, opt = 'text'): string
291  return nr .. opt
292enddef
293
294def FuncVarargs(...arg: list<string>): string
295  return join(arg, ',')
296enddef
297
298def Test_func_type_varargs()
299  let RefDefArg: func(?string)
300  RefDefArg = FuncOneDefArg
301  RefDefArg()
302  assert_equal('text', s:value)
303  RefDefArg('some')
304  assert_equal('some', s:value)
305
306  let RefDef2Arg: func(?number, ?string): string
307  RefDef2Arg = FuncTwoDefArg
308  assert_equal('123text', RefDef2Arg())
309  assert_equal('99text', RefDef2Arg(99))
310  assert_equal('77some', RefDef2Arg(77, 'some'))
311
312  call CheckDefFailure(['let RefWrong: func(string?)'], 'E1010:')
313  call CheckDefFailure(['let RefWrong: func(?string, string)'], 'E1007:')
314
315  let RefVarargs: func(...list<string>): string
316  RefVarargs = FuncVarargs
317  assert_equal('', RefVarargs())
318  assert_equal('one', RefVarargs('one'))
319  assert_equal('one,two', RefVarargs('one', 'two'))
320
321  call CheckDefFailure(['let RefWrong: func(...list<string>, string)'], 'E110:')
322  call CheckDefFailure(['let RefWrong: func(...list<string>, ?string)'], 'E110:')
323enddef
324
325" Only varargs
326def MyVarargsOnly(...args: list<string>): string
327  return join(args, ',')
328enddef
329
330def Test_call_varargs_only()
331  assert_equal('', MyVarargsOnly())
332  assert_equal('one', MyVarargsOnly('one'))
333  assert_equal('one,two', MyVarargsOnly('one', 'two'))
334  call CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: argument 1: type mismatch, expected string but got number')
335  call CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: argument 2: type mismatch, expected string but got number')
336enddef
337
338def Test_using_var_as_arg()
339  call writefile(['def Func(x: number)',  'let x = 234', 'enddef', 'defcompile'], 'Xdef')
340  call assert_fails('so Xdef', 'E1006:')
341  call delete('Xdef')
342enddef
343
344def DictArg(arg: dict<string>)
345  arg['key'] = 'value'
346enddef
347
348def ListArg(arg: list<string>)
349  arg[0] = 'value'
350enddef
351
352def Test_assign_to_argument()
353  # works for dict and list
354  let d: dict<string> = {}
355  DictArg(d)
356  assert_equal('value', d['key'])
357  let l: list<string> = []
358  ListArg(l)
359  assert_equal('value', l[0])
360
361  call CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:')
362enddef
363
364def Test_call_func_defined_later()
365  call assert_equal('one', g:DefinedLater('one'))
366  call assert_fails('call NotDefined("one")', 'E117:')
367enddef
368
369func DefinedLater(arg)
370  return a:arg
371endfunc
372
373def Test_call_funcref()
374  assert_equal(3, g:SomeFunc('abc'))
375  assert_fails('NotAFunc()', 'E117:') # comment after call
376  assert_fails('g:NotAFunc()', 'E117:')
377
378  let lines =<< trim END
379    vim9script
380    def RetNumber(): number
381      return 123
382    enddef
383    let Funcref: func: number = function('RetNumber')
384    assert_equal(123, Funcref())
385  END
386  CheckScriptSuccess(lines)
387
388  lines =<< trim END
389    vim9script
390    def RetNumber(): number
391      return 123
392    enddef
393    def Bar(F: func: number): number
394      return F()
395    enddef
396    let Funcref = function('RetNumber')
397    assert_equal(123, Bar(Funcref))
398  END
399  CheckScriptSuccess(lines)
400
401  lines =<< trim END
402    vim9script
403    def UseNumber(nr: number)
404      echo nr
405    enddef
406    let Funcref: func(number) = function('UseNumber')
407    Funcref(123)
408  END
409  CheckScriptSuccess(lines)
410
411  lines =<< trim END
412    vim9script
413    def UseNumber(nr: number)
414      echo nr
415    enddef
416    let Funcref: func(string) = function('UseNumber')
417  END
418  CheckScriptFailure(lines, 'E1013: type mismatch, expected func(string) but got func(number)')
419
420  lines =<< trim END
421    vim9script
422    def EchoNr(nr = 34)
423      g:echo = nr
424    enddef
425    let Funcref: func(?number) = function('EchoNr')
426    Funcref()
427    assert_equal(34, g:echo)
428    Funcref(123)
429    assert_equal(123, g:echo)
430  END
431  CheckScriptSuccess(lines)
432
433  lines =<< trim END
434    vim9script
435    def EchoList(...l: list<number>)
436      g:echo = l
437    enddef
438    let Funcref: func(...list<number>) = function('EchoList')
439    Funcref()
440    assert_equal([], g:echo)
441    Funcref(1, 2, 3)
442    assert_equal([1, 2, 3], g:echo)
443  END
444  CheckScriptSuccess(lines)
445
446  lines =<< trim END
447    vim9script
448    def OptAndVar(nr: number, opt = 12, ...l: list<number>): number
449      g:optarg = opt
450      g:listarg = l
451      return nr
452    enddef
453    let Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar')
454    assert_equal(10, Funcref(10))
455    assert_equal(12, g:optarg)
456    assert_equal([], g:listarg)
457
458    assert_equal(11, Funcref(11, 22))
459    assert_equal(22, g:optarg)
460    assert_equal([], g:listarg)
461
462    assert_equal(17, Funcref(17, 18, 1, 2, 3))
463    assert_equal(18, g:optarg)
464    assert_equal([1, 2, 3], g:listarg)
465  END
466  CheckScriptSuccess(lines)
467enddef
468
469let SomeFunc = function('len')
470let NotAFunc = 'text'
471
472def CombineFuncrefTypes()
473  # same arguments, different return type
474  let Ref1: func(bool): string
475  let Ref2: func(bool): number
476  let Ref3: func(bool): any
477  Ref3 = g:cond ? Ref1 : Ref2
478
479  # different number of arguments
480  let Refa1: func(bool): number
481  let Refa2: func(bool, number): number
482  let Refa3: func: number
483  Refa3 = g:cond ? Refa1 : Refa2
484
485  # different argument types
486  let Refb1: func(bool, string): number
487  let Refb2: func(string, number): number
488  let Refb3: func(any, any): number
489  Refb3 = g:cond ? Refb1 : Refb2
490enddef
491
492def FuncWithForwardCall()
493  return g:DefinedEvenLater("yes")
494enddef
495
496def DefinedEvenLater(arg: string): string
497  return arg
498enddef
499
500def Test_error_in_nested_function()
501  # Error in called function requires unwinding the call stack.
502  assert_fails('call FuncWithForwardCall()', 'E1096')
503enddef
504
505def Test_return_type_wrong()
506  CheckScriptFailure([
507        'def Func(): number',
508        'return "a"',
509        'enddef',
510        'defcompile'], 'expected number but got string')
511  CheckScriptFailure([
512        'def Func(): string',
513        'return 1',
514        'enddef',
515        'defcompile'], 'expected string but got number')
516  CheckScriptFailure([
517        'def Func(): void',
518        'return "a"',
519        'enddef',
520        'defcompile'],
521        'E1096: Returning a value in a function without a return type')
522  CheckScriptFailure([
523        'def Func()',
524        'return "a"',
525        'enddef',
526        'defcompile'],
527        'E1096: Returning a value in a function without a return type')
528
529  CheckScriptFailure([
530        'def Func(): number',
531        'return',
532        'enddef',
533        'defcompile'], 'E1003:')
534
535  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
536  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
537  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
538
539  CheckScriptFailure([
540        'vim9script',
541        'def FuncB()',
542        '  return 123',
543        'enddef',
544        'def FuncA()',
545        '   FuncB()',
546        'enddef',
547        'defcompile'], 'E1096:')
548enddef
549
550def Test_arg_type_wrong()
551  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
552  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
553  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
554  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
555enddef
556
557def Test_vim9script_call()
558  let lines =<< trim END
559    vim9script
560    let var = ''
561    def MyFunc(arg: string)
562       var = arg
563    enddef
564    MyFunc('foobar')
565    assert_equal('foobar', var)
566
567    let str = 'barfoo'
568    str->MyFunc()
569    assert_equal('barfoo', var)
570
571    g:value = 'value'
572    g:value->MyFunc()
573    assert_equal('value', var)
574
575    let listvar = []
576    def ListFunc(arg: list<number>)
577       listvar = arg
578    enddef
579    [1, 2, 3]->ListFunc()
580    assert_equal([1, 2, 3], listvar)
581
582    let dictvar = {}
583    def DictFunc(arg: dict<number>)
584       dictvar = arg
585    enddef
586    {'a': 1, 'b': 2}->DictFunc()
587    assert_equal(#{a: 1, b: 2}, dictvar)
588    def CompiledDict()
589      {'a': 3, 'b': 4}->DictFunc()
590    enddef
591    CompiledDict()
592    assert_equal(#{a: 3, b: 4}, dictvar)
593
594    #{a: 3, b: 4}->DictFunc()
595    assert_equal(#{a: 3, b: 4}, dictvar)
596
597    ('text')->MyFunc()
598    assert_equal('text', var)
599    ("some")->MyFunc()
600    assert_equal('some', var)
601
602    # line starting with single quote is not a mark
603    # line starting with double quote can be a method call
604    'asdfasdf'->MyFunc()
605    assert_equal('asdfasdf', var)
606    "xyz"->MyFunc()
607    assert_equal('xyz', var)
608
609    def UseString()
610      'xyork'->MyFunc()
611    enddef
612    UseString()
613    assert_equal('xyork', var)
614
615    def UseString2()
616      "knife"->MyFunc()
617    enddef
618    UseString2()
619    assert_equal('knife', var)
620
621    # prepending a colon makes it a mark
622    new
623    setline(1, ['aaa', 'bbb', 'ccc'])
624    normal! 3Gmt1G
625    :'t
626    assert_equal(3, getcurpos()[1])
627    bwipe!
628
629    MyFunc(
630        'continued'
631        )
632    assert_equal('continued',
633            var
634            )
635
636    call MyFunc(
637        'more'
638          ..
639          'lines'
640        )
641    assert_equal(
642        'morelines',
643        var)
644  END
645  writefile(lines, 'Xcall.vim')
646  source Xcall.vim
647  delete('Xcall.vim')
648enddef
649
650def Test_vim9script_call_fail_decl()
651  let lines =<< trim END
652    vim9script
653    let var = ''
654    def MyFunc(arg: string)
655       let var = 123
656    enddef
657    defcompile
658  END
659  CheckScriptFailure(lines, 'E1054:')
660enddef
661
662def Test_vim9script_call_fail_type()
663  let lines =<< trim END
664    vim9script
665    def MyFunc(arg: string)
666      echo arg
667    enddef
668    MyFunc(1234)
669  END
670  CheckScriptFailure(lines, 'E1013: type mismatch, expected string but got number')
671enddef
672
673def Test_vim9script_call_fail_const()
674  let lines =<< trim END
675    vim9script
676    const var = ''
677    def MyFunc(arg: string)
678       var = 'asdf'
679    enddef
680    defcompile
681  END
682  writefile(lines, 'Xcall_const.vim')
683  assert_fails('source Xcall_const.vim', 'E46:')
684  delete('Xcall_const.vim')
685enddef
686
687" Test that inside :function a Python function can be defined, :def is not
688" recognized.
689func Test_function_python()
690  CheckFeature python3
691  let py = 'python3'
692  execute py "<< EOF"
693def do_something():
694  return 1
695EOF
696endfunc
697
698def Test_delfunc()
699  let lines =<< trim END
700    vim9script
701    def g:GoneSoon()
702      echo 'hello'
703    enddef
704
705    def CallGoneSoon()
706      GoneSoon()
707    enddef
708    defcompile
709
710    delfunc g:GoneSoon
711    CallGoneSoon()
712  END
713  writefile(lines, 'XToDelFunc')
714  assert_fails('so XToDelFunc', 'E933')
715  assert_fails('so XToDelFunc', 'E933')
716
717  delete('XToDelFunc')
718enddef
719
720def Test_redef_failure()
721  call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
722  so Xdef
723  call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
724  so Xdef
725  call writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
726  call assert_fails('so Xdef', 'E1027:')
727  call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
728  so Xdef
729  call delete('Xdef')
730
731  call assert_equal(0, g:Func0())
732  call assert_equal('Func1', g:Func1())
733  call assert_equal('Func2', g:Func2())
734
735  delfunc! Func0
736  delfunc! Func1
737  delfunc! Func2
738enddef
739
740def Test_vim9script_func()
741  let lines =<< trim END
742    vim9script
743    func Func(arg)
744      echo a:arg
745    endfunc
746    Func('text')
747  END
748  writefile(lines, 'XVim9Func')
749  so XVim9Func
750
751  delete('XVim9Func')
752enddef
753
754" Test for internal functions returning different types
755func Test_InternalFuncRetType()
756  let lines =<< trim END
757    def RetFloat(): float
758      return ceil(1.456)
759    enddef
760
761    def RetListAny(): list<any>
762      return items({'k' : 'v'})
763    enddef
764
765    def RetListString(): list<string>
766      return split('a:b:c', ':')
767    enddef
768
769    def RetListDictAny(): list<dict<any>>
770      return getbufinfo()
771    enddef
772
773    def RetDictNumber(): dict<number>
774      return wordcount()
775    enddef
776
777    def RetDictString(): dict<string>
778      return environ()
779    enddef
780  END
781  call writefile(lines, 'Xscript')
782  source Xscript
783
784  call assert_equal(2.0, RetFloat())
785  call assert_equal([['k', 'v']], RetListAny())
786  call assert_equal(['a', 'b', 'c'], RetListString())
787  call assert_notequal([], RetListDictAny())
788  call assert_notequal({}, RetDictNumber())
789  call assert_notequal({}, RetDictString())
790  call delete('Xscript')
791endfunc
792
793" Test for passing too many or too few arguments to internal functions
794func Test_internalfunc_arg_error()
795  let l =<< trim END
796    def! FArgErr(): float
797      return ceil(1.1, 2)
798    enddef
799    defcompile
800  END
801  call writefile(l, 'Xinvalidarg')
802  call assert_fails('so Xinvalidarg', 'E118:')
803  let l =<< trim END
804    def! FArgErr(): float
805      return ceil()
806    enddef
807    defcompile
808  END
809  call writefile(l, 'Xinvalidarg')
810  call assert_fails('so Xinvalidarg', 'E119:')
811  call delete('Xinvalidarg')
812endfunc
813
814let s:funcResult = 0
815
816def FuncNoArgNoRet()
817  funcResult = 11
818enddef
819
820def FuncNoArgRetNumber(): number
821  funcResult = 22
822  return 1234
823enddef
824
825def FuncNoArgRetString(): string
826  funcResult = 45
827  return 'text'
828enddef
829
830def FuncOneArgNoRet(arg: number)
831  funcResult = arg
832enddef
833
834def FuncOneArgRetNumber(arg: number): number
835  funcResult = arg
836  return arg
837enddef
838
839def FuncTwoArgNoRet(one: bool, two: number)
840  funcResult = two
841enddef
842
843def FuncOneArgRetString(arg: string): string
844  return arg
845enddef
846
847def FuncOneArgRetAny(arg: any): any
848  return arg
849enddef
850
851def Test_func_type()
852  let Ref1: func()
853  funcResult = 0
854  Ref1 = FuncNoArgNoRet
855  Ref1()
856  assert_equal(11, funcResult)
857
858  let Ref2: func
859  funcResult = 0
860  Ref2 = FuncNoArgNoRet
861  Ref2()
862  assert_equal(11, funcResult)
863
864  funcResult = 0
865  Ref2 = FuncOneArgNoRet
866  Ref2(12)
867  assert_equal(12, funcResult)
868
869  funcResult = 0
870  Ref2 = FuncNoArgRetNumber
871  assert_equal(1234, Ref2())
872  assert_equal(22, funcResult)
873
874  funcResult = 0
875  Ref2 = FuncOneArgRetNumber
876  assert_equal(13, Ref2(13))
877  assert_equal(13, funcResult)
878enddef
879
880def Test_repeat_return_type()
881  let res = 0
882  for n in repeat([1], 3)
883    res += n
884  endfor
885  assert_equal(3, res)
886
887  res = 0
888  for n in add([1, 2], 3)
889    res += n
890  endfor
891  assert_equal(6, res)
892enddef
893
894def Test_argv_return_type()
895  next fileone filetwo
896  let res = ''
897  for name in argv()
898    res ..= name
899  endfor
900  assert_equal('fileonefiletwo', res)
901enddef
902
903def Test_func_type_part()
904  let RefVoid: func: void
905  RefVoid = FuncNoArgNoRet
906  RefVoid = FuncOneArgNoRet
907  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
908  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
909
910  let RefAny: func(): any
911  RefAny = FuncNoArgRetNumber
912  RefAny = FuncNoArgRetString
913  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
914  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
915
916  let RefNr: func: number
917  RefNr = FuncNoArgRetNumber
918  RefNr = FuncOneArgRetNumber
919  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
920  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
921
922  let RefStr: func: string
923  RefStr = FuncNoArgRetString
924  RefStr = FuncOneArgRetString
925  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
926  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
927enddef
928
929def Test_func_type_fails()
930  CheckDefFailure(['let ref1: func()'], 'E704:')
931
932  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
933  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)')
934  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number')
935  CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)')
936  CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)')
937  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)')
938
939  call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
940  call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
941  call CheckDefFailure(['let RefWrong: func(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)'], 'E740:')
942  call CheckDefFailure(['let RefWrong: func(bool):string'], 'E1069:')
943enddef
944
945def Test_func_return_type()
946  let nr: number
947  nr = FuncNoArgRetNumber()
948  assert_equal(1234, nr)
949
950  nr = FuncOneArgRetAny(122)
951  assert_equal(122, nr)
952
953  let str: string
954  str = FuncOneArgRetAny('yes')
955  assert_equal('yes', str)
956
957  CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1013: type mismatch, expected string but got number')
958enddef
959
960def MultiLine(
961    arg1: string,
962    arg2 = 1234,
963    ...rest: list<string>
964      ): string
965  return arg1 .. arg2 .. join(rest, '-')
966enddef
967
968def MultiLineComment(
969    arg1: string, # comment
970    arg2 = 1234, # comment
971    ...rest: list<string> # comment
972      ): string # comment
973  return arg1 .. arg2 .. join(rest, '-')
974enddef
975
976def Test_multiline()
977  assert_equal('text1234', MultiLine('text'))
978  assert_equal('text777', MultiLine('text', 777))
979  assert_equal('text777one', MultiLine('text', 777, 'one'))
980  assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
981enddef
982
983func Test_multiline_not_vim9()
984  call assert_equal('text1234', MultiLine('text'))
985  call assert_equal('text777', MultiLine('text', 777))
986  call assert_equal('text777one', MultiLine('text', 777, 'one'))
987  call assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
988endfunc
989
990
991" When using CheckScriptFailure() for the below test, E1010 is generated instead
992" of E1056.
993func Test_E1056_1059()
994  let caught_1056 = 0
995  try
996    def F():
997      return 1
998    enddef
999  catch /E1056:/
1000    let caught_1056 = 1
1001  endtry
1002  call assert_equal(1, caught_1056)
1003
1004  let caught_1059 = 0
1005  try
1006    def F5(items : list)
1007      echo 'a'
1008    enddef
1009  catch /E1059:/
1010    let caught_1059 = 1
1011  endtry
1012  call assert_equal(1, caught_1059)
1013endfunc
1014
1015func DelMe()
1016  echo 'DelMe'
1017endfunc
1018
1019def Test_error_reporting()
1020  # comment lines at the start of the function
1021  let lines =<< trim END
1022    " comment
1023    def Func()
1024      # comment
1025      # comment
1026      invalid
1027    enddef
1028    defcompile
1029  END
1030  call writefile(lines, 'Xdef')
1031  try
1032    source Xdef
1033  catch /E476:/
1034    assert_match('Invalid command: invalid', v:exception)
1035    assert_match(', line 3$', v:throwpoint)
1036  endtry
1037
1038  # comment lines after the start of the function
1039  lines =<< trim END
1040    " comment
1041    def Func()
1042      let x = 1234
1043      # comment
1044      # comment
1045      invalid
1046    enddef
1047    defcompile
1048  END
1049  call writefile(lines, 'Xdef')
1050  try
1051    source Xdef
1052  catch /E476:/
1053    assert_match('Invalid command: invalid', v:exception)
1054    assert_match(', line 4$', v:throwpoint)
1055  endtry
1056
1057  call delete('Xdef')
1058enddef
1059
1060def Test_deleted_function()
1061  CheckDefExecFailure([
1062      'let RefMe: func = function("g:DelMe")',
1063      'delfunc g:DelMe',
1064      'echo RefMe()'], 'E117:')
1065enddef
1066
1067def Test_unknown_function()
1068  CheckDefExecFailure([
1069      'let Ref: func = function("NotExist")',
1070      'delfunc g:NotExist'], 'E700:')
1071enddef
1072
1073def RefFunc(Ref: func(string): string): string
1074  return Ref('more')
1075enddef
1076
1077def Test_closure_simple()
1078  let local = 'some '
1079  assert_equal('some more', RefFunc({s -> local .. s}))
1080enddef
1081
1082def MakeRef()
1083  let local = 'some '
1084  g:Ref = {s -> local .. s}
1085enddef
1086
1087def Test_closure_ref_after_return()
1088  MakeRef()
1089  assert_equal('some thing', g:Ref('thing'))
1090  unlet g:Ref
1091enddef
1092
1093def MakeTwoRefs()
1094  let local = ['some']
1095  g:Extend = {s -> local->add(s)}
1096  g:Read = {-> local}
1097enddef
1098
1099def Test_closure_two_refs()
1100  MakeTwoRefs()
1101  assert_equal('some', join(g:Read(), ' '))
1102  g:Extend('more')
1103  assert_equal('some more', join(g:Read(), ' '))
1104  g:Extend('even')
1105  assert_equal('some more even', join(g:Read(), ' '))
1106
1107  unlet g:Extend
1108  unlet g:Read
1109enddef
1110
1111def ReadRef(Ref: func(): list<string>): string
1112  return join(Ref(), ' ')
1113enddef
1114
1115def ExtendRef(Ref: func(string), add: string)
1116  Ref(add)
1117enddef
1118
1119def Test_closure_two_indirect_refs()
1120  MakeTwoRefs()
1121  assert_equal('some', ReadRef(g:Read))
1122  ExtendRef(g:Extend, 'more')
1123  assert_equal('some more', ReadRef(g:Read))
1124  ExtendRef(g:Extend, 'even')
1125  assert_equal('some more even', ReadRef(g:Read))
1126
1127  unlet g:Extend
1128  unlet g:Read
1129enddef
1130
1131def MakeArgRefs(theArg: string)
1132  let local = 'loc_val'
1133  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
1134enddef
1135
1136def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1137  let local = 'the_loc'
1138  g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)}
1139enddef
1140
1141def Test_closure_using_argument()
1142  MakeArgRefs('arg_val')
1143  assert_equal('arg_val/loc_val/call_val', g:UseArg('call_val'))
1144
1145  MakeArgRefsVarargs('arg_val', 'one', 'two')
1146  assert_equal('arg_val/the_loc/call_val/one two', g:UseVararg('call_val'))
1147
1148  unlet g:UseArg
1149  unlet g:UseVararg
1150enddef
1151
1152def MakeGetAndAppendRefs()
1153  let local = 'a'
1154
1155  def Append(arg: string)
1156    local ..= arg
1157  enddef
1158  g:Append = Append
1159
1160  def Get(): string
1161    return local
1162  enddef
1163  g:Get = Get
1164enddef
1165
1166def Test_closure_append_get()
1167  MakeGetAndAppendRefs()
1168  assert_equal('a', g:Get())
1169  g:Append('-b')
1170  assert_equal('a-b', g:Get())
1171  g:Append('-c')
1172  assert_equal('a-b-c', g:Get())
1173
1174  unlet g:Append
1175  unlet g:Get
1176enddef
1177
1178def Test_nested_closure()
1179  let local = 'text'
1180  def Closure(arg: string): string
1181    return local .. arg
1182  enddef
1183  assert_equal('text!!!', Closure('!!!'))
1184enddef
1185
1186func GetResult(Ref)
1187  return a:Ref('some')
1188endfunc
1189
1190def Test_call_closure_not_compiled()
1191  let text = 'text'
1192  g:Ref = {s ->  s .. text}
1193  assert_equal('sometext', GetResult(g:Ref))
1194enddef
1195
1196def Test_sort_return_type()
1197  let res: list<number>
1198  res = [1, 2, 3]->sort()
1199enddef
1200
1201def Test_getqflist_return_type()
1202  let l = getqflist()
1203  assert_equal([], l)
1204
1205  let d = getqflist(#{items: 0})
1206  assert_equal(#{items: []}, d)
1207enddef
1208
1209def Test_getloclist_return_type()
1210  let l = getloclist(1)
1211  assert_equal([], l)
1212
1213  let d = getloclist(1, #{items: 0})
1214  assert_equal(#{items: []}, d)
1215enddef
1216
1217def Test_copy_return_type()
1218  let l = copy([1, 2, 3])
1219  let res = 0
1220  for n in l
1221    res += n
1222  endfor
1223  assert_equal(6, res)
1224
1225  let dl = deepcopy([1, 2, 3])
1226  res = 0
1227  for n in dl
1228    res += n
1229  endfor
1230  assert_equal(6, res)
1231enddef
1232
1233def Test_extend_return_type()
1234  let l = extend([1, 2], [3])
1235  let res = 0
1236  for n in l
1237    res += n
1238  endfor
1239  assert_equal(6, res)
1240enddef
1241
1242def Test_insert_return_type()
1243  let l = insert([2, 1], 3)
1244  let res = 0
1245  for n in l
1246    res += n
1247  endfor
1248  assert_equal(6, res)
1249enddef
1250
1251def Test_reverse_return_type()
1252  let l = reverse([1, 2, 3])
1253  let res = 0
1254  for n in l
1255    res += n
1256  endfor
1257  assert_equal(6, res)
1258enddef
1259
1260def Test_remove_return_type()
1261  let l = remove(#{one: [1, 2], two: [3, 4]}, 'one')
1262  let res = 0
1263  for n in l
1264    res += n
1265  endfor
1266  assert_equal(3, res)
1267enddef
1268
1269def Test_filter_return_type()
1270  let l = filter([1, 2, 3], {-> 1})
1271  let res = 0
1272  for n in l
1273    res += n
1274  endfor
1275  assert_equal(6, res)
1276enddef
1277
1278def Test_getreg_return_type()
1279  let s1: string = getreg('"')
1280  let s2: string = getreg('"', 1)
1281  let s3: list<string> = getreg('"', 1, 1)
1282enddef
1283
1284def Wrong_dict_key_type(items: list<number>): list<number>
1285  return filter(items, {_, val -> get({val: 1}, 'x')})
1286enddef
1287
1288def Test_wrong_dict_key_type()
1289  assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1029:')
1290enddef
1291
1292def Line_continuation_in_def(dir: string = ''): string
1293    let path: string = empty(dir)
1294            \ ? 'empty'
1295            \ : 'full'
1296    return path
1297enddef
1298
1299def Test_line_continuation_in_def()
1300  assert_equal('full', Line_continuation_in_def('.'))
1301enddef
1302
1303def Line_continuation_in_lambda(): list<number>
1304  let x = range(97, 100)
1305      ->map({_, v -> nr2char(v)
1306          ->toupper()})
1307      ->reverse()
1308  return x
1309enddef
1310
1311def Test_line_continuation_in_lambda()
1312  assert_equal(['D', 'C', 'B', 'A'], Line_continuation_in_lambda())
1313enddef
1314
1315func Test_silent_echo()
1316  CheckScreendump
1317
1318  let lines =<< trim END
1319    vim9script
1320    def EchoNothing()
1321      silent echo ''
1322    enddef
1323    defcompile
1324  END
1325  call writefile(lines, 'XTest_silent_echo')
1326
1327  " Check that the balloon shows up after a mouse move
1328  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1329  call term_sendkeys(buf, ":abc")
1330  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1331
1332  " clean up
1333  call StopVimInTerminal(buf)
1334  call delete('XTest_silent_echo')
1335endfunc
1336
1337def Fibonacci(n: number): number
1338  if n < 2
1339    return n
1340  else
1341    return Fibonacci(n - 1) + Fibonacci(n - 2)
1342  endif
1343enddef
1344
1345def Test_recursive_call()
1346  assert_equal(6765, Fibonacci(20))
1347enddef
1348
1349def TreeWalk(dir: string): list<any>
1350  return readdir(dir)->map({_, val ->
1351            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
1352               ? {val: TreeWalk(dir .. '/' .. val)}
1353               : val
1354             })
1355enddef
1356
1357def Test_closure_in_map()
1358  mkdir('XclosureDir/tdir', 'p')
1359  writefile(['111'], 'XclosureDir/file1')
1360  writefile(['222'], 'XclosureDir/file2')
1361  writefile(['333'], 'XclosureDir/tdir/file3')
1362
1363  assert_equal(['file1', 'file2', {'tdir': ['file3']}], TreeWalk('XclosureDir'))
1364
1365  delete('XclosureDir', 'rf')
1366enddef
1367
1368def Test_partial_call()
1369  let Xsetlist = function('setloclist', [0])
1370  Xsetlist([], ' ', {'title': 'test'})
1371  assert_equal({'title': 'test'}, getloclist(0, {'title': 1}))
1372
1373  Xsetlist = function('setloclist', [0, [], ' '])
1374  Xsetlist({'title': 'test'})
1375  assert_equal({'title': 'test'}, getloclist(0, {'title': 1}))
1376
1377  Xsetlist = function('setqflist')
1378  Xsetlist([], ' ', {'title': 'test'})
1379  assert_equal({'title': 'test'}, getqflist({'title': 1}))
1380
1381  Xsetlist = function('setqflist', [[], ' '])
1382  Xsetlist({'title': 'test'})
1383  assert_equal({'title': 'test'}, getqflist({'title': 1}))
1384enddef
1385
1386def Test_cmd_modifier()
1387  tab echo '0'
1388  call CheckDefFailure(['5tab echo 3'], 'E16:')
1389enddef
1390
1391def Test_restore_modifiers()
1392  # check that when compiling a :def function command modifiers are not messed
1393  # up.
1394  let lines =<< trim END
1395      vim9script
1396      set eventignore=
1397      autocmd QuickFixCmdPost * copen
1398      def AutocmdsDisabled()
1399          eval 0
1400      enddef
1401      func Func()
1402        noautocmd call s:AutocmdsDisabled()
1403        let g:ei_after = &eventignore
1404      endfunc
1405      Func()
1406  END
1407  CheckScriptSuccess(lines)
1408  assert_equal('', g:ei_after)
1409enddef
1410
1411
1412" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
1413