1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source term_util.vim
5source view_util.vim
6source vim9.vim
7source screendump.vim
8
9func Test_def_basic()
10  def SomeFunc(): string
11    return 'yes'
12  enddef
13  call SomeFunc()->assert_equal('yes')
14endfunc
15
16func Test_compiling_error()
17  " use a terminal to see the whole error message
18  CheckRunVimInTerminal
19
20  call TestCompilingError()
21  call TestCompilingErrorInTry()
22endfunc
23
24def TestCompilingError()
25  var lines =<< trim END
26    vim9script
27    def Fails()
28      echo nothing
29    enddef
30    defcompile
31  END
32  writefile(lines, 'XTest_compile_error')
33  var buf = RunVimInTerminal('-S XTest_compile_error',
34              {rows: 10, wait_for_ruler: 0})
35  WaitForAssert(() => assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing',
36                     Term_getlines(buf, range(1, 9))))
37
38  # clean up
39  StopVimInTerminal(buf)
40  delete('XTest_compile_error')
41enddef
42
43def TestCompilingErrorInTry()
44  var dir = 'Xdir/autoload'
45  mkdir(dir, 'p')
46
47  var lines =<< trim END
48      vim9script
49      def script#OnlyCompiled()
50        g:runtime = 'yes'
51        invalid
52      enddef
53  END
54  writefile(lines, dir .. '/script.vim')
55
56  lines =<< trim END
57      vim9script
58      todo
59      try
60        script#OnlyCompiled()
61      catch /nothing/
62      endtry
63  END
64  lines[1] = 'set rtp=' .. getcwd() .. '/Xdir'
65  writefile(lines, 'XTest_compile_error')
66
67  var buf = RunVimInTerminal('-S XTest_compile_error', {rows: 10, wait_for_ruler: 0})
68  WaitForAssert(() => assert_match('Error detected while compiling command line.*function script#OnlyCompiled.*Invalid command: invalid',
69                     Term_getlines(buf, range(1, 9))))
70
71  # clean up
72  StopVimInTerminal(buf)
73  delete('XTest_compile_error')
74  delete('Xdir', 'rf')
75enddef
76
77def Test_compile_error_in_called_function()
78  var lines =<< trim END
79      vim9script
80      var n: number
81      def Foo()
82        &hls = n
83      enddef
84      def Bar()
85        Foo()
86      enddef
87      silent! Foo()
88      Bar()
89  END
90  CheckScriptFailureList(lines, ['E1012:', 'E1191:'])
91enddef
92
93def Test_wrong_function_name()
94  var lines =<< trim END
95      vim9script
96      func _Foo()
97        echo 'foo'
98      endfunc
99  END
100  CheckScriptFailure(lines, 'E128:')
101
102  lines =<< trim END
103      vim9script
104      def _Foo()
105        echo 'foo'
106      enddef
107  END
108  CheckScriptFailure(lines, 'E128:')
109enddef
110
111def Test_autoload_name_mismatch()
112  var dir = 'Xdir/autoload'
113  mkdir(dir, 'p')
114
115  var lines =<< trim END
116      vim9script
117      def scriptX#Function()
118        # comment
119        g:runtime = 'yes'
120      enddef
121  END
122  writefile(lines, dir .. '/script.vim')
123
124  var save_rtp = &rtp
125  exe 'set rtp=' .. getcwd() .. '/Xdir'
126  lines =<< trim END
127      call script#Function()
128  END
129  CheckScriptFailure(lines, 'E746:', 2)
130
131  &rtp = save_rtp
132  delete(dir, 'rf')
133enddef
134
135def Test_autoload_names()
136  var dir = 'Xdir/autoload'
137  mkdir(dir, 'p')
138
139  var lines =<< trim END
140      func foobar#function()
141        return 'yes'
142      endfunc
143      let foobar#var = 'no'
144  END
145  writefile(lines, dir .. '/foobar.vim')
146
147  var save_rtp = &rtp
148  exe 'set rtp=' .. getcwd() .. '/Xdir'
149
150  lines =<< trim END
151      assert_equal('yes', foobar#function())
152      var Function = foobar#function
153      assert_equal('yes', Function())
154
155      assert_equal('no', foobar#var)
156  END
157  CheckDefAndScriptSuccess(lines)
158
159  &rtp = save_rtp
160  delete(dir, 'rf')
161enddef
162
163def Test_autoload_error_in_script()
164  var dir = 'Xdir/autoload'
165  mkdir(dir, 'p')
166
167  var lines =<< trim END
168      func scripterror#function()
169        let g:called_function = 'yes'
170      endfunc
171      let 0 = 1
172  END
173  writefile(lines, dir .. '/scripterror.vim')
174
175  var save_rtp = &rtp
176  exe 'set rtp=' .. getcwd() .. '/Xdir'
177
178  g:called_function = 'no'
179  # The error in the autoload script cannot be checked with assert_fails(), use
180  # CheckDefSuccess() instead of CheckDefFailure()
181  try
182    CheckDefSuccess(['scripterror#function()'])
183  catch
184    assert_match('E121: Undefined variable: 0', v:exception)
185  endtry
186  assert_equal('no', g:called_function)
187
188  lines =<< trim END
189      func scriptcaught#function()
190        let g:called_function = 'yes'
191      endfunc
192      try
193        let 0 = 1
194      catch
195        let g:caught = v:exception
196      endtry
197  END
198  writefile(lines, dir .. '/scriptcaught.vim')
199
200  g:called_function = 'no'
201  CheckDefSuccess(['scriptcaught#function()'])
202  assert_match('E121: Undefined variable: 0', g:caught)
203  assert_equal('yes', g:called_function)
204
205  &rtp = save_rtp
206  delete(dir, 'rf')
207enddef
208
209def CallRecursive(n: number): number
210  return CallRecursive(n + 1)
211enddef
212
213def CallMapRecursive(l: list<number>): number
214  return map(l, (_, v) => CallMapRecursive([v]))[0]
215enddef
216
217def Test_funcdepth_error()
218  set maxfuncdepth=10
219
220  var caught = false
221  try
222    CallRecursive(1)
223  catch /E132:/
224    caught = true
225  endtry
226  assert_true(caught)
227
228  caught = false
229  try
230    CallMapRecursive([1])
231  catch /E132:/
232    caught = true
233  endtry
234  assert_true(caught)
235
236  set maxfuncdepth&
237enddef
238
239def Test_endfunc_enddef()
240  var lines =<< trim END
241    def Test()
242      echo 'test'
243      endfunc
244    enddef
245  END
246  CheckScriptFailure(lines, 'E1151:', 3)
247
248  lines =<< trim END
249    def Test()
250      func Nested()
251        echo 'test'
252      enddef
253    enddef
254  END
255  CheckScriptFailure(lines, 'E1152:', 4)
256
257  lines =<< trim END
258    def Ok()
259      echo 'hello'
260    enddef | echo 'there'
261    def Bad()
262      echo 'hello'
263    enddef there
264  END
265  CheckScriptFailure(lines, 'E1173: Text found after enddef: there', 6)
266enddef
267
268def Test_missing_endfunc_enddef()
269  var lines =<< trim END
270    vim9script
271    def Test()
272      echo 'test'
273    endef
274  END
275  CheckScriptFailure(lines, 'E1057:', 2)
276
277  lines =<< trim END
278    vim9script
279    func Some()
280      echo 'test'
281    enfffunc
282  END
283  CheckScriptFailure(lines, 'E126:', 2)
284enddef
285
286def Test_white_space_before_paren()
287  var lines =<< trim END
288    vim9script
289    def Test ()
290      echo 'test'
291    enddef
292  END
293  CheckScriptFailure(lines, 'E1068:', 2)
294
295  lines =<< trim END
296    vim9script
297    func Test ()
298      echo 'test'
299    endfunc
300  END
301  CheckScriptFailure(lines, 'E1068:', 2)
302
303  lines =<< trim END
304    def Test ()
305      echo 'test'
306    enddef
307  END
308  CheckScriptFailure(lines, 'E1068:', 1)
309
310  lines =<< trim END
311    func Test ()
312      echo 'test'
313    endfunc
314  END
315  CheckScriptSuccess(lines)
316enddef
317
318def Test_enddef_dict_key()
319  var d = {
320    enddef: 'x',
321    endfunc: 'y',
322  }
323  assert_equal({enddef: 'x', endfunc: 'y'}, d)
324enddef
325
326def ReturnString(): string
327  return 'string'
328enddef
329
330def ReturnNumber(): number
331  return 123
332enddef
333
334let g:notNumber = 'string'
335
336def ReturnGlobal(): number
337  return g:notNumber
338enddef
339
340def Test_return_something()
341  ReturnString()->assert_equal('string')
342  ReturnNumber()->assert_equal(123)
343  assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal')
344enddef
345
346def Test_check_argument_type()
347  var lines =<< trim END
348      vim9script
349      def Val(a: number, b: number): number
350        return 0
351      enddef
352      def Func()
353        var x: any = true
354        Val(0, x)
355      enddef
356      disass Func
357      Func()
358  END
359  CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got bool', 2)
360enddef
361
362def Test_missing_return()
363  CheckDefFailure(['def Missing(): number',
364                   '  if g:cond',
365                   '    echo "no return"',
366                   '  else',
367                   '    return 0',
368                   '  endif'
369                   'enddef'], 'E1027:')
370  CheckDefFailure(['def Missing(): number',
371                   '  if g:cond',
372                   '    return 1',
373                   '  else',
374                   '    echo "no return"',
375                   '  endif'
376                   'enddef'], 'E1027:')
377  CheckDefFailure(['def Missing(): number',
378                   '  if g:cond',
379                   '    return 1',
380                   '  else',
381                   '    return 2',
382                   '  endif'
383                   '  return 3'
384                   'enddef'], 'E1095:')
385enddef
386
387def Test_return_bool()
388  var lines =<< trim END
389      vim9script
390      def MenuFilter(id: number, key: string): bool
391        return popup_filter_menu(id, key)
392      enddef
393      def YesnoFilter(id: number, key: string): bool
394        return popup_filter_yesno(id, key)
395      enddef
396      defcompile
397  END
398  CheckScriptSuccess(lines)
399enddef
400
401let s:nothing = 0
402def ReturnNothing()
403  s:nothing = 1
404  if true
405    return
406  endif
407  s:nothing = 2
408enddef
409
410def Test_return_nothing()
411  ReturnNothing()
412  s:nothing->assert_equal(1)
413enddef
414
415def Test_return_invalid()
416  var lines =<< trim END
417    vim9script
418    def Func(): invalid
419      return xxx
420    enddef
421    defcompile
422  END
423  CheckScriptFailure(lines, 'E1010:', 2)
424
425  lines =<< trim END
426      vim9script
427      def Test(Fun: func(number): number): list<number>
428          return map([1, 2, 3], (_, i) => Fun(i))
429      enddef
430      defcompile
431      def Inc(nr: number): nr
432        return nr + 2
433      enddef
434      echo Test(Inc)
435  END
436  # doing this twice was leaking memory
437  CheckScriptFailure(lines, 'E1010:')
438  CheckScriptFailure(lines, 'E1010:')
439enddef
440
441func Increment()
442  let g:counter += 1
443endfunc
444
445def Test_call_ufunc_count()
446  g:counter = 1
447  Increment()
448  Increment()
449  Increment()
450  # works with and without :call
451  g:counter->assert_equal(4)
452  eval g:counter->assert_equal(4)
453  unlet g:counter
454enddef
455
456def MyVarargs(arg: string, ...rest: list<string>): string
457  var res = arg
458  for s in rest
459    res ..= ',' .. s
460  endfor
461  return res
462enddef
463
464def Test_call_varargs()
465  MyVarargs('one')->assert_equal('one')
466  MyVarargs('one', 'two')->assert_equal('one,two')
467  MyVarargs('one', 'two', 'three')->assert_equal('one,two,three')
468enddef
469
470def MyDefaultArgs(name = 'string'): string
471  return name
472enddef
473
474def MyDefaultSecond(name: string, second: bool  = true): string
475  return second ? name : 'none'
476enddef
477
478
479def Test_call_default_args()
480  MyDefaultArgs()->assert_equal('string')
481  MyDefaultArgs(v:none)->assert_equal('string')
482  MyDefaultArgs('one')->assert_equal('one')
483  assert_fails('MyDefaultArgs("one", "two")', 'E118:', '', 4, 'Test_call_default_args')
484
485  MyDefaultSecond('test')->assert_equal('test')
486  MyDefaultSecond('test', true)->assert_equal('test')
487  MyDefaultSecond('test', false)->assert_equal('none')
488
489  var lines =<< trim END
490      def MyDefaultThird(name: string, aa = 'aa', bb = 'bb'): string
491        return name .. aa .. bb
492      enddef
493
494      MyDefaultThird('->')->assert_equal('->aabb')
495      MyDefaultThird('->', v:none)->assert_equal('->aabb')
496      MyDefaultThird('->', 'xx')->assert_equal('->xxbb')
497      MyDefaultThird('->', v:none, v:none)->assert_equal('->aabb')
498      MyDefaultThird('->', 'xx', v:none)->assert_equal('->xxbb')
499      MyDefaultThird('->', v:none, 'yy')->assert_equal('->aayy')
500      MyDefaultThird('->', 'xx', 'yy')->assert_equal('->xxyy')
501
502      def DefArg(mandatory: any, optional = mandatory): string
503        return mandatory .. optional
504      enddef
505      DefArg(1234)->assert_equal('12341234')
506      DefArg("ok")->assert_equal('okok')
507  END
508  CheckDefAndScriptSuccess(lines)
509
510  CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:')
511  delfunc g:Func
512  CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: Argument 1: type mismatch, expected number but got string')
513  delfunc g:Func
514  CheckDefFailure(['def Func(x: number = )', 'enddef'], 'E15:')
515
516  lines =<< trim END
517      vim9script
518      def Func(a = b == 0 ? 1 : 2, b = 0)
519      enddef
520      defcompile
521  END
522  CheckScriptFailure(lines, 'E1001: Variable not found: b')
523enddef
524
525def FuncWithComment(  # comment
526  a: number, #comment
527  b: bool, # comment
528  c: string) #comment
529  assert_equal(4, a)
530  assert_equal(true, b)
531  assert_equal('yes', c)
532enddef
533
534def Test_func_with_comments()
535  FuncWithComment(4, true, 'yes')
536
537  var lines =<< trim END
538      def Func(# comment
539        arg: string)
540      enddef
541  END
542  CheckScriptFailure(lines, 'E125:', 1)
543
544  lines =<< trim END
545      def Func(
546        arg: string# comment
547        )
548      enddef
549  END
550  CheckScriptFailure(lines, 'E475:', 2)
551
552  lines =<< trim END
553      def Func(
554        arg: string
555        )# comment
556      enddef
557  END
558  CheckScriptFailure(lines, 'E488:', 3)
559enddef
560
561def Test_nested_function()
562  def Nested(arg: string): string
563    return 'nested ' .. arg
564  enddef
565  Nested('function')->assert_equal('nested function')
566
567  CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
568  CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
569
570  CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
571  CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
572  CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
573
574  var lines =<< trim END
575      def Outer()
576        def Inner()
577          # comment
578        enddef
579        def Inner()
580        enddef
581      enddef
582  END
583  CheckDefFailure(lines, 'E1073:')
584
585  lines =<< trim END
586      def Outer()
587        def Inner()
588          # comment
589        enddef
590        def! Inner()
591        enddef
592      enddef
593  END
594  CheckDefFailure(lines, 'E1117:')
595
596  # nested function inside conditional
597  lines =<< trim END
598      vim9script
599      var thecount = 0
600      if true
601        def Test(): number
602          def TheFunc(): number
603            thecount += 1
604            return thecount
605          enddef
606          return TheFunc()
607        enddef
608      endif
609      defcompile
610      assert_equal(1, Test())
611      assert_equal(2, Test())
612  END
613  CheckScriptSuccess(lines)
614
615  # also works when "thecount" is inside the "if" block
616  lines =<< trim END
617      vim9script
618      if true
619        var thecount = 0
620        def Test(): number
621          def TheFunc(): number
622            thecount += 1
623            return thecount
624          enddef
625          return TheFunc()
626        enddef
627      endif
628      defcompile
629      assert_equal(1, Test())
630      assert_equal(2, Test())
631  END
632  CheckScriptSuccess(lines)
633enddef
634
635def Test_not_nested_function()
636  echo printf('%d',
637      function('len')('xxx'))
638enddef
639
640func Test_call_default_args_from_func()
641  call MyDefaultArgs()->assert_equal('string')
642  call MyDefaultArgs('one')->assert_equal('one')
643  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args_from_func')
644endfunc
645
646def Test_nested_global_function()
647  var lines =<< trim END
648      vim9script
649      def Outer()
650          def g:Inner(): string
651              return 'inner'
652          enddef
653      enddef
654      defcompile
655      Outer()
656      g:Inner()->assert_equal('inner')
657      delfunc g:Inner
658      Outer()
659      g:Inner()->assert_equal('inner')
660      delfunc g:Inner
661      Outer()
662      g:Inner()->assert_equal('inner')
663      delfunc g:Inner
664  END
665  CheckScriptSuccess(lines)
666
667  lines =<< trim END
668      vim9script
669      def Outer()
670          def g:Inner(): string
671              return 'inner'
672          enddef
673      enddef
674      defcompile
675      Outer()
676      Outer()
677  END
678  CheckScriptFailure(lines, "E122:")
679  delfunc g:Inner
680
681  lines =<< trim END
682      vim9script
683      def Outer()
684        def g:Inner()
685          echo map([1, 2, 3], (_, v) => v + 1)
686        enddef
687        g:Inner()
688      enddef
689      Outer()
690  END
691  CheckScriptSuccess(lines)
692  delfunc g:Inner
693
694  lines =<< trim END
695      vim9script
696      def Func()
697        echo 'script'
698      enddef
699      def Outer()
700        def Func()
701          echo 'inner'
702        enddef
703      enddef
704      defcompile
705  END
706  CheckScriptFailure(lines, "E1073:")
707enddef
708
709def DefListAll()
710  def
711enddef
712
713def DefListOne()
714  def DefListOne
715enddef
716
717def DefListMatches()
718  def /DefList
719enddef
720
721def Test_nested_def_list()
722  var funcs = split(execute('call DefListAll()'), "\n")
723  assert_true(len(funcs) > 10)
724  assert_true(funcs->index('def DefListAll()') >= 0)
725
726  funcs = split(execute('call DefListOne()'), "\n")
727  assert_equal(['   def DefListOne()', '1    def DefListOne', '   enddef'], funcs)
728
729  funcs = split(execute('call DefListMatches()'), "\n")
730  assert_true(len(funcs) >= 3)
731  assert_true(funcs->index('def DefListAll()') >= 0)
732  assert_true(funcs->index('def DefListOne()') >= 0)
733  assert_true(funcs->index('def DefListMatches()') >= 0)
734
735  var lines =<< trim END
736    vim9script
737    def Func()
738      def +Func+
739    enddef
740    defcompile
741  END
742  CheckScriptFailure(lines, 'E476:', 1)
743enddef
744
745def Test_global_local_function()
746  var lines =<< trim END
747      vim9script
748      def g:Func(): string
749          return 'global'
750      enddef
751      def Func(): string
752          return 'local'
753      enddef
754      g:Func()->assert_equal('global')
755      Func()->assert_equal('local')
756      delfunc g:Func
757  END
758  CheckScriptSuccess(lines)
759
760  lines =<< trim END
761      vim9script
762      def g:Funcy()
763        echo 'funcy'
764      enddef
765      s:Funcy()
766  END
767  CheckScriptFailure(lines, 'E117:')
768enddef
769
770def Test_local_function_shadows_global()
771  var lines =<< trim END
772      vim9script
773      def g:Gfunc(): string
774        return 'global'
775      enddef
776      def AnotherFunc(): number
777        var Gfunc = function('len')
778        return Gfunc('testing')
779      enddef
780      g:Gfunc()->assert_equal('global')
781      AnotherFunc()->assert_equal(7)
782      delfunc g:Gfunc
783  END
784  CheckScriptSuccess(lines)
785
786  lines =<< trim END
787      vim9script
788      def g:Func(): string
789        return 'global'
790      enddef
791      def AnotherFunc()
792        g:Func = function('len')
793      enddef
794      AnotherFunc()
795  END
796  CheckScriptFailure(lines, 'E705:')
797  delfunc g:Func
798
799  # global function is found without g: prefix
800  lines =<< trim END
801      vim9script
802      def g:Func(): string
803        return 'global'
804      enddef
805      def AnotherFunc(): string
806        return Func()
807      enddef
808      assert_equal('global', AnotherFunc())
809    delfunc g:Func
810  END
811  CheckScriptSuccess(lines)
812
813  lines =<< trim END
814      vim9script
815      def g:Func(): string
816        return 'global'
817      enddef
818      assert_equal('global', Func())
819      delfunc g:Func
820  END
821  CheckScriptSuccess(lines)
822enddef
823
824func TakesOneArg(arg)
825  echo a:arg
826endfunc
827
828def Test_call_wrong_args()
829  CheckDefFailure(['TakesOneArg()'], 'E119:')
830  CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
831  CheckDefFailure(['bufnr(xxx)'], 'E1001:')
832  CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:')
833
834  var lines =<< trim END
835    vim9script
836    def Func(s: string)
837      echo s
838    enddef
839    Func([])
840  END
841  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 5)
842
843  lines =<< trim END
844    vim9script
845    var name = 'piet'
846    def FuncOne(name: string)
847      echo nr
848    enddef
849  END
850  CheckScriptFailure(lines, 'E1168:')
851
852  lines =<< trim END
853    vim9script
854    def FuncOne(nr: number)
855      echo nr
856    enddef
857    def FuncTwo()
858      FuncOne()
859    enddef
860    defcompile
861  END
862  writefile(lines, 'Xscript')
863  var didCatch = false
864  try
865    source Xscript
866  catch
867    assert_match('E119: Not enough arguments for function: <SNR>\d\+_FuncOne', v:exception)
868    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
869    didCatch = true
870  endtry
871  assert_true(didCatch)
872
873  lines =<< trim END
874    vim9script
875    def FuncOne(nr: number)
876      echo nr
877    enddef
878    def FuncTwo()
879      FuncOne(1, 2)
880    enddef
881    defcompile
882  END
883  writefile(lines, 'Xscript')
884  didCatch = false
885  try
886    source Xscript
887  catch
888    assert_match('E118: Too many arguments for function: <SNR>\d\+_FuncOne', v:exception)
889    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
890    didCatch = true
891  endtry
892  assert_true(didCatch)
893
894  delete('Xscript')
895enddef
896
897def Test_call_funcref_wrong_args()
898  var head =<< trim END
899      vim9script
900      def Func3(a1: string, a2: number, a3: list<number>)
901        echo a1 .. a2 .. a3[0]
902      enddef
903      def Testme()
904        var funcMap: dict<func> = {func: Func3}
905  END
906  var tail =<< trim END
907      enddef
908      Testme()
909  END
910  CheckScriptSuccess(head + ["funcMap['func']('str', 123, [1, 2, 3])"] + tail)
911
912  CheckScriptFailure(head + ["funcMap['func']('str', 123)"] + tail, 'E119:')
913  CheckScriptFailure(head + ["funcMap['func']('str', 123, [1], 4)"] + tail, 'E118:')
914
915  var lines =<< trim END
916      vim9script
917      var Ref: func(number): any
918      Ref = (j) => !j
919      echo Ref(false)
920  END
921  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4)
922
923  lines =<< trim END
924      vim9script
925      var Ref: func(number): any
926      Ref = (j) => !j
927      call Ref(false)
928  END
929  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4)
930enddef
931
932def Test_call_lambda_args()
933  var lines =<< trim END
934    var Callback = (..._) => 'anything'
935    assert_equal('anything', Callback())
936    assert_equal('anything', Callback(1))
937    assert_equal('anything', Callback('a', 2))
938
939    assert_equal('xyz', ((a: string): string => a)('xyz'))
940  END
941  CheckDefAndScriptSuccess(lines)
942
943  CheckDefFailure(['echo ((i) => 0)()'],
944                  'E119: Not enough arguments for function: ((i) => 0)()')
945
946  lines =<< trim END
947      var Ref = (x: number, y: number) => x + y
948      echo Ref(1, 'x')
949  END
950  CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string')
951
952  lines =<< trim END
953    var Ref: func(job, string, number)
954    Ref = (x, y) => 0
955  END
956  CheckDefAndScriptFailure(lines, 'E1012:')
957
958  lines =<< trim END
959    var Ref: func(job, string)
960    Ref = (x, y, z) => 0
961  END
962  CheckDefAndScriptFailure(lines, 'E1012:')
963
964  lines =<< trim END
965      var one = 1
966      var l = [1, 2, 3]
967      echo map(l, (one) => one)
968  END
969  CheckDefFailure(lines, 'E1167:')
970  CheckScriptFailure(['vim9script'] + lines, 'E1168:')
971
972  lines =<< trim END
973    var Ref: func(any, ?any): bool
974    Ref = (_, y = 1) => false
975  END
976  CheckDefAndScriptFailure(lines, 'E1172:')
977
978  lines =<< trim END
979      var a = 0
980      var b = (a == 0 ? 1 : 2)
981      assert_equal(1, b)
982      var txt = 'a'
983      b = (txt =~ 'x' ? 1 : 2)
984      assert_equal(2, b)
985  END
986  CheckDefAndScriptSuccess(lines)
987
988  lines =<< trim END
989      def ShadowLocal()
990        var one = 1
991        var l = [1, 2, 3]
992        echo map(l, (one) => one)
993      enddef
994  END
995  CheckDefFailure(lines, 'E1167:')
996
997  lines =<< trim END
998      def Shadowarg(one: number)
999        var l = [1, 2, 3]
1000        echo map(l, (one) => one)
1001      enddef
1002  END
1003  CheckDefFailure(lines, 'E1167:')
1004
1005  lines =<< trim END
1006    echo ((a) => a)('aa', 'bb')
1007  END
1008  CheckDefAndScriptFailure(lines, 'E118:', 1)
1009
1010  lines =<< trim END
1011    echo 'aa'->((a) => a)('bb')
1012  END
1013  CheckDefFailure(lines, 'E118: Too many arguments for function: ->((a) => a)(''bb'')', 1)
1014  CheckScriptFailure(['vim9script'] + lines, 'E118: Too many arguments for function: <lambda>', 2)
1015enddef
1016
1017def FilterWithCond(x: string, Cond: func(string): bool): bool
1018  return Cond(x)
1019enddef
1020
1021def Test_lambda_return_type()
1022  var lines =<< trim END
1023    var Ref = (): => 123
1024  END
1025  CheckDefAndScriptFailure(lines, 'E1157:', 1)
1026
1027  # no space before the return type
1028  lines =<< trim END
1029    var Ref = (x):number => x + 1
1030  END
1031  CheckDefAndScriptFailure(lines, 'E1069:', 1)
1032
1033  # this works
1034  for x in ['foo', 'boo']
1035    echo FilterWithCond(x, (v) => v =~ '^b')
1036  endfor
1037
1038  # this fails
1039  lines =<< trim END
1040      echo FilterWithCond('foo', (v) => v .. '^b')
1041  END
1042  CheckDefAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected func(string): bool but got func(any): string', 1)
1043
1044  lines =<< trim END
1045      var Lambda1 = (x) => {
1046              return x
1047              }
1048      assert_equal('asdf', Lambda1('asdf'))
1049      var Lambda2 = (x): string => {
1050              return x
1051              }
1052      assert_equal('foo', Lambda2('foo'))
1053  END
1054  CheckDefAndScriptSuccess(lines)
1055
1056  lines =<< trim END
1057      var Lambda = (x): string => {
1058              return x
1059              }
1060      echo Lambda(['foo'])
1061  END
1062  CheckDefExecAndScriptFailure(lines, 'E1012:')
1063enddef
1064
1065def Test_lambda_uses_assigned_var()
1066  CheckDefSuccess([
1067        'var x: any = "aaa"'
1068        'x = filter(["bbb"], (_, v) => v =~ x)'])
1069enddef
1070
1071def Test_pass_legacy_lambda_to_def_func()
1072  var lines =<< trim END
1073      vim9script
1074      func Foo()
1075        eval s:Bar({x -> 0})
1076      endfunc
1077      def Bar(y: any)
1078      enddef
1079      Foo()
1080  END
1081  CheckScriptSuccess(lines)
1082
1083  lines =<< trim END
1084      vim9script
1085      def g:TestFunc(f: func)
1086      enddef
1087      legacy call g:TestFunc({-> 0})
1088      delfunc g:TestFunc
1089
1090      def g:TestFunc(f: func(number))
1091      enddef
1092      legacy call g:TestFunc({nr -> 0})
1093      delfunc g:TestFunc
1094  END
1095  CheckScriptSuccess(lines)
1096enddef
1097
1098" Default arg and varargs
1099def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
1100  var res = one .. ',' .. two
1101  for s in rest
1102    res ..= ',' .. s
1103  endfor
1104  return res
1105enddef
1106
1107def Test_call_def_varargs()
1108  assert_fails('MyDefVarargs()', 'E119:', '', 1, 'Test_call_def_varargs')
1109  MyDefVarargs('one')->assert_equal('one,foo')
1110  MyDefVarargs('one', 'two')->assert_equal('one,two')
1111  MyDefVarargs('one', 'two', 'three')->assert_equal('one,two,three')
1112  CheckDefFailure(['MyDefVarargs("one", 22)'],
1113      'E1013: Argument 2: type mismatch, expected string but got number')
1114  CheckDefFailure(['MyDefVarargs("one", "two", 123)'],
1115      'E1013: Argument 3: type mismatch, expected string but got number')
1116
1117  var lines =<< trim END
1118      vim9script
1119      def Func(...l: list<string>)
1120        echo l
1121      enddef
1122      Func('a', 'b', 'c')
1123  END
1124  CheckScriptSuccess(lines)
1125
1126  lines =<< trim END
1127      vim9script
1128      def Func(...l: list<string>)
1129        echo l
1130      enddef
1131      Func()
1132  END
1133  CheckScriptSuccess(lines)
1134
1135  lines =<< trim END
1136      vim9script
1137      def Func(...l: list<any>)
1138        echo l
1139      enddef
1140      Func(0)
1141  END
1142  CheckScriptSuccess(lines)
1143
1144  lines =<< trim END
1145      vim9script
1146      def Func(...l: any)
1147        echo l
1148      enddef
1149      Func(0)
1150  END
1151  CheckScriptFailure(lines, 'E1180:', 2)
1152
1153  lines =<< trim END
1154      vim9script
1155      def Func(..._l: list<string>)
1156        echo _l
1157      enddef
1158      Func('a', 'b', 'c')
1159  END
1160  CheckScriptSuccess(lines)
1161
1162  lines =<< trim END
1163      vim9script
1164      def Func(...l: list<string>)
1165        echo l
1166      enddef
1167      Func(1, 2, 3)
1168  END
1169  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
1170
1171  lines =<< trim END
1172      vim9script
1173      def Func(...l: list<string>)
1174        echo l
1175      enddef
1176      Func('a', 9)
1177  END
1178  CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch')
1179
1180  lines =<< trim END
1181      vim9script
1182      def Func(...l: list<string>)
1183        echo l
1184      enddef
1185      Func(1, 'a')
1186  END
1187  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
1188
1189  lines =<< trim END
1190      vim9script
1191      def Func(  # some comment
1192                ...l = []
1193                )
1194        echo l
1195      enddef
1196  END
1197  CheckScriptFailure(lines, 'E1160:')
1198
1199  lines =<< trim END
1200      vim9script
1201      def DoIt()
1202        g:Later('')
1203      enddef
1204      defcompile
1205      def g:Later(...l:  list<number>)
1206      enddef
1207      DoIt()
1208  END
1209  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got string')
1210enddef
1211
1212let s:value = ''
1213
1214def FuncOneDefArg(opt = 'text')
1215  s:value = opt
1216enddef
1217
1218def FuncTwoDefArg(nr = 123, opt = 'text'): string
1219  return nr .. opt
1220enddef
1221
1222def FuncVarargs(...arg: list<string>): string
1223  return join(arg, ',')
1224enddef
1225
1226def Test_func_type_varargs()
1227  var RefDefArg: func(?string)
1228  RefDefArg = FuncOneDefArg
1229  RefDefArg()
1230  s:value->assert_equal('text')
1231  RefDefArg('some')
1232  s:value->assert_equal('some')
1233
1234  var RefDef2Arg: func(?number, ?string): string
1235  RefDef2Arg = FuncTwoDefArg
1236  RefDef2Arg()->assert_equal('123text')
1237  RefDef2Arg(99)->assert_equal('99text')
1238  RefDef2Arg(77, 'some')->assert_equal('77some')
1239
1240  CheckDefFailure(['var RefWrong: func(string?)'], 'E1010:')
1241  CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:')
1242
1243  var RefVarargs: func(...list<string>): string
1244  RefVarargs = FuncVarargs
1245  RefVarargs()->assert_equal('')
1246  RefVarargs('one')->assert_equal('one')
1247  RefVarargs('one', 'two')->assert_equal('one,two')
1248
1249  CheckDefFailure(['var RefWrong: func(...list<string>, string)'], 'E110:')
1250  CheckDefFailure(['var RefWrong: func(...list<string>, ?string)'], 'E110:')
1251enddef
1252
1253" Only varargs
1254def MyVarargsOnly(...args: list<string>): string
1255  return join(args, ',')
1256enddef
1257
1258def Test_call_varargs_only()
1259  MyVarargsOnly()->assert_equal('')
1260  MyVarargsOnly('one')->assert_equal('one')
1261  MyVarargsOnly('one', 'two')->assert_equal('one,two')
1262  CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: Argument 1: type mismatch, expected string but got number')
1263  CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number')
1264enddef
1265
1266def Test_using_var_as_arg()
1267  writefile(['def Func(x: number)',  'var x = 234', 'enddef', 'defcompile'], 'Xdef')
1268  assert_fails('so Xdef', 'E1006:', '', 1, 'Func')
1269  delete('Xdef')
1270enddef
1271
1272def DictArg(arg: dict<string>)
1273  arg['key'] = 'value'
1274enddef
1275
1276def ListArg(arg: list<string>)
1277  arg[0] = 'value'
1278enddef
1279
1280def Test_assign_to_argument()
1281  # works for dict and list
1282  var d: dict<string> = {}
1283  DictArg(d)
1284  d['key']->assert_equal('value')
1285  var l: list<string> = []
1286  ListArg(l)
1287  l[0]->assert_equal('value')
1288
1289  CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:')
1290  delfunc! g:Func
1291enddef
1292
1293" These argument names are reserved in legacy functions.
1294def WithReservedNames(firstline: string, lastline: string): string
1295  return firstline .. lastline
1296enddef
1297
1298def Test_argument_names()
1299  assert_equal('OK', WithReservedNames('O', 'K'))
1300enddef
1301
1302def Test_call_func_defined_later()
1303  g:DefinedLater('one')->assert_equal('one')
1304  assert_fails('NotDefined("one")', 'E117:', '', 2, 'Test_call_func_defined_later')
1305enddef
1306
1307func DefinedLater(arg)
1308  return a:arg
1309endfunc
1310
1311def Test_call_funcref()
1312  g:SomeFunc('abc')->assert_equal(3)
1313  assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call
1314  assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref')
1315
1316  var lines =<< trim END
1317    vim9script
1318    def RetNumber(): number
1319      return 123
1320    enddef
1321    var Funcref: func: number = function('RetNumber')
1322    Funcref()->assert_equal(123)
1323  END
1324  CheckScriptSuccess(lines)
1325
1326  lines =<< trim END
1327    vim9script
1328    def RetNumber(): number
1329      return 123
1330    enddef
1331    def Bar(F: func: number): number
1332      return F()
1333    enddef
1334    var Funcref = function('RetNumber')
1335    Bar(Funcref)->assert_equal(123)
1336  END
1337  CheckScriptSuccess(lines)
1338
1339  lines =<< trim END
1340    vim9script
1341    def UseNumber(nr: number)
1342      echo nr
1343    enddef
1344    var Funcref: func(number) = function('UseNumber')
1345    Funcref(123)
1346  END
1347  CheckScriptSuccess(lines)
1348
1349  lines =<< trim END
1350    vim9script
1351    def UseNumber(nr: number)
1352      echo nr
1353    enddef
1354    var Funcref: func(string) = function('UseNumber')
1355  END
1356  CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)')
1357
1358  lines =<< trim END
1359    vim9script
1360    def EchoNr(nr = 34)
1361      g:echo = nr
1362    enddef
1363    var Funcref: func(?number) = function('EchoNr')
1364    Funcref()
1365    g:echo->assert_equal(34)
1366    Funcref(123)
1367    g:echo->assert_equal(123)
1368  END
1369  CheckScriptSuccess(lines)
1370
1371  lines =<< trim END
1372    vim9script
1373    def EchoList(...l: list<number>)
1374      g:echo = l
1375    enddef
1376    var Funcref: func(...list<number>) = function('EchoList')
1377    Funcref()
1378    g:echo->assert_equal([])
1379    Funcref(1, 2, 3)
1380    g:echo->assert_equal([1, 2, 3])
1381  END
1382  CheckScriptSuccess(lines)
1383
1384  lines =<< trim END
1385    vim9script
1386    def OptAndVar(nr: number, opt = 12, ...l: list<number>): number
1387      g:optarg = opt
1388      g:listarg = l
1389      return nr
1390    enddef
1391    var Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar')
1392    Funcref(10)->assert_equal(10)
1393    g:optarg->assert_equal(12)
1394    g:listarg->assert_equal([])
1395
1396    Funcref(11, 22)->assert_equal(11)
1397    g:optarg->assert_equal(22)
1398    g:listarg->assert_equal([])
1399
1400    Funcref(17, 18, 1, 2, 3)->assert_equal(17)
1401    g:optarg->assert_equal(18)
1402    g:listarg->assert_equal([1, 2, 3])
1403  END
1404  CheckScriptSuccess(lines)
1405enddef
1406
1407let SomeFunc = function('len')
1408let NotAFunc = 'text'
1409
1410def CombineFuncrefTypes()
1411  # same arguments, different return type
1412  var Ref1: func(bool): string
1413  var Ref2: func(bool): number
1414  var Ref3: func(bool): any
1415  Ref3 = g:cond ? Ref1 : Ref2
1416
1417  # different number of arguments
1418  var Refa1: func(bool): number
1419  var Refa2: func(bool, number): number
1420  var Refa3: func: number
1421  Refa3 = g:cond ? Refa1 : Refa2
1422
1423  # different argument types
1424  var Refb1: func(bool, string): number
1425  var Refb2: func(string, number): number
1426  var Refb3: func(any, any): number
1427  Refb3 = g:cond ? Refb1 : Refb2
1428enddef
1429
1430def FuncWithForwardCall()
1431  return g:DefinedEvenLater("yes")
1432enddef
1433
1434def DefinedEvenLater(arg: string): string
1435  return arg
1436enddef
1437
1438def Test_error_in_nested_function()
1439  # Error in called function requires unwinding the call stack.
1440  assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall')
1441enddef
1442
1443def Test_return_type_wrong()
1444  CheckScriptFailure([
1445        'def Func(): number',
1446        'return "a"',
1447        'enddef',
1448        'defcompile'], 'expected number but got string')
1449  delfunc! g:Func
1450  CheckScriptFailure([
1451        'def Func(): string',
1452        'return 1',
1453        'enddef',
1454        'defcompile'], 'expected string but got number')
1455  delfunc! g:Func
1456  CheckScriptFailure([
1457        'def Func(): void',
1458        'return "a"',
1459        'enddef',
1460        'defcompile'],
1461        'E1096: Returning a value in a function without a return type')
1462  delfunc! g:Func
1463  CheckScriptFailure([
1464        'def Func()',
1465        'return "a"',
1466        'enddef',
1467        'defcompile'],
1468        'E1096: Returning a value in a function without a return type')
1469  delfunc! g:Func
1470
1471  CheckScriptFailure([
1472        'def Func(): number',
1473        'return',
1474        'enddef',
1475        'defcompile'], 'E1003:')
1476  delfunc! g:Func
1477
1478  CheckScriptFailure([
1479        'def Func():number',
1480        'return 123',
1481        'enddef',
1482        'defcompile'], 'E1069:')
1483  delfunc! g:Func
1484
1485  CheckScriptFailure([
1486        'def Func() :number',
1487        'return 123',
1488        'enddef',
1489        'defcompile'], 'E1059:')
1490  delfunc! g:Func
1491
1492  CheckScriptFailure([
1493        'def Func() : number',
1494        'return 123',
1495        'enddef',
1496        'defcompile'], 'E1059:')
1497  delfunc! g:Func
1498
1499  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
1500  delfunc! g:Func
1501  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
1502  delfunc! g:Func
1503  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
1504  delfunc! g:Func
1505
1506  CheckScriptFailure([
1507        'vim9script',
1508        'def FuncB()',
1509        '  return 123',
1510        'enddef',
1511        'def FuncA()',
1512        '   FuncB()',
1513        'enddef',
1514        'defcompile'], 'E1096:')
1515enddef
1516
1517def Test_arg_type_wrong()
1518  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
1519  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
1520  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
1521  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
1522  CheckScriptFailure(['def Func6(...x:list<number>)', 'echo "a"', 'enddef'], 'E1069:')
1523  CheckScriptFailure(['def Func7(...x: int)', 'echo "a"', 'enddef'], 'E1010:')
1524enddef
1525
1526def Test_white_space_before_comma()
1527  var lines =<< trim END
1528    vim9script
1529    def Func(a: number , b: number)
1530    enddef
1531  END
1532  CheckScriptFailure(lines, 'E1068:')
1533  call assert_fails('vim9cmd echo stridx("a" .. "b" , "a")', 'E1068:')
1534enddef
1535
1536def Test_white_space_after_comma()
1537  var lines =<< trim END
1538    vim9script
1539    def Func(a: number,b: number)
1540    enddef
1541  END
1542  CheckScriptFailure(lines, 'E1069:')
1543
1544  # OK in legacy function
1545  lines =<< trim END
1546    vim9script
1547    func Func(a,b)
1548    endfunc
1549  END
1550  CheckScriptSuccess(lines)
1551enddef
1552
1553def Test_vim9script_call()
1554  var lines =<< trim END
1555    vim9script
1556    var name = ''
1557    def MyFunc(arg: string)
1558       name = arg
1559    enddef
1560    MyFunc('foobar')
1561    name->assert_equal('foobar')
1562
1563    var str = 'barfoo'
1564    str->MyFunc()
1565    name->assert_equal('barfoo')
1566
1567    g:value = 'value'
1568    g:value->MyFunc()
1569    name->assert_equal('value')
1570
1571    var listvar = []
1572    def ListFunc(arg: list<number>)
1573       listvar = arg
1574    enddef
1575    [1, 2, 3]->ListFunc()
1576    listvar->assert_equal([1, 2, 3])
1577
1578    var dictvar = {}
1579    def DictFunc(arg: dict<number>)
1580       dictvar = arg
1581    enddef
1582    {a: 1, b: 2}->DictFunc()
1583    dictvar->assert_equal({a: 1, b: 2})
1584    def CompiledDict()
1585      {a: 3, b: 4}->DictFunc()
1586    enddef
1587    CompiledDict()
1588    dictvar->assert_equal({a: 3, b: 4})
1589
1590    {a: 3, b: 4}->DictFunc()
1591    dictvar->assert_equal({a: 3, b: 4})
1592
1593    ('text')->MyFunc()
1594    name->assert_equal('text')
1595    ("some")->MyFunc()
1596    name->assert_equal('some')
1597
1598    # line starting with single quote is not a mark
1599    # line starting with double quote can be a method call
1600    'asdfasdf'->MyFunc()
1601    name->assert_equal('asdfasdf')
1602    "xyz"->MyFunc()
1603    name->assert_equal('xyz')
1604
1605    def UseString()
1606      'xyork'->MyFunc()
1607    enddef
1608    UseString()
1609    name->assert_equal('xyork')
1610
1611    def UseString2()
1612      "knife"->MyFunc()
1613    enddef
1614    UseString2()
1615    name->assert_equal('knife')
1616
1617    # prepending a colon makes it a mark
1618    new
1619    setline(1, ['aaa', 'bbb', 'ccc'])
1620    normal! 3Gmt1G
1621    :'t
1622    getcurpos()[1]->assert_equal(3)
1623    bwipe!
1624
1625    MyFunc(
1626        'continued'
1627        )
1628    assert_equal('continued',
1629            name
1630            )
1631
1632    call MyFunc(
1633        'more'
1634          ..
1635          'lines'
1636        )
1637    assert_equal(
1638        'morelines',
1639        name)
1640  END
1641  writefile(lines, 'Xcall.vim')
1642  source Xcall.vim
1643  delete('Xcall.vim')
1644enddef
1645
1646def Test_vim9script_call_fail_decl()
1647  var lines =<< trim END
1648    vim9script
1649    var name = ''
1650    def MyFunc(arg: string)
1651       var name = 123
1652    enddef
1653    defcompile
1654  END
1655  CheckScriptFailure(lines, 'E1054:')
1656enddef
1657
1658def Test_vim9script_call_fail_type()
1659  var lines =<< trim END
1660    vim9script
1661    def MyFunc(arg: string)
1662      echo arg
1663    enddef
1664    MyFunc(1234)
1665  END
1666  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
1667enddef
1668
1669def Test_vim9script_call_fail_const()
1670  var lines =<< trim END
1671    vim9script
1672    const var = ''
1673    def MyFunc(arg: string)
1674       var = 'asdf'
1675    enddef
1676    defcompile
1677  END
1678  writefile(lines, 'Xcall_const.vim')
1679  assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
1680  delete('Xcall_const.vim')
1681
1682  lines =<< trim END
1683      const g:Aconst = 77
1684      def Change()
1685        # comment
1686        g:Aconst = 99
1687      enddef
1688      call Change()
1689      unlet g:Aconst
1690  END
1691  CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2)
1692enddef
1693
1694" Test that inside :function a Python function can be defined, :def is not
1695" recognized.
1696func Test_function_python()
1697  CheckFeature python3
1698  let py = 'python3'
1699  execute py "<< EOF"
1700def do_something():
1701  return 1
1702EOF
1703endfunc
1704
1705def Test_delfunc()
1706  var lines =<< trim END
1707    vim9script
1708    def g:GoneSoon()
1709      echo 'hello'
1710    enddef
1711
1712    def CallGoneSoon()
1713      GoneSoon()
1714    enddef
1715    defcompile
1716
1717    delfunc g:GoneSoon
1718    CallGoneSoon()
1719  END
1720  writefile(lines, 'XToDelFunc')
1721  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1722  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1723
1724  delete('XToDelFunc')
1725enddef
1726
1727def Test_redef_failure()
1728  writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
1729  so Xdef
1730  writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
1731  so Xdef
1732  writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
1733  assert_fails('so Xdef', 'E1027:', '', 1, 'Func0')
1734  writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
1735  so Xdef
1736  delete('Xdef')
1737
1738  assert_fails('g:Func0()', 'E1091:')
1739  g:Func1()->assert_equal('Func1')
1740  g:Func2()->assert_equal('Func2')
1741
1742  delfunc! Func0
1743  delfunc! Func1
1744  delfunc! Func2
1745enddef
1746
1747def Test_vim9script_func()
1748  var lines =<< trim END
1749    vim9script
1750    func Func(arg)
1751      echo a:arg
1752    endfunc
1753    Func('text')
1754  END
1755  writefile(lines, 'XVim9Func')
1756  so XVim9Func
1757
1758  delete('XVim9Func')
1759enddef
1760
1761let s:funcResult = 0
1762
1763def FuncNoArgNoRet()
1764  s:funcResult = 11
1765enddef
1766
1767def FuncNoArgRetNumber(): number
1768  s:funcResult = 22
1769  return 1234
1770enddef
1771
1772def FuncNoArgRetString(): string
1773  s:funcResult = 45
1774  return 'text'
1775enddef
1776
1777def FuncOneArgNoRet(arg: number)
1778  s:funcResult = arg
1779enddef
1780
1781def FuncOneArgRetNumber(arg: number): number
1782  s:funcResult = arg
1783  return arg
1784enddef
1785
1786def FuncTwoArgNoRet(one: bool, two: number)
1787  s:funcResult = two
1788enddef
1789
1790def FuncOneArgRetString(arg: string): string
1791  return arg
1792enddef
1793
1794def FuncOneArgRetAny(arg: any): any
1795  return arg
1796enddef
1797
1798def Test_func_type()
1799  var Ref1: func()
1800  s:funcResult = 0
1801  Ref1 = FuncNoArgNoRet
1802  Ref1()
1803  s:funcResult->assert_equal(11)
1804
1805  var Ref2: func
1806  s:funcResult = 0
1807  Ref2 = FuncNoArgNoRet
1808  Ref2()
1809  s:funcResult->assert_equal(11)
1810
1811  s:funcResult = 0
1812  Ref2 = FuncOneArgNoRet
1813  Ref2(12)
1814  s:funcResult->assert_equal(12)
1815
1816  s:funcResult = 0
1817  Ref2 = FuncNoArgRetNumber
1818  Ref2()->assert_equal(1234)
1819  s:funcResult->assert_equal(22)
1820
1821  s:funcResult = 0
1822  Ref2 = FuncOneArgRetNumber
1823  Ref2(13)->assert_equal(13)
1824  s:funcResult->assert_equal(13)
1825enddef
1826
1827def Test_repeat_return_type()
1828  var res = 0
1829  for n in repeat([1], 3)
1830    res += n
1831  endfor
1832  res->assert_equal(3)
1833
1834  res = 0
1835  for n in add([1, 2], 3)
1836    res += n
1837  endfor
1838  res->assert_equal(6)
1839enddef
1840
1841def Test_argv_return_type()
1842  next fileone filetwo
1843  var res = ''
1844  for name in argv()
1845    res ..= name
1846  endfor
1847  res->assert_equal('fileonefiletwo')
1848enddef
1849
1850def Test_func_type_part()
1851  var RefVoid: func: void
1852  RefVoid = FuncNoArgNoRet
1853  RefVoid = FuncOneArgNoRet
1854  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
1855  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
1856
1857  var RefAny: func(): any
1858  RefAny = FuncNoArgRetNumber
1859  RefAny = FuncNoArgRetString
1860  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
1861  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
1862
1863  var RefAnyNoArgs: func: any = RefAny
1864
1865  var RefNr: func: number
1866  RefNr = FuncNoArgRetNumber
1867  RefNr = FuncOneArgRetNumber
1868  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1869  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1870
1871  var RefStr: func: string
1872  RefStr = FuncNoArgRetString
1873  RefStr = FuncOneArgRetString
1874  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1875  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1876enddef
1877
1878def Test_func_type_fails()
1879  CheckDefFailure(['var ref1: func()'], 'E704:')
1880
1881  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1882  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1883  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1884  CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1885  CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1886  CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1887
1888  CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
1889  CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
1890  CheckDefFailure(['var RefWrong: func(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)'], 'E1005:')
1891  CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:')
1892enddef
1893
1894def Test_func_return_type()
1895  var nr: number
1896  nr = FuncNoArgRetNumber()
1897  nr->assert_equal(1234)
1898
1899  nr = FuncOneArgRetAny(122)
1900  nr->assert_equal(122)
1901
1902  var str: string
1903  str = FuncOneArgRetAny('yes')
1904  str->assert_equal('yes')
1905
1906  CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
1907enddef
1908
1909def Test_func_common_type()
1910  def FuncOne(n: number): number
1911    return n
1912  enddef
1913  def FuncTwo(s: string): number
1914    return len(s)
1915  enddef
1916  def FuncThree(n: number, s: string): number
1917    return n + len(s)
1918  enddef
1919  var list = [FuncOne, FuncTwo, FuncThree]
1920  assert_equal(8, list[0](8))
1921  assert_equal(4, list[1]('word'))
1922  assert_equal(7, list[2](3, 'word'))
1923enddef
1924
1925def MultiLine(
1926    arg1: string,
1927    arg2 = 1234,
1928    ...rest: list<string>
1929      ): string
1930  return arg1 .. arg2 .. join(rest, '-')
1931enddef
1932
1933def MultiLineComment(
1934    arg1: string, # comment
1935    arg2 = 1234, # comment
1936    ...rest: list<string> # comment
1937      ): string # comment
1938  return arg1 .. arg2 .. join(rest, '-')
1939enddef
1940
1941def Test_multiline()
1942  MultiLine('text')->assert_equal('text1234')
1943  MultiLine('text', 777)->assert_equal('text777')
1944  MultiLine('text', 777, 'one')->assert_equal('text777one')
1945  MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1946enddef
1947
1948func Test_multiline_not_vim9()
1949  call MultiLine('text')->assert_equal('text1234')
1950  call MultiLine('text', 777)->assert_equal('text777')
1951  call MultiLine('text', 777, 'one')->assert_equal('text777one')
1952  call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1953endfunc
1954
1955
1956" When using CheckScriptFailure() for the below test, E1010 is generated instead
1957" of E1056.
1958func Test_E1056_1059()
1959  let caught_1056 = 0
1960  try
1961    def F():
1962      return 1
1963    enddef
1964  catch /E1056:/
1965    let caught_1056 = 1
1966  endtry
1967  eval caught_1056->assert_equal(1)
1968
1969  let caught_1059 = 0
1970  try
1971    def F5(items : list)
1972      echo 'a'
1973    enddef
1974  catch /E1059:/
1975    let caught_1059 = 1
1976  endtry
1977  eval caught_1059->assert_equal(1)
1978endfunc
1979
1980func DelMe()
1981  echo 'DelMe'
1982endfunc
1983
1984def Test_error_reporting()
1985  # comment lines at the start of the function
1986  var lines =<< trim END
1987    " comment
1988    def Func()
1989      # comment
1990      # comment
1991      invalid
1992    enddef
1993    defcompile
1994  END
1995  writefile(lines, 'Xdef')
1996  try
1997    source Xdef
1998    assert_report('should have failed')
1999  catch /E476:/
2000    v:exception->assert_match('Invalid command: invalid')
2001    v:throwpoint->assert_match(', line 3$')
2002  endtry
2003  delfunc! g:Func
2004
2005  # comment lines after the start of the function
2006  lines =<< trim END
2007    " comment
2008    def Func()
2009      var x = 1234
2010      # comment
2011      # comment
2012      invalid
2013    enddef
2014    defcompile
2015  END
2016  writefile(lines, 'Xdef')
2017  try
2018    source Xdef
2019    assert_report('should have failed')
2020  catch /E476:/
2021    v:exception->assert_match('Invalid command: invalid')
2022    v:throwpoint->assert_match(', line 4$')
2023  endtry
2024  delfunc! g:Func
2025
2026  lines =<< trim END
2027    vim9script
2028    def Func()
2029      var db = {foo: 1, bar: 2}
2030      # comment
2031      var x = db.asdf
2032    enddef
2033    defcompile
2034    Func()
2035  END
2036  writefile(lines, 'Xdef')
2037  try
2038    source Xdef
2039    assert_report('should have failed')
2040  catch /E716:/
2041    v:throwpoint->assert_match('_Func, line 3$')
2042  endtry
2043  delfunc! g:Func
2044
2045  delete('Xdef')
2046enddef
2047
2048def Test_deleted_function()
2049  CheckDefExecFailure([
2050      'var RefMe: func = function("g:DelMe")',
2051      'delfunc g:DelMe',
2052      'echo RefMe()'], 'E117:')
2053enddef
2054
2055def Test_unknown_function()
2056  CheckDefExecFailure([
2057      'var Ref: func = function("NotExist")',
2058      'delfunc g:NotExist'], 'E700:')
2059enddef
2060
2061def RefFunc(Ref: func(any): any): string
2062  return Ref('more')
2063enddef
2064
2065def Test_closure_simple()
2066  var local = 'some '
2067  RefFunc((s) => local .. s)->assert_equal('some more')
2068enddef
2069
2070def MakeRef()
2071  var local = 'some '
2072  g:Ref = (s) => local .. s
2073enddef
2074
2075def Test_closure_ref_after_return()
2076  MakeRef()
2077  g:Ref('thing')->assert_equal('some thing')
2078  unlet g:Ref
2079enddef
2080
2081def MakeTwoRefs()
2082  var local = ['some']
2083  g:Extend = (s) => local->add(s)
2084  g:Read = () => local
2085enddef
2086
2087def Test_closure_two_refs()
2088  MakeTwoRefs()
2089  join(g:Read(), ' ')->assert_equal('some')
2090  g:Extend('more')
2091  join(g:Read(), ' ')->assert_equal('some more')
2092  g:Extend('even')
2093  join(g:Read(), ' ')->assert_equal('some more even')
2094
2095  unlet g:Extend
2096  unlet g:Read
2097enddef
2098
2099def ReadRef(Ref: func(): list<string>): string
2100  return join(Ref(), ' ')
2101enddef
2102
2103def ExtendRef(Ref: func(string): list<string>, add: string)
2104  Ref(add)
2105enddef
2106
2107def Test_closure_two_indirect_refs()
2108  MakeTwoRefs()
2109  ReadRef(g:Read)->assert_equal('some')
2110  ExtendRef(g:Extend, 'more')
2111  ReadRef(g:Read)->assert_equal('some more')
2112  ExtendRef(g:Extend, 'even')
2113  ReadRef(g:Read)->assert_equal('some more even')
2114
2115  unlet g:Extend
2116  unlet g:Read
2117enddef
2118
2119def MakeArgRefs(theArg: string)
2120  var local = 'loc_val'
2121  g:UseArg = (s) => theArg .. '/' .. local .. '/' .. s
2122enddef
2123
2124def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
2125  var local = 'the_loc'
2126  g:UseVararg = (s) => theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)
2127enddef
2128
2129def Test_closure_using_argument()
2130  MakeArgRefs('arg_val')
2131  g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val')
2132
2133  MakeArgRefsVarargs('arg_val', 'one', 'two')
2134  g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two')
2135
2136  unlet g:UseArg
2137  unlet g:UseVararg
2138
2139  var lines =<< trim END
2140      vim9script
2141      def Test(Fun: func(number): number): list<number>
2142        return map([1, 2, 3], (_, i) => Fun(i))
2143      enddef
2144      def Inc(nr: number): number
2145        return nr + 2
2146      enddef
2147      assert_equal([3, 4, 5], Test(Inc))
2148  END
2149  CheckScriptSuccess(lines)
2150enddef
2151
2152def MakeGetAndAppendRefs()
2153  var local = 'a'
2154
2155  def Append(arg: string)
2156    local ..= arg
2157  enddef
2158  g:Append = Append
2159
2160  def Get(): string
2161    return local
2162  enddef
2163  g:Get = Get
2164enddef
2165
2166def Test_closure_append_get()
2167  MakeGetAndAppendRefs()
2168  g:Get()->assert_equal('a')
2169  g:Append('-b')
2170  g:Get()->assert_equal('a-b')
2171  g:Append('-c')
2172  g:Get()->assert_equal('a-b-c')
2173
2174  unlet g:Append
2175  unlet g:Get
2176enddef
2177
2178def Test_nested_closure()
2179  var local = 'text'
2180  def Closure(arg: string): string
2181    return local .. arg
2182  enddef
2183  Closure('!!!')->assert_equal('text!!!')
2184enddef
2185
2186func GetResult(Ref)
2187  return a:Ref('some')
2188endfunc
2189
2190def Test_call_closure_not_compiled()
2191  var text = 'text'
2192  g:Ref = (s) =>  s .. text
2193  GetResult(g:Ref)->assert_equal('sometext')
2194enddef
2195
2196def Test_double_closure_fails()
2197  var lines =<< trim END
2198    vim9script
2199    def Func()
2200      var name = 0
2201      for i in range(2)
2202          timer_start(0, () => name)
2203      endfor
2204    enddef
2205    Func()
2206  END
2207  CheckScriptSuccess(lines)
2208enddef
2209
2210def Test_nested_closure_used()
2211  var lines =<< trim END
2212      vim9script
2213      def Func()
2214        var x = 'hello'
2215        var Closure = () => x
2216        g:Myclosure = () => Closure()
2217      enddef
2218      Func()
2219      assert_equal('hello', g:Myclosure())
2220  END
2221  CheckScriptSuccess(lines)
2222enddef
2223
2224def Test_nested_closure_fails()
2225  var lines =<< trim END
2226    vim9script
2227    def FuncA()
2228      FuncB(0)
2229    enddef
2230    def FuncB(n: number): list<string>
2231      return map([0], (_, v) => n)
2232    enddef
2233    FuncA()
2234  END
2235  CheckScriptFailure(lines, 'E1012:')
2236enddef
2237
2238def Test_global_closure()
2239  var lines =<< trim END
2240      vim9script
2241      def ReverseEveryNLines(n: number, line1: number, line2: number)
2242        var mods = 'sil keepj keepp lockm '
2243        var range = ':' .. line1 .. ',' .. line2
2244        def g:Offset(): number
2245            var offset = (line('.') - line1 + 1) % n
2246            return offset != 0 ? offset : n
2247        enddef
2248        exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()'
2249      enddef
2250
2251      new
2252      repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1)
2253      ReverseEveryNLines(3, 1, 9)
2254  END
2255  CheckScriptSuccess(lines)
2256  var expected = repeat(['ccc', 'bbb', 'aaa'], 3)
2257  assert_equal(expected, getline(1, 9))
2258  bwipe!
2259enddef
2260
2261def Test_global_closure_called_directly()
2262  var lines =<< trim END
2263      vim9script
2264      def Outer()
2265        var x = 1
2266        def g:Inner()
2267          var y = x
2268          x += 1
2269          assert_equal(1, y)
2270        enddef
2271        g:Inner()
2272        assert_equal(2, x)
2273      enddef
2274      Outer()
2275  END
2276  CheckScriptSuccess(lines)
2277  delfunc g:Inner
2278enddef
2279
2280def Test_failure_in_called_function()
2281  # this was using the frame index as the return value
2282  var lines =<< trim END
2283      vim9script
2284      au TerminalWinOpen * eval [][0]
2285      def PopupTerm(a: any)
2286        # make sure typvals on stack are string
2287        ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join()
2288        FireEvent()
2289      enddef
2290      def FireEvent()
2291          do TerminalWinOpen
2292      enddef
2293      # use try/catch to make eval fail
2294      try
2295          call PopupTerm(0)
2296      catch
2297      endtry
2298      au! TerminalWinOpen
2299  END
2300  CheckScriptSuccess(lines)
2301enddef
2302
2303def Test_nested_lambda()
2304  var lines =<< trim END
2305    vim9script
2306    def Func()
2307      var x = 4
2308      var Lambda1 = () => 7
2309      var Lambda2 = () => [Lambda1(), x]
2310      var res = Lambda2()
2311      assert_equal([7, 4], res)
2312    enddef
2313    Func()
2314  END
2315  CheckScriptSuccess(lines)
2316enddef
2317
2318def Test_double_nested_lambda()
2319  var lines =<< trim END
2320      vim9script
2321      def F(head: string): func(string): func(string): string
2322        return (sep: string): func(string): string => ((tail: string): string => {
2323            return head .. sep .. tail
2324          })
2325      enddef
2326      assert_equal('hello-there', F('hello')('-')('there'))
2327  END
2328  CheckScriptSuccess(lines)
2329enddef
2330
2331def Test_nested_inline_lambda()
2332  var lines =<< trim END
2333      vim9script
2334      def F(text: string): func(string): func(string): string
2335        return (arg: string): func(string): string => ((sep: string): string => {
2336            return sep .. arg .. text
2337          })
2338      enddef
2339      assert_equal('--there++', F('++')('there')('--'))
2340  END
2341  CheckScriptSuccess(lines)
2342
2343  lines =<< trim END
2344      vim9script
2345      echo range(4)->mapnew((_, v) => {
2346        return range(v) ->mapnew((_, s) => {
2347          return string(s)
2348          })
2349        })
2350  END
2351  CheckScriptSuccess(lines)
2352
2353  lines =<< trim END
2354      vim9script
2355
2356      def s:func()
2357        range(10)
2358          ->mapnew((_, _) => ({
2359            key: range(10)->mapnew((_, _) => {
2360              return ' '
2361            }),
2362          }))
2363      enddef
2364
2365      defcomp
2366  END
2367  CheckScriptSuccess(lines)
2368enddef
2369
2370def Shadowed(): list<number>
2371  var FuncList: list<func: number> = [() => 42]
2372  return FuncList->mapnew((_, Shadowed) => Shadowed())
2373enddef
2374
2375def Test_lambda_arg_shadows_func()
2376  assert_equal([42], Shadowed())
2377enddef
2378
2379def Line_continuation_in_def(dir: string = ''): string
2380  var path: string = empty(dir)
2381          \ ? 'empty'
2382          \ : 'full'
2383  return path
2384enddef
2385
2386def Test_line_continuation_in_def()
2387  Line_continuation_in_def('.')->assert_equal('full')
2388enddef
2389
2390def Test_script_var_in_lambda()
2391  var lines =<< trim END
2392      vim9script
2393      var script = 'test'
2394      assert_equal(['test'], map(['one'], (_, _) => script))
2395  END
2396  CheckScriptSuccess(lines)
2397enddef
2398
2399def Line_continuation_in_lambda(): list<string>
2400  var x = range(97, 100)
2401      ->mapnew((_, v) => nr2char(v)
2402          ->toupper())
2403      ->reverse()
2404  return x
2405enddef
2406
2407def Test_line_continuation_in_lambda()
2408  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
2409
2410  var lines =<< trim END
2411      vim9script
2412      var res = [{n: 1, m: 2, s: 'xxx'}]
2413                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
2414                    v.n,
2415                    v.m,
2416                    substitute(v.s, '.*', 'yyy', '')
2417                    ))
2418      assert_equal(['1:2:yyy'], res)
2419  END
2420  CheckScriptSuccess(lines)
2421enddef
2422
2423def Test_list_lambda()
2424  timer_start(1000, (_) => 0)
2425  var body = execute(timer_info()[0].callback
2426         ->string()
2427         ->substitute("('", ' ', '')
2428         ->substitute("')", '', '')
2429         ->substitute('function\zs', ' ', ''))
2430  assert_match('def <lambda>\d\+(_: any): number\n1  return 0\n   enddef', body)
2431enddef
2432
2433def Test_lambda_block_variable()
2434  var lines =<< trim END
2435      vim9script
2436      var flist: list<func>
2437      for i in range(10)
2438          var inloop = i
2439          flist[i] = () => inloop
2440      endfor
2441  END
2442  CheckScriptSuccess(lines)
2443
2444  lines =<< trim END
2445      vim9script
2446      if true
2447        var outloop = 5
2448        var flist: list<func>
2449        for i in range(10)
2450          flist[i] = () => outloop
2451        endfor
2452      endif
2453  END
2454  CheckScriptSuccess(lines)
2455
2456  lines =<< trim END
2457      vim9script
2458      if true
2459        var outloop = 5
2460      endif
2461      var flist: list<func>
2462      for i in range(10)
2463        flist[i] = () => outloop
2464      endfor
2465  END
2466  CheckScriptFailure(lines, 'E1001: Variable not found: outloop', 1)
2467
2468  lines =<< trim END
2469      vim9script
2470      for i in range(10)
2471        var Ref = () => 0
2472      endfor
2473      assert_equal(0, ((i) => 0)(0))
2474  END
2475  CheckScriptSuccess(lines)
2476enddef
2477
2478def Test_legacy_lambda()
2479  legacy echo {x -> 'hello ' .. x}('foo')
2480
2481  var lines =<< trim END
2482      echo {x -> 'hello ' .. x}('foo')
2483  END
2484  CheckDefAndScriptFailure(lines, 'E720:')
2485
2486  lines =<< trim END
2487      vim9script
2488      def Func()
2489        echo (() => 'no error')()
2490      enddef
2491      legacy call s:Func()
2492  END
2493  CheckScriptSuccess(lines)
2494enddef
2495
2496def Test_legacy()
2497  var lines =<< trim END
2498      vim9script
2499      func g:LegacyFunction()
2500        let g:legacyvar = 1
2501      endfunc
2502      def Testit()
2503        legacy call g:LegacyFunction()
2504      enddef
2505      Testit()
2506      assert_equal(1, g:legacyvar)
2507      unlet g:legacyvar
2508      delfunc g:LegacyFunction
2509  END
2510  CheckScriptSuccess(lines)
2511enddef
2512
2513def Test_legacy_errors()
2514  for cmd in ['if', 'elseif', 'else', 'endif',
2515              'for', 'endfor', 'continue', 'break',
2516              'while', 'endwhile',
2517              'try', 'catch', 'finally', 'endtry']
2518    CheckDefFailure(['legacy ' .. cmd .. ' expr'], 'E1189:')
2519  endfor
2520enddef
2521
2522def DoFilterThis(a: string): list<string>
2523  # closure nested inside another closure using argument
2524  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
2525  return ['x', 'y', 'a', 'x2', 'c']->Filter()
2526enddef
2527
2528def Test_nested_closure_using_argument()
2529  assert_equal(['x', 'x2'], DoFilterThis('x'))
2530enddef
2531
2532def Test_triple_nested_closure()
2533  var what = 'x'
2534  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
2535  var Filter = (l) => filter(l, (_, v) => Match(v, what))
2536  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
2537enddef
2538
2539func Test_silent_echo()
2540  CheckScreendump
2541
2542  let lines =<< trim END
2543    vim9script
2544    def EchoNothing()
2545      silent echo ''
2546    enddef
2547    defcompile
2548  END
2549  call writefile(lines, 'XTest_silent_echo')
2550
2551  " Check that the balloon shows up after a mouse move
2552  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
2553  call term_sendkeys(buf, ":abc")
2554  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
2555
2556  " clean up
2557  call StopVimInTerminal(buf)
2558  call delete('XTest_silent_echo')
2559endfunc
2560
2561def SilentlyError()
2562  execute('silent! invalid')
2563  g:did_it = 'yes'
2564enddef
2565
2566func UserError()
2567  silent! invalid
2568endfunc
2569
2570def SilentlyUserError()
2571  UserError()
2572  g:did_it = 'yes'
2573enddef
2574
2575" This can't be a :def function, because the assert would not be reached.
2576func Test_ignore_silent_error()
2577  let g:did_it = 'no'
2578  call SilentlyError()
2579  call assert_equal('yes', g:did_it)
2580
2581  let g:did_it = 'no'
2582  call SilentlyUserError()
2583  call assert_equal('yes', g:did_it)
2584
2585  unlet g:did_it
2586endfunc
2587
2588def Test_ignore_silent_error_in_filter()
2589  var lines =<< trim END
2590      vim9script
2591      def Filter(winid: number, key: string): bool
2592          if key == 'o'
2593              silent! eval [][0]
2594              return true
2595          endif
2596          return popup_filter_menu(winid, key)
2597      enddef
2598
2599      popup_create('popup', {filter: Filter})
2600      feedkeys("o\r", 'xnt')
2601  END
2602  CheckScriptSuccess(lines)
2603enddef
2604
2605def Fibonacci(n: number): number
2606  if n < 2
2607    return n
2608  else
2609    return Fibonacci(n - 1) + Fibonacci(n - 2)
2610  endif
2611enddef
2612
2613def Test_recursive_call()
2614  Fibonacci(20)->assert_equal(6765)
2615enddef
2616
2617def TreeWalk(dir: string): list<any>
2618  return readdir(dir)->mapnew((_, val) =>
2619            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2620               ? {[val]: TreeWalk(dir .. '/' .. val)}
2621               : val
2622             )
2623enddef
2624
2625def Test_closure_in_map()
2626  mkdir('XclosureDir/tdir', 'p')
2627  writefile(['111'], 'XclosureDir/file1')
2628  writefile(['222'], 'XclosureDir/file2')
2629  writefile(['333'], 'XclosureDir/tdir/file3')
2630
2631  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2632
2633  delete('XclosureDir', 'rf')
2634enddef
2635
2636def Test_invalid_function_name()
2637  var lines =<< trim END
2638      vim9script
2639      def s: list<string>
2640  END
2641  CheckScriptFailure(lines, 'E129:')
2642
2643  lines =<< trim END
2644      vim9script
2645      def g: list<string>
2646  END
2647  CheckScriptFailure(lines, 'E129:')
2648
2649  lines =<< trim END
2650      vim9script
2651      def <SID>: list<string>
2652  END
2653  CheckScriptFailure(lines, 'E884:')
2654
2655  lines =<< trim END
2656      vim9script
2657      def F list<string>
2658  END
2659  CheckScriptFailure(lines, 'E488:')
2660enddef
2661
2662def Test_partial_call()
2663  var lines =<< trim END
2664      var Xsetlist: func
2665      Xsetlist = function('setloclist', [0])
2666      Xsetlist([], ' ', {title: 'test'})
2667      getloclist(0, {title: 1})->assert_equal({title: 'test'})
2668
2669      Xsetlist = function('setloclist', [0, [], ' '])
2670      Xsetlist({title: 'test'})
2671      getloclist(0, {title: 1})->assert_equal({title: 'test'})
2672
2673      Xsetlist = function('setqflist')
2674      Xsetlist([], ' ', {title: 'test'})
2675      getqflist({title: 1})->assert_equal({title: 'test'})
2676
2677      Xsetlist = function('setqflist', [[], ' '])
2678      Xsetlist({title: 'test'})
2679      getqflist({title: 1})->assert_equal({title: 'test'})
2680
2681      var Len: func: number = function('len', ['word'])
2682      assert_equal(4, Len())
2683
2684      var RepeatFunc = function('repeat', ['o'])
2685      assert_equal('ooooo', RepeatFunc(5))
2686  END
2687  CheckDefAndScriptSuccess(lines)
2688enddef
2689
2690def Test_cmd_modifier()
2691  tab echo '0'
2692  CheckDefFailure(['5tab echo 3'], 'E16:')
2693enddef
2694
2695def Test_restore_modifiers()
2696  # check that when compiling a :def function command modifiers are not messed
2697  # up.
2698  var lines =<< trim END
2699      vim9script
2700      set eventignore=
2701      autocmd QuickFixCmdPost * copen
2702      def AutocmdsDisabled()
2703        eval 1 + 2
2704      enddef
2705      func Func()
2706        noautocmd call s:AutocmdsDisabled()
2707        let g:ei_after = &eventignore
2708      endfunc
2709      Func()
2710  END
2711  CheckScriptSuccess(lines)
2712  g:ei_after->assert_equal('')
2713enddef
2714
2715def StackTop()
2716  eval 1 + 2
2717  eval 2 + 3
2718  # call not on fourth line
2719  StackBot()
2720enddef
2721
2722def StackBot()
2723  # throw an error
2724  eval [][0]
2725enddef
2726
2727def Test_callstack_def()
2728  try
2729    StackTop()
2730  catch
2731    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2732  endtry
2733enddef
2734
2735" Re-using spot for variable used in block
2736def Test_block_scoped_var()
2737  var lines =<< trim END
2738      vim9script
2739      def Func()
2740        var x = ['a', 'b', 'c']
2741        if 1
2742          var y = 'x'
2743          map(x, (_, _) => y)
2744        endif
2745        var z = x
2746        assert_equal(['x', 'x', 'x'], z)
2747      enddef
2748      Func()
2749  END
2750  CheckScriptSuccess(lines)
2751enddef
2752
2753def Test_reset_did_emsg()
2754  var lines =<< trim END
2755      @s = 'blah'
2756      au BufWinLeave * #
2757      def Func()
2758        var winid = popup_create('popup', {})
2759        exe '*s'
2760        popup_close(winid)
2761      enddef
2762      Func()
2763  END
2764  CheckScriptFailure(lines, 'E492:', 8)
2765  delfunc! g:Func
2766enddef
2767
2768def Test_did_emsg_reset()
2769  # executing an autocommand resets did_emsg, this should not result in a
2770  # builtin function considered failing
2771  var lines =<< trim END
2772      vim9script
2773      au BufWinLeave * #
2774      def Func()
2775          popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()})
2776          eval [][0]
2777      enddef
2778      nno <F3> <cmd>call <sid>Func()<cr>
2779      feedkeys("\<F3>\e", 'xt')
2780  END
2781  writefile(lines, 'XemsgReset')
2782  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2783  delete('XemsgReset')
2784  nunmap <F3>
2785  au! BufWinLeave
2786enddef
2787
2788def Test_abort_with_silent_call()
2789  var lines =<< trim END
2790      vim9script
2791      g:result = 'none'
2792      def Func()
2793        g:result += 3
2794        g:result = 'yes'
2795      enddef
2796      # error is silenced, but function aborts on error
2797      silent! Func()
2798      assert_equal('none', g:result)
2799      unlet g:result
2800  END
2801  CheckScriptSuccess(lines)
2802enddef
2803
2804def Test_continues_with_silent_error()
2805  var lines =<< trim END
2806      vim9script
2807      g:result = 'none'
2808      def Func()
2809        silent!  g:result += 3
2810        g:result = 'yes'
2811      enddef
2812      # error is silenced, function does not abort
2813      Func()
2814      assert_equal('yes', g:result)
2815      unlet g:result
2816  END
2817  CheckScriptSuccess(lines)
2818enddef
2819
2820def Test_abort_even_with_silent()
2821  var lines =<< trim END
2822      vim9script
2823      g:result = 'none'
2824      def Func()
2825        eval {-> ''}() .. '' .. {}['X']
2826        g:result = 'yes'
2827      enddef
2828      silent! Func()
2829      assert_equal('none', g:result)
2830      unlet g:result
2831  END
2832  CheckScriptSuccess(lines)
2833enddef
2834
2835def Test_cmdmod_silent_restored()
2836  var lines =<< trim END
2837      vim9script
2838      def Func()
2839        g:result = 'none'
2840        silent! g:result += 3
2841        g:result = 'none'
2842        g:result += 3
2843      enddef
2844      Func()
2845  END
2846  # can't use CheckScriptFailure, it ignores the :silent!
2847  var fname = 'Xdefsilent'
2848  writefile(lines, fname)
2849  var caught = 'no'
2850  try
2851    exe 'source ' .. fname
2852  catch /E1030:/
2853    caught = 'yes'
2854    assert_match('Func, line 4', v:throwpoint)
2855  endtry
2856  assert_equal('yes', caught)
2857  delete(fname)
2858enddef
2859
2860def Test_cmdmod_silent_nested()
2861  var lines =<< trim END
2862      vim9script
2863      var result = ''
2864
2865      def Error()
2866          result ..= 'Eb'
2867          eval [][0]
2868          result ..= 'Ea'
2869      enddef
2870
2871      def Crash()
2872          result ..= 'Cb'
2873          sil! Error()
2874          result ..= 'Ca'
2875      enddef
2876
2877      Crash()
2878      assert_equal('CbEbEaCa', result)
2879  END
2880  CheckScriptSuccess(lines)
2881enddef
2882
2883def Test_dict_member_with_silent()
2884  var lines =<< trim END
2885      vim9script
2886      g:result = 'none'
2887      var d: dict<any>
2888      def Func()
2889        try
2890          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2891        catch
2892        endtry
2893      enddef
2894      silent! Func()
2895      assert_equal('0', g:result)
2896      unlet g:result
2897  END
2898  CheckScriptSuccess(lines)
2899enddef
2900
2901def Test_skip_cmds_with_silent()
2902  var lines =<< trim END
2903      vim9script
2904
2905      def Func(b: bool)
2906        Crash()
2907      enddef
2908
2909      def Crash()
2910        sil! :/not found/d _
2911        sil! :/not found/put _
2912      enddef
2913
2914      Func(true)
2915  END
2916  CheckScriptSuccess(lines)
2917enddef
2918
2919def Test_opfunc()
2920  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2921  def g:Opfunc(_: any): string
2922    setline(1, 'ASDF')
2923    return ''
2924  enddef
2925  new
2926  setline(1, 'asdf')
2927  feedkeys("\<F3>$", 'x')
2928  assert_equal('ASDF', getline(1))
2929
2930  bwipe!
2931  nunmap <F3>
2932enddef
2933
2934" this was crashing on exit
2935def Test_nested_lambda_in_closure()
2936  var lines =<< trim END
2937      vim9script
2938      command WriteDone writefile(['Done'], 'XnestedDone')
2939      def Outer()
2940          def g:Inner()
2941              echo map([1, 2, 3], {_, v -> v + 1})
2942          enddef
2943          g:Inner()
2944      enddef
2945      defcompile
2946      # not reached
2947  END
2948  if !RunVim([], lines, '--clean -c WriteDone -c quit')
2949    return
2950  endif
2951  assert_equal(['Done'], readfile('XnestedDone'))
2952  delete('XnestedDone')
2953enddef
2954
2955def Test_check_func_arg_types()
2956  var lines =<< trim END
2957      vim9script
2958      def F1(x: string): string
2959        return x
2960      enddef
2961
2962      def F2(x: number): number
2963        return x + 1
2964      enddef
2965
2966      def G(g: func): dict<func>
2967        return {f: g}
2968      enddef
2969
2970      def H(d: dict<func>): string
2971        return d.f('a')
2972      enddef
2973  END
2974
2975  CheckScriptSuccess(lines + ['echo H(G(F1))'])
2976  CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
2977enddef
2978
2979def Test_list_any_type_checked()
2980  var lines =<< trim END
2981      vim9script
2982      def Foo()
2983        --decl--
2984        Bar(l)
2985      enddef
2986      def Bar(ll: list<dict<any>>)
2987      enddef
2988      Foo()
2989  END
2990  lines[2] = 'var l: list<any>'
2991  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<dict<any>> but got list<any>', 2)
2992
2993  lines[2] = 'var l: list<any> = []'
2994  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<dict<any>> but got list<any>', 2)
2995
2996  lines[2] = 'var l: list<any> = [11]'
2997  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<dict<any>> but got list<number>', 2)
2998enddef
2999
3000def Test_compile_error()
3001  var lines =<< trim END
3002    def g:Broken()
3003      echo 'a' + {}
3004    enddef
3005    call g:Broken()
3006  END
3007  # First call: compilation error
3008  CheckScriptFailure(lines, 'E1051: Wrong argument type for +')
3009
3010  # Second call won't try compiling again
3011  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
3012  delfunc g:Broken
3013
3014  # No error when compiling with :silent!
3015  lines =<< trim END
3016    def g:Broken()
3017      echo 'a' + []
3018    enddef
3019    silent! defcompile
3020  END
3021  CheckScriptSuccess(lines)
3022
3023  # Calling the function won't try compiling again
3024  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
3025  delfunc g:Broken
3026enddef
3027
3028def Test_ignored_argument()
3029  var lines =<< trim END
3030      vim9script
3031      def Ignore(_, _): string
3032        return 'yes'
3033      enddef
3034      assert_equal('yes', Ignore(1, 2))
3035
3036      func Ok(_)
3037        return a:_
3038      endfunc
3039      assert_equal('ok', Ok('ok'))
3040
3041      func Oktoo()
3042        let _ = 'too'
3043        return _
3044      endfunc
3045      assert_equal('too', Oktoo())
3046
3047      assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1)))
3048  END
3049  CheckScriptSuccess(lines)
3050
3051  lines =<< trim END
3052      def Ignore(_: string): string
3053        return _
3054      enddef
3055      defcompile
3056  END
3057  CheckScriptFailure(lines, 'E1181:', 1)
3058
3059  lines =<< trim END
3060      var _ = 1
3061  END
3062  CheckDefAndScriptFailure(lines, 'E1181:', 1)
3063
3064  lines =<< trim END
3065      var x = _
3066  END
3067  CheckDefAndScriptFailure(lines, 'E1181:', 1)
3068enddef
3069
3070def Test_too_many_arguments()
3071  var lines =<< trim END
3072    echo [0, 1, 2]->map(() => 123)
3073  END
3074  CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1)
3075
3076  lines =<< trim END
3077    echo [0, 1, 2]->map((_) => 123)
3078  END
3079  CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1)
3080enddef
3081
3082def Test_closing_brace_at_start_of_line()
3083  var lines =<< trim END
3084      def Func()
3085      enddef
3086      Func(
3087      )
3088  END
3089  call CheckDefAndScriptSuccess(lines)
3090enddef
3091
3092func CreateMydict()
3093  let g:mydict = {}
3094  func g:mydict.afunc()
3095    let g:result = self.key
3096  endfunc
3097endfunc
3098
3099def Test_numbered_function_reference()
3100  CreateMydict()
3101  var output = execute('legacy func g:mydict.afunc')
3102  var funcName = 'g:' .. substitute(output, '.*function \(\d\+\).*', '\1', '')
3103  execute 'function(' .. funcName .. ', [], {key: 42})()'
3104  # check that the function still exists
3105  assert_equal(output, execute('legacy func g:mydict.afunc'))
3106  unlet g:mydict
3107enddef
3108
3109if has('python3')
3110  def Test_python3_heredoc()
3111    py3 << trim EOF
3112      import vim
3113      vim.vars['didit'] = 'yes'
3114    EOF
3115    assert_equal('yes', g:didit)
3116
3117    python3 << trim EOF
3118      import vim
3119      vim.vars['didit'] = 'again'
3120    EOF
3121    assert_equal('again', g:didit)
3122  enddef
3123endif
3124
3125" This messes up syntax highlight, keep near the end.
3126if has('lua')
3127  def Test_lua_heredoc()
3128    g:d = {}
3129    lua << trim EOF
3130        x = vim.eval('g:d')
3131        x['key'] = 'val'
3132    EOF
3133    assert_equal('val', g:d.key)
3134  enddef
3135endif
3136
3137
3138" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
3139