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