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 Test_call_legacy_with_dict()
2561  var lines =<< trim END
2562      vim9script
2563      func Legacy() dict
2564        let g:result = self.value
2565      endfunc
2566      def TestDirect()
2567        var d = {value: 'yes', func: Legacy}
2568        d.func()
2569      enddef
2570      TestDirect()
2571      assert_equal('yes', g:result)
2572      unlet g:result
2573
2574      def TestIndirect()
2575        var d = {value: 'foo', func: Legacy}
2576        var Fi = d.func
2577        Fi()
2578      enddef
2579      TestIndirect()
2580      assert_equal('foo', g:result)
2581      unlet g:result
2582
2583      var d = {value: 'bar', func: Legacy}
2584      d.func()
2585      assert_equal('bar', g:result)
2586      unlet g:result
2587  END
2588  CheckScriptSuccess(lines)
2589enddef
2590
2591def DoFilterThis(a: string): list<string>
2592  # closure nested inside another closure using argument
2593  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
2594  return ['x', 'y', 'a', 'x2', 'c']->Filter()
2595enddef
2596
2597def Test_nested_closure_using_argument()
2598  assert_equal(['x', 'x2'], DoFilterThis('x'))
2599enddef
2600
2601def Test_triple_nested_closure()
2602  var what = 'x'
2603  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
2604  var Filter = (l) => filter(l, (_, v) => Match(v, what))
2605  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
2606enddef
2607
2608func Test_silent_echo()
2609  CheckScreendump
2610
2611  let lines =<< trim END
2612    vim9script
2613    def EchoNothing()
2614      silent echo ''
2615    enddef
2616    defcompile
2617  END
2618  call writefile(lines, 'XTest_silent_echo')
2619
2620  " Check that the balloon shows up after a mouse move
2621  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
2622  call term_sendkeys(buf, ":abc")
2623  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
2624
2625  " clean up
2626  call StopVimInTerminal(buf)
2627  call delete('XTest_silent_echo')
2628endfunc
2629
2630def SilentlyError()
2631  execute('silent! invalid')
2632  g:did_it = 'yes'
2633enddef
2634
2635func UserError()
2636  silent! invalid
2637endfunc
2638
2639def SilentlyUserError()
2640  UserError()
2641  g:did_it = 'yes'
2642enddef
2643
2644" This can't be a :def function, because the assert would not be reached.
2645func Test_ignore_silent_error()
2646  let g:did_it = 'no'
2647  call SilentlyError()
2648  call assert_equal('yes', g:did_it)
2649
2650  let g:did_it = 'no'
2651  call SilentlyUserError()
2652  call assert_equal('yes', g:did_it)
2653
2654  unlet g:did_it
2655endfunc
2656
2657def Test_ignore_silent_error_in_filter()
2658  var lines =<< trim END
2659      vim9script
2660      def Filter(winid: number, key: string): bool
2661          if key == 'o'
2662              silent! eval [][0]
2663              return true
2664          endif
2665          return popup_filter_menu(winid, key)
2666      enddef
2667
2668      popup_create('popup', {filter: Filter})
2669      feedkeys("o\r", 'xnt')
2670  END
2671  CheckScriptSuccess(lines)
2672enddef
2673
2674def Fibonacci(n: number): number
2675  if n < 2
2676    return n
2677  else
2678    return Fibonacci(n - 1) + Fibonacci(n - 2)
2679  endif
2680enddef
2681
2682def Test_recursive_call()
2683  Fibonacci(20)->assert_equal(6765)
2684enddef
2685
2686def TreeWalk(dir: string): list<any>
2687  return readdir(dir)->mapnew((_, val) =>
2688            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2689               ? {[val]: TreeWalk(dir .. '/' .. val)}
2690               : val
2691             )
2692enddef
2693
2694def Test_closure_in_map()
2695  mkdir('XclosureDir/tdir', 'p')
2696  writefile(['111'], 'XclosureDir/file1')
2697  writefile(['222'], 'XclosureDir/file2')
2698  writefile(['333'], 'XclosureDir/tdir/file3')
2699
2700  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2701
2702  delete('XclosureDir', 'rf')
2703enddef
2704
2705def Test_invalid_function_name()
2706  var lines =<< trim END
2707      vim9script
2708      def s: list<string>
2709  END
2710  CheckScriptFailure(lines, 'E129:')
2711
2712  lines =<< trim END
2713      vim9script
2714      def g: list<string>
2715  END
2716  CheckScriptFailure(lines, 'E129:')
2717
2718  lines =<< trim END
2719      vim9script
2720      def <SID>: list<string>
2721  END
2722  CheckScriptFailure(lines, 'E884:')
2723
2724  lines =<< trim END
2725      vim9script
2726      def F list<string>
2727  END
2728  CheckScriptFailure(lines, 'E488:')
2729enddef
2730
2731def Test_partial_call()
2732  var lines =<< trim END
2733      var Xsetlist: func
2734      Xsetlist = function('setloclist', [0])
2735      Xsetlist([], ' ', {title: 'test'})
2736      getloclist(0, {title: 1})->assert_equal({title: 'test'})
2737
2738      Xsetlist = function('setloclist', [0, [], ' '])
2739      Xsetlist({title: 'test'})
2740      getloclist(0, {title: 1})->assert_equal({title: 'test'})
2741
2742      Xsetlist = function('setqflist')
2743      Xsetlist([], ' ', {title: 'test'})
2744      getqflist({title: 1})->assert_equal({title: 'test'})
2745
2746      Xsetlist = function('setqflist', [[], ' '])
2747      Xsetlist({title: 'test'})
2748      getqflist({title: 1})->assert_equal({title: 'test'})
2749
2750      var Len: func: number = function('len', ['word'])
2751      assert_equal(4, Len())
2752
2753      var RepeatFunc = function('repeat', ['o'])
2754      assert_equal('ooooo', RepeatFunc(5))
2755  END
2756  CheckDefAndScriptSuccess(lines)
2757
2758  lines =<< trim END
2759      vim9script
2760      def Foo(Parser: any)
2761      enddef
2762      var Expr: func(dict<any>): dict<any>
2763      const Call = Foo(Expr)
2764  END
2765  CheckScriptFailure(lines, 'E1235:')
2766enddef
2767
2768def Test_cmd_modifier()
2769  tab echo '0'
2770  CheckDefFailure(['5tab echo 3'], 'E16:')
2771enddef
2772
2773def Test_restore_modifiers()
2774  # check that when compiling a :def function command modifiers are not messed
2775  # up.
2776  var lines =<< trim END
2777      vim9script
2778      set eventignore=
2779      autocmd QuickFixCmdPost * copen
2780      def AutocmdsDisabled()
2781        eval 1 + 2
2782      enddef
2783      func Func()
2784        noautocmd call s:AutocmdsDisabled()
2785        let g:ei_after = &eventignore
2786      endfunc
2787      Func()
2788  END
2789  CheckScriptSuccess(lines)
2790  g:ei_after->assert_equal('')
2791enddef
2792
2793def StackTop()
2794  eval 1 + 2
2795  eval 2 + 3
2796  # call not on fourth line
2797  StackBot()
2798enddef
2799
2800def StackBot()
2801  # throw an error
2802  eval [][0]
2803enddef
2804
2805def Test_callstack_def()
2806  try
2807    StackTop()
2808  catch
2809    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2810  endtry
2811enddef
2812
2813" Re-using spot for variable used in block
2814def Test_block_scoped_var()
2815  var lines =<< trim END
2816      vim9script
2817      def Func()
2818        var x = ['a', 'b', 'c']
2819        if 1
2820          var y = 'x'
2821          map(x, (_, _) => y)
2822        endif
2823        var z = x
2824        assert_equal(['x', 'x', 'x'], z)
2825      enddef
2826      Func()
2827  END
2828  CheckScriptSuccess(lines)
2829enddef
2830
2831def Test_reset_did_emsg()
2832  var lines =<< trim END
2833      @s = 'blah'
2834      au BufWinLeave * #
2835      def Func()
2836        var winid = popup_create('popup', {})
2837        exe '*s'
2838        popup_close(winid)
2839      enddef
2840      Func()
2841  END
2842  CheckScriptFailure(lines, 'E492:', 8)
2843  delfunc! g:Func
2844enddef
2845
2846def Test_did_emsg_reset()
2847  # executing an autocommand resets did_emsg, this should not result in a
2848  # builtin function considered failing
2849  var lines =<< trim END
2850      vim9script
2851      au BufWinLeave * #
2852      def Func()
2853          popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()})
2854          eval [][0]
2855      enddef
2856      nno <F3> <cmd>call <sid>Func()<cr>
2857      feedkeys("\<F3>\e", 'xt')
2858  END
2859  writefile(lines, 'XemsgReset')
2860  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2861  delete('XemsgReset')
2862  nunmap <F3>
2863  au! BufWinLeave
2864enddef
2865
2866def Test_abort_with_silent_call()
2867  var lines =<< trim END
2868      vim9script
2869      g:result = 'none'
2870      def Func()
2871        g:result += 3
2872        g:result = 'yes'
2873      enddef
2874      # error is silenced, but function aborts on error
2875      silent! Func()
2876      assert_equal('none', g:result)
2877      unlet g:result
2878  END
2879  CheckScriptSuccess(lines)
2880enddef
2881
2882def Test_continues_with_silent_error()
2883  var lines =<< trim END
2884      vim9script
2885      g:result = 'none'
2886      def Func()
2887        silent!  g:result += 3
2888        g:result = 'yes'
2889      enddef
2890      # error is silenced, function does not abort
2891      Func()
2892      assert_equal('yes', g:result)
2893      unlet g:result
2894  END
2895  CheckScriptSuccess(lines)
2896enddef
2897
2898def Test_abort_even_with_silent()
2899  var lines =<< trim END
2900      vim9script
2901      g:result = 'none'
2902      def Func()
2903        eval {-> ''}() .. '' .. {}['X']
2904        g:result = 'yes'
2905      enddef
2906      silent! Func()
2907      assert_equal('none', g:result)
2908      unlet g:result
2909  END
2910  CheckScriptSuccess(lines)
2911enddef
2912
2913def Test_cmdmod_silent_restored()
2914  var lines =<< trim END
2915      vim9script
2916      def Func()
2917        g:result = 'none'
2918        silent! g:result += 3
2919        g:result = 'none'
2920        g:result += 3
2921      enddef
2922      Func()
2923  END
2924  # can't use CheckScriptFailure, it ignores the :silent!
2925  var fname = 'Xdefsilent'
2926  writefile(lines, fname)
2927  var caught = 'no'
2928  try
2929    exe 'source ' .. fname
2930  catch /E1030:/
2931    caught = 'yes'
2932    assert_match('Func, line 4', v:throwpoint)
2933  endtry
2934  assert_equal('yes', caught)
2935  delete(fname)
2936enddef
2937
2938def Test_cmdmod_silent_nested()
2939  var lines =<< trim END
2940      vim9script
2941      var result = ''
2942
2943      def Error()
2944          result ..= 'Eb'
2945          eval [][0]
2946          result ..= 'Ea'
2947      enddef
2948
2949      def Crash()
2950          result ..= 'Cb'
2951          sil! Error()
2952          result ..= 'Ca'
2953      enddef
2954
2955      Crash()
2956      assert_equal('CbEbEaCa', result)
2957  END
2958  CheckScriptSuccess(lines)
2959enddef
2960
2961def Test_dict_member_with_silent()
2962  var lines =<< trim END
2963      vim9script
2964      g:result = 'none'
2965      var d: dict<any>
2966      def Func()
2967        try
2968          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2969        catch
2970        endtry
2971      enddef
2972      silent! Func()
2973      assert_equal('0', g:result)
2974      unlet g:result
2975  END
2976  CheckScriptSuccess(lines)
2977enddef
2978
2979def Test_skip_cmds_with_silent()
2980  var lines =<< trim END
2981      vim9script
2982
2983      def Func(b: bool)
2984        Crash()
2985      enddef
2986
2987      def Crash()
2988        sil! :/not found/d _
2989        sil! :/not found/put _
2990      enddef
2991
2992      Func(true)
2993  END
2994  CheckScriptSuccess(lines)
2995enddef
2996
2997def Test_opfunc()
2998  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2999  def g:Opfunc(_: any): string
3000    setline(1, 'ASDF')
3001    return ''
3002  enddef
3003  new
3004  setline(1, 'asdf')
3005  feedkeys("\<F3>$", 'x')
3006  assert_equal('ASDF', getline(1))
3007
3008  bwipe!
3009  nunmap <F3>
3010enddef
3011
3012" this was crashing on exit
3013def Test_nested_lambda_in_closure()
3014  var lines =<< trim END
3015      vim9script
3016      command WriteDone writefile(['Done'], 'XnestedDone')
3017      def Outer()
3018          def g:Inner()
3019              echo map([1, 2, 3], {_, v -> v + 1})
3020          enddef
3021          g:Inner()
3022      enddef
3023      defcompile
3024      # not reached
3025  END
3026  if !RunVim([], lines, '--clean -c WriteDone -c quit')
3027    return
3028  endif
3029  assert_equal(['Done'], readfile('XnestedDone'))
3030  delete('XnestedDone')
3031enddef
3032
3033def Test_check_func_arg_types()
3034  var lines =<< trim END
3035      vim9script
3036      def F1(x: string): string
3037        return x
3038      enddef
3039
3040      def F2(x: number): number
3041        return x + 1
3042      enddef
3043
3044      def G(g: func): dict<func>
3045        return {f: g}
3046      enddef
3047
3048      def H(d: dict<func>): string
3049        return d.f('a')
3050      enddef
3051  END
3052
3053  CheckScriptSuccess(lines + ['echo H(G(F1))'])
3054  CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
3055enddef
3056
3057def Test_list_any_type_checked()
3058  var lines =<< trim END
3059      vim9script
3060      def Foo()
3061        --decl--
3062        Bar(l)
3063      enddef
3064      def Bar(ll: list<dict<any>>)
3065      enddef
3066      Foo()
3067  END
3068  lines[2] = 'var l: list<any>'
3069  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<dict<any>> but got list<any>', 2)
3070
3071  lines[2] = 'var l: list<any> = []'
3072  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<dict<any>> but got list<any>', 2)
3073
3074  lines[2] = 'var l: list<any> = [11]'
3075  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<dict<any>> but got list<number>', 2)
3076enddef
3077
3078def Test_compile_error()
3079  var lines =<< trim END
3080    def g:Broken()
3081      echo 'a' + {}
3082    enddef
3083    call g:Broken()
3084  END
3085  # First call: compilation error
3086  CheckScriptFailure(lines, 'E1051: Wrong argument type for +')
3087
3088  # Second call won't try compiling again
3089  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
3090  delfunc g:Broken
3091
3092  # No error when compiling with :silent!
3093  lines =<< trim END
3094    def g:Broken()
3095      echo 'a' + []
3096    enddef
3097    silent! defcompile
3098  END
3099  CheckScriptSuccess(lines)
3100
3101  # Calling the function won't try compiling again
3102  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
3103  delfunc g:Broken
3104enddef
3105
3106def Test_ignored_argument()
3107  var lines =<< trim END
3108      vim9script
3109      def Ignore(_, _): string
3110        return 'yes'
3111      enddef
3112      assert_equal('yes', Ignore(1, 2))
3113
3114      func Ok(_)
3115        return a:_
3116      endfunc
3117      assert_equal('ok', Ok('ok'))
3118
3119      func Oktoo()
3120        let _ = 'too'
3121        return _
3122      endfunc
3123      assert_equal('too', Oktoo())
3124
3125      assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1)))
3126  END
3127  CheckScriptSuccess(lines)
3128
3129  lines =<< trim END
3130      def Ignore(_: string): string
3131        return _
3132      enddef
3133      defcompile
3134  END
3135  CheckScriptFailure(lines, 'E1181:', 1)
3136
3137  lines =<< trim END
3138      var _ = 1
3139  END
3140  CheckDefAndScriptFailure(lines, 'E1181:', 1)
3141
3142  lines =<< trim END
3143      var x = _
3144  END
3145  CheckDefAndScriptFailure(lines, 'E1181:', 1)
3146enddef
3147
3148def Test_too_many_arguments()
3149  var lines =<< trim END
3150    echo [0, 1, 2]->map(() => 123)
3151  END
3152  CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1)
3153
3154  lines =<< trim END
3155    echo [0, 1, 2]->map((_) => 123)
3156  END
3157  CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1)
3158enddef
3159
3160def Test_closing_brace_at_start_of_line()
3161  var lines =<< trim END
3162      def Func()
3163      enddef
3164      Func(
3165      )
3166  END
3167  call CheckDefAndScriptSuccess(lines)
3168enddef
3169
3170func CreateMydict()
3171  let g:mydict = {}
3172  func g:mydict.afunc()
3173    let g:result = self.key
3174  endfunc
3175endfunc
3176
3177def Test_numbered_function_reference()
3178  CreateMydict()
3179  var output = execute('legacy func g:mydict.afunc')
3180  var funcName = 'g:' .. substitute(output, '.*function \(\d\+\).*', '\1', '')
3181  execute 'function(' .. funcName .. ', [], {key: 42})()'
3182  # check that the function still exists
3183  assert_equal(output, execute('legacy func g:mydict.afunc'))
3184  unlet g:mydict
3185enddef
3186
3187if has('python3')
3188  def Test_python3_heredoc()
3189    py3 << trim EOF
3190      import vim
3191      vim.vars['didit'] = 'yes'
3192    EOF
3193    assert_equal('yes', g:didit)
3194
3195    python3 << trim EOF
3196      import vim
3197      vim.vars['didit'] = 'again'
3198    EOF
3199    assert_equal('again', g:didit)
3200  enddef
3201endif
3202
3203" This messes up syntax highlight, keep near the end.
3204if has('lua')
3205  def Test_lua_heredoc()
3206    g:d = {}
3207    lua << trim EOF
3208        x = vim.eval('g:d')
3209        x['key'] = 'val'
3210    EOF
3211    assert_equal('val', g:d.key)
3212  enddef
3213endif
3214
3215
3216" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
3217