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