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