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