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