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