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