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