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