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