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(['def Func(): list', 'return []', 'enddef'], 'E1008:')
1433  delfunc! g:Func
1434  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
1435  delfunc! g:Func
1436  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
1437  delfunc! g:Func
1438
1439  CheckScriptFailure([
1440        'vim9script',
1441        'def FuncB()',
1442        '  return 123',
1443        'enddef',
1444        'def FuncA()',
1445        '   FuncB()',
1446        'enddef',
1447        'defcompile'], 'E1096:')
1448enddef
1449
1450def Test_arg_type_wrong()
1451  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
1452  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
1453  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
1454  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
1455  CheckScriptFailure(['def Func6(...x:list<number>)', 'echo "a"', 'enddef'], 'E1069:')
1456  CheckScriptFailure(['def Func7(...x: int)', 'echo "a"', 'enddef'], 'E1010:')
1457enddef
1458
1459def Test_white_space_before_comma()
1460  var lines =<< trim END
1461    vim9script
1462    def Func(a: number , b: number)
1463    enddef
1464  END
1465  CheckScriptFailure(lines, 'E1068:')
1466  call assert_fails('vim9cmd echo stridx("a" .. "b" , "a")', 'E1068:')
1467enddef
1468
1469def Test_white_space_after_comma()
1470  var lines =<< trim END
1471    vim9script
1472    def Func(a: number,b: number)
1473    enddef
1474  END
1475  CheckScriptFailure(lines, 'E1069:')
1476
1477  # OK in legacy function
1478  lines =<< trim END
1479    vim9script
1480    func Func(a,b)
1481    endfunc
1482  END
1483  CheckScriptSuccess(lines)
1484enddef
1485
1486def Test_vim9script_call()
1487  var lines =<< trim END
1488    vim9script
1489    var name = ''
1490    def MyFunc(arg: string)
1491       name = arg
1492    enddef
1493    MyFunc('foobar')
1494    name->assert_equal('foobar')
1495
1496    var str = 'barfoo'
1497    str->MyFunc()
1498    name->assert_equal('barfoo')
1499
1500    g:value = 'value'
1501    g:value->MyFunc()
1502    name->assert_equal('value')
1503
1504    var listvar = []
1505    def ListFunc(arg: list<number>)
1506       listvar = arg
1507    enddef
1508    [1, 2, 3]->ListFunc()
1509    listvar->assert_equal([1, 2, 3])
1510
1511    var dictvar = {}
1512    def DictFunc(arg: dict<number>)
1513       dictvar = arg
1514    enddef
1515    {a: 1, b: 2}->DictFunc()
1516    dictvar->assert_equal({a: 1, b: 2})
1517    def CompiledDict()
1518      {a: 3, b: 4}->DictFunc()
1519    enddef
1520    CompiledDict()
1521    dictvar->assert_equal({a: 3, b: 4})
1522
1523    {a: 3, b: 4}->DictFunc()
1524    dictvar->assert_equal({a: 3, b: 4})
1525
1526    ('text')->MyFunc()
1527    name->assert_equal('text')
1528    ("some")->MyFunc()
1529    name->assert_equal('some')
1530
1531    # line starting with single quote is not a mark
1532    # line starting with double quote can be a method call
1533    'asdfasdf'->MyFunc()
1534    name->assert_equal('asdfasdf')
1535    "xyz"->MyFunc()
1536    name->assert_equal('xyz')
1537
1538    def UseString()
1539      'xyork'->MyFunc()
1540    enddef
1541    UseString()
1542    name->assert_equal('xyork')
1543
1544    def UseString2()
1545      "knife"->MyFunc()
1546    enddef
1547    UseString2()
1548    name->assert_equal('knife')
1549
1550    # prepending a colon makes it a mark
1551    new
1552    setline(1, ['aaa', 'bbb', 'ccc'])
1553    normal! 3Gmt1G
1554    :'t
1555    getcurpos()[1]->assert_equal(3)
1556    bwipe!
1557
1558    MyFunc(
1559        'continued'
1560        )
1561    assert_equal('continued',
1562            name
1563            )
1564
1565    call MyFunc(
1566        'more'
1567          ..
1568          'lines'
1569        )
1570    assert_equal(
1571        'morelines',
1572        name)
1573  END
1574  writefile(lines, 'Xcall.vim')
1575  source Xcall.vim
1576  delete('Xcall.vim')
1577enddef
1578
1579def Test_vim9script_call_fail_decl()
1580  var lines =<< trim END
1581    vim9script
1582    var name = ''
1583    def MyFunc(arg: string)
1584       var name = 123
1585    enddef
1586    defcompile
1587  END
1588  CheckScriptFailure(lines, 'E1054:')
1589enddef
1590
1591def Test_vim9script_call_fail_type()
1592  var lines =<< trim END
1593    vim9script
1594    def MyFunc(arg: string)
1595      echo arg
1596    enddef
1597    MyFunc(1234)
1598  END
1599  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
1600enddef
1601
1602def Test_vim9script_call_fail_const()
1603  var lines =<< trim END
1604    vim9script
1605    const var = ''
1606    def MyFunc(arg: string)
1607       var = 'asdf'
1608    enddef
1609    defcompile
1610  END
1611  writefile(lines, 'Xcall_const.vim')
1612  assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
1613  delete('Xcall_const.vim')
1614
1615  lines =<< trim END
1616      const g:Aconst = 77
1617      def Change()
1618        # comment
1619        g:Aconst = 99
1620      enddef
1621      call Change()
1622      unlet g:Aconst
1623  END
1624  CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2)
1625enddef
1626
1627" Test that inside :function a Python function can be defined, :def is not
1628" recognized.
1629func Test_function_python()
1630  CheckFeature python3
1631  let py = 'python3'
1632  execute py "<< EOF"
1633def do_something():
1634  return 1
1635EOF
1636endfunc
1637
1638def Test_delfunc()
1639  var lines =<< trim END
1640    vim9script
1641    def g:GoneSoon()
1642      echo 'hello'
1643    enddef
1644
1645    def CallGoneSoon()
1646      GoneSoon()
1647    enddef
1648    defcompile
1649
1650    delfunc g:GoneSoon
1651    CallGoneSoon()
1652  END
1653  writefile(lines, 'XToDelFunc')
1654  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1655  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1656
1657  delete('XToDelFunc')
1658enddef
1659
1660def Test_redef_failure()
1661  writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
1662  so Xdef
1663  writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
1664  so Xdef
1665  writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
1666  assert_fails('so Xdef', 'E1027:', '', 1, 'Func0')
1667  writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
1668  so Xdef
1669  delete('Xdef')
1670
1671  assert_fails('g:Func0()', 'E1091:')
1672  g:Func1()->assert_equal('Func1')
1673  g:Func2()->assert_equal('Func2')
1674
1675  delfunc! Func0
1676  delfunc! Func1
1677  delfunc! Func2
1678enddef
1679
1680def Test_vim9script_func()
1681  var lines =<< trim END
1682    vim9script
1683    func Func(arg)
1684      echo a:arg
1685    endfunc
1686    Func('text')
1687  END
1688  writefile(lines, 'XVim9Func')
1689  so XVim9Func
1690
1691  delete('XVim9Func')
1692enddef
1693
1694let s:funcResult = 0
1695
1696def FuncNoArgNoRet()
1697  s:funcResult = 11
1698enddef
1699
1700def FuncNoArgRetNumber(): number
1701  s:funcResult = 22
1702  return 1234
1703enddef
1704
1705def FuncNoArgRetString(): string
1706  s:funcResult = 45
1707  return 'text'
1708enddef
1709
1710def FuncOneArgNoRet(arg: number)
1711  s:funcResult = arg
1712enddef
1713
1714def FuncOneArgRetNumber(arg: number): number
1715  s:funcResult = arg
1716  return arg
1717enddef
1718
1719def FuncTwoArgNoRet(one: bool, two: number)
1720  s:funcResult = two
1721enddef
1722
1723def FuncOneArgRetString(arg: string): string
1724  return arg
1725enddef
1726
1727def FuncOneArgRetAny(arg: any): any
1728  return arg
1729enddef
1730
1731def Test_func_type()
1732  var Ref1: func()
1733  s:funcResult = 0
1734  Ref1 = FuncNoArgNoRet
1735  Ref1()
1736  s:funcResult->assert_equal(11)
1737
1738  var Ref2: func
1739  s:funcResult = 0
1740  Ref2 = FuncNoArgNoRet
1741  Ref2()
1742  s:funcResult->assert_equal(11)
1743
1744  s:funcResult = 0
1745  Ref2 = FuncOneArgNoRet
1746  Ref2(12)
1747  s:funcResult->assert_equal(12)
1748
1749  s:funcResult = 0
1750  Ref2 = FuncNoArgRetNumber
1751  Ref2()->assert_equal(1234)
1752  s:funcResult->assert_equal(22)
1753
1754  s:funcResult = 0
1755  Ref2 = FuncOneArgRetNumber
1756  Ref2(13)->assert_equal(13)
1757  s:funcResult->assert_equal(13)
1758enddef
1759
1760def Test_repeat_return_type()
1761  var res = 0
1762  for n in repeat([1], 3)
1763    res += n
1764  endfor
1765  res->assert_equal(3)
1766
1767  res = 0
1768  for n in add([1, 2], 3)
1769    res += n
1770  endfor
1771  res->assert_equal(6)
1772enddef
1773
1774def Test_argv_return_type()
1775  next fileone filetwo
1776  var res = ''
1777  for name in argv()
1778    res ..= name
1779  endfor
1780  res->assert_equal('fileonefiletwo')
1781enddef
1782
1783def Test_func_type_part()
1784  var RefVoid: func: void
1785  RefVoid = FuncNoArgNoRet
1786  RefVoid = FuncOneArgNoRet
1787  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
1788  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
1789
1790  var RefAny: func(): any
1791  RefAny = FuncNoArgRetNumber
1792  RefAny = FuncNoArgRetString
1793  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
1794  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
1795
1796  var RefAnyNoArgs: func: any = RefAny
1797
1798  var RefNr: func: number
1799  RefNr = FuncNoArgRetNumber
1800  RefNr = FuncOneArgRetNumber
1801  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1802  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1803
1804  var RefStr: func: string
1805  RefStr = FuncNoArgRetString
1806  RefStr = FuncOneArgRetString
1807  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1808  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1809enddef
1810
1811def Test_func_type_fails()
1812  CheckDefFailure(['var ref1: func()'], 'E704:')
1813
1814  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1815  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1816  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1817  CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1818  CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1819  CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1820
1821  CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
1822  CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
1823  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:')
1824  CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:')
1825enddef
1826
1827def Test_func_return_type()
1828  var nr: number
1829  nr = FuncNoArgRetNumber()
1830  nr->assert_equal(1234)
1831
1832  nr = FuncOneArgRetAny(122)
1833  nr->assert_equal(122)
1834
1835  var str: string
1836  str = FuncOneArgRetAny('yes')
1837  str->assert_equal('yes')
1838
1839  CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
1840enddef
1841
1842def Test_func_common_type()
1843  def FuncOne(n: number): number
1844    return n
1845  enddef
1846  def FuncTwo(s: string): number
1847    return len(s)
1848  enddef
1849  def FuncThree(n: number, s: string): number
1850    return n + len(s)
1851  enddef
1852  var list = [FuncOne, FuncTwo, FuncThree]
1853  assert_equal(8, list[0](8))
1854  assert_equal(4, list[1]('word'))
1855  assert_equal(7, list[2](3, 'word'))
1856enddef
1857
1858def MultiLine(
1859    arg1: string,
1860    arg2 = 1234,
1861    ...rest: list<string>
1862      ): string
1863  return arg1 .. arg2 .. join(rest, '-')
1864enddef
1865
1866def MultiLineComment(
1867    arg1: string, # comment
1868    arg2 = 1234, # comment
1869    ...rest: list<string> # comment
1870      ): string # comment
1871  return arg1 .. arg2 .. join(rest, '-')
1872enddef
1873
1874def Test_multiline()
1875  MultiLine('text')->assert_equal('text1234')
1876  MultiLine('text', 777)->assert_equal('text777')
1877  MultiLine('text', 777, 'one')->assert_equal('text777one')
1878  MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1879enddef
1880
1881func Test_multiline_not_vim9()
1882  call MultiLine('text')->assert_equal('text1234')
1883  call MultiLine('text', 777)->assert_equal('text777')
1884  call MultiLine('text', 777, 'one')->assert_equal('text777one')
1885  call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1886endfunc
1887
1888
1889" When using CheckScriptFailure() for the below test, E1010 is generated instead
1890" of E1056.
1891func Test_E1056_1059()
1892  let caught_1056 = 0
1893  try
1894    def F():
1895      return 1
1896    enddef
1897  catch /E1056:/
1898    let caught_1056 = 1
1899  endtry
1900  eval caught_1056->assert_equal(1)
1901
1902  let caught_1059 = 0
1903  try
1904    def F5(items : list)
1905      echo 'a'
1906    enddef
1907  catch /E1059:/
1908    let caught_1059 = 1
1909  endtry
1910  eval caught_1059->assert_equal(1)
1911endfunc
1912
1913func DelMe()
1914  echo 'DelMe'
1915endfunc
1916
1917def Test_error_reporting()
1918  # comment lines at the start of the function
1919  var lines =<< trim END
1920    " comment
1921    def Func()
1922      # comment
1923      # comment
1924      invalid
1925    enddef
1926    defcompile
1927  END
1928  writefile(lines, 'Xdef')
1929  try
1930    source Xdef
1931    assert_report('should have failed')
1932  catch /E476:/
1933    v:exception->assert_match('Invalid command: invalid')
1934    v:throwpoint->assert_match(', line 3$')
1935  endtry
1936  delfunc! g:Func
1937
1938  # comment lines after the start of the function
1939  lines =<< trim END
1940    " comment
1941    def Func()
1942      var x = 1234
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 4$')
1956  endtry
1957  delfunc! g:Func
1958
1959  lines =<< trim END
1960    vim9script
1961    def Func()
1962      var db = {foo: 1, bar: 2}
1963      # comment
1964      var x = db.asdf
1965    enddef
1966    defcompile
1967    Func()
1968  END
1969  writefile(lines, 'Xdef')
1970  try
1971    source Xdef
1972    assert_report('should have failed')
1973  catch /E716:/
1974    v:throwpoint->assert_match('_Func, line 3$')
1975  endtry
1976  delfunc! g:Func
1977
1978  delete('Xdef')
1979enddef
1980
1981def Test_deleted_function()
1982  CheckDefExecFailure([
1983      'var RefMe: func = function("g:DelMe")',
1984      'delfunc g:DelMe',
1985      'echo RefMe()'], 'E117:')
1986enddef
1987
1988def Test_unknown_function()
1989  CheckDefExecFailure([
1990      'var Ref: func = function("NotExist")',
1991      'delfunc g:NotExist'], 'E700:')
1992enddef
1993
1994def RefFunc(Ref: func(any): any): string
1995  return Ref('more')
1996enddef
1997
1998def Test_closure_simple()
1999  var local = 'some '
2000  RefFunc((s) => local .. s)->assert_equal('some more')
2001enddef
2002
2003def MakeRef()
2004  var local = 'some '
2005  g:Ref = (s) => local .. s
2006enddef
2007
2008def Test_closure_ref_after_return()
2009  MakeRef()
2010  g:Ref('thing')->assert_equal('some thing')
2011  unlet g:Ref
2012enddef
2013
2014def MakeTwoRefs()
2015  var local = ['some']
2016  g:Extend = (s) => local->add(s)
2017  g:Read = () => local
2018enddef
2019
2020def Test_closure_two_refs()
2021  MakeTwoRefs()
2022  join(g:Read(), ' ')->assert_equal('some')
2023  g:Extend('more')
2024  join(g:Read(), ' ')->assert_equal('some more')
2025  g:Extend('even')
2026  join(g:Read(), ' ')->assert_equal('some more even')
2027
2028  unlet g:Extend
2029  unlet g:Read
2030enddef
2031
2032def ReadRef(Ref: func(): list<string>): string
2033  return join(Ref(), ' ')
2034enddef
2035
2036def ExtendRef(Ref: func(string): list<string>, add: string)
2037  Ref(add)
2038enddef
2039
2040def Test_closure_two_indirect_refs()
2041  MakeTwoRefs()
2042  ReadRef(g:Read)->assert_equal('some')
2043  ExtendRef(g:Extend, 'more')
2044  ReadRef(g:Read)->assert_equal('some more')
2045  ExtendRef(g:Extend, 'even')
2046  ReadRef(g:Read)->assert_equal('some more even')
2047
2048  unlet g:Extend
2049  unlet g:Read
2050enddef
2051
2052def MakeArgRefs(theArg: string)
2053  var local = 'loc_val'
2054  g:UseArg = (s) => theArg .. '/' .. local .. '/' .. s
2055enddef
2056
2057def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
2058  var local = 'the_loc'
2059  g:UseVararg = (s) => theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)
2060enddef
2061
2062def Test_closure_using_argument()
2063  MakeArgRefs('arg_val')
2064  g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val')
2065
2066  MakeArgRefsVarargs('arg_val', 'one', 'two')
2067  g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two')
2068
2069  unlet g:UseArg
2070  unlet g:UseVararg
2071
2072  var lines =<< trim END
2073      vim9script
2074      def Test(Fun: func(number): number): list<number>
2075        return map([1, 2, 3], (_, i) => Fun(i))
2076      enddef
2077      def Inc(nr: number): number
2078        return nr + 2
2079      enddef
2080      assert_equal([3, 4, 5], Test(Inc))
2081  END
2082  CheckScriptSuccess(lines)
2083enddef
2084
2085def MakeGetAndAppendRefs()
2086  var local = 'a'
2087
2088  def Append(arg: string)
2089    local ..= arg
2090  enddef
2091  g:Append = Append
2092
2093  def Get(): string
2094    return local
2095  enddef
2096  g:Get = Get
2097enddef
2098
2099def Test_closure_append_get()
2100  MakeGetAndAppendRefs()
2101  g:Get()->assert_equal('a')
2102  g:Append('-b')
2103  g:Get()->assert_equal('a-b')
2104  g:Append('-c')
2105  g:Get()->assert_equal('a-b-c')
2106
2107  unlet g:Append
2108  unlet g:Get
2109enddef
2110
2111def Test_nested_closure()
2112  var local = 'text'
2113  def Closure(arg: string): string
2114    return local .. arg
2115  enddef
2116  Closure('!!!')->assert_equal('text!!!')
2117enddef
2118
2119func GetResult(Ref)
2120  return a:Ref('some')
2121endfunc
2122
2123def Test_call_closure_not_compiled()
2124  var text = 'text'
2125  g:Ref = (s) =>  s .. text
2126  GetResult(g:Ref)->assert_equal('sometext')
2127enddef
2128
2129def Test_double_closure_fails()
2130  var lines =<< trim END
2131    vim9script
2132    def Func()
2133      var name = 0
2134      for i in range(2)
2135          timer_start(0, () => name)
2136      endfor
2137    enddef
2138    Func()
2139  END
2140  CheckScriptSuccess(lines)
2141enddef
2142
2143def Test_nested_closure_used()
2144  var lines =<< trim END
2145      vim9script
2146      def Func()
2147        var x = 'hello'
2148        var Closure = () => x
2149        g:Myclosure = () => Closure()
2150      enddef
2151      Func()
2152      assert_equal('hello', g:Myclosure())
2153  END
2154  CheckScriptSuccess(lines)
2155enddef
2156
2157def Test_nested_closure_fails()
2158  var lines =<< trim END
2159    vim9script
2160    def FuncA()
2161      FuncB(0)
2162    enddef
2163    def FuncB(n: number): list<string>
2164      return map([0], (_, v) => n)
2165    enddef
2166    FuncA()
2167  END
2168  CheckScriptFailure(lines, 'E1012:')
2169enddef
2170
2171def Test_global_closure()
2172  var lines =<< trim END
2173      vim9script
2174      def ReverseEveryNLines(n: number, line1: number, line2: number)
2175        var mods = 'sil keepj keepp lockm '
2176        var range = ':' .. line1 .. ',' .. line2
2177        def g:Offset(): number
2178            var offset = (line('.') - line1 + 1) % n
2179            return offset != 0 ? offset : n
2180        enddef
2181        exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()'
2182      enddef
2183
2184      new
2185      repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1)
2186      ReverseEveryNLines(3, 1, 9)
2187  END
2188  CheckScriptSuccess(lines)
2189  var expected = repeat(['ccc', 'bbb', 'aaa'], 3)
2190  assert_equal(expected, getline(1, 9))
2191  bwipe!
2192enddef
2193
2194def Test_global_closure_called_directly()
2195  var lines =<< trim END
2196      vim9script
2197      def Outer()
2198        var x = 1
2199        def g:Inner()
2200          var y = x
2201          x += 1
2202          assert_equal(1, y)
2203        enddef
2204        g:Inner()
2205        assert_equal(2, x)
2206      enddef
2207      Outer()
2208  END
2209  CheckScriptSuccess(lines)
2210  delfunc g:Inner
2211enddef
2212
2213def Test_failure_in_called_function()
2214  # this was using the frame index as the return value
2215  var lines =<< trim END
2216      vim9script
2217      au TerminalWinOpen * eval [][0]
2218      def PopupTerm(a: any)
2219        # make sure typvals on stack are string
2220        ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join()
2221        FireEvent()
2222      enddef
2223      def FireEvent()
2224          do TerminalWinOpen
2225      enddef
2226      # use try/catch to make eval fail
2227      try
2228          call PopupTerm(0)
2229      catch
2230      endtry
2231      au! TerminalWinOpen
2232  END
2233  CheckScriptSuccess(lines)
2234enddef
2235
2236def Test_nested_lambda()
2237  var lines =<< trim END
2238    vim9script
2239    def Func()
2240      var x = 4
2241      var Lambda1 = () => 7
2242      var Lambda2 = () => [Lambda1(), x]
2243      var res = Lambda2()
2244      assert_equal([7, 4], res)
2245    enddef
2246    Func()
2247  END
2248  CheckScriptSuccess(lines)
2249enddef
2250
2251def Test_double_nested_lambda()
2252  var lines =<< trim END
2253      vim9script
2254      def F(head: string): func(string): func(string): string
2255        return (sep: string): func(string): string => ((tail: string): string => {
2256            return head .. sep .. tail
2257          })
2258      enddef
2259      assert_equal('hello-there', F('hello')('-')('there'))
2260  END
2261  CheckScriptSuccess(lines)
2262enddef
2263
2264def Test_nested_inline_lambda()
2265  var lines =<< trim END
2266      vim9script
2267      def F(text: string): func(string): func(string): string
2268        return (arg: string): func(string): string => ((sep: string): string => {
2269            return sep .. arg .. text
2270          })
2271      enddef
2272      assert_equal('--there++', F('++')('there')('--'))
2273  END
2274  CheckScriptSuccess(lines)
2275
2276  lines =<< trim END
2277      vim9script
2278      echo range(4)->mapnew((_, v) => {
2279        return range(v) ->mapnew((_, s) => {
2280          return string(s)
2281          })
2282        })
2283  END
2284  CheckScriptSuccess(lines)
2285
2286  lines =<< trim END
2287      vim9script
2288
2289      def s:func()
2290        range(10)
2291          ->mapnew((_, _) => ({
2292            key: range(10)->mapnew((_, _) => {
2293              return ' '
2294            }),
2295          }))
2296      enddef
2297
2298      defcomp
2299  END
2300  CheckScriptSuccess(lines)
2301enddef
2302
2303def Shadowed(): list<number>
2304  var FuncList: list<func: number> = [() => 42]
2305  return FuncList->mapnew((_, Shadowed) => Shadowed())
2306enddef
2307
2308def Test_lambda_arg_shadows_func()
2309  assert_equal([42], Shadowed())
2310enddef
2311
2312def Line_continuation_in_def(dir: string = ''): string
2313  var path: string = empty(dir)
2314          \ ? 'empty'
2315          \ : 'full'
2316  return path
2317enddef
2318
2319def Test_line_continuation_in_def()
2320  Line_continuation_in_def('.')->assert_equal('full')
2321enddef
2322
2323def Test_script_var_in_lambda()
2324  var lines =<< trim END
2325      vim9script
2326      var script = 'test'
2327      assert_equal(['test'], map(['one'], (_, _) => script))
2328  END
2329  CheckScriptSuccess(lines)
2330enddef
2331
2332def Line_continuation_in_lambda(): list<string>
2333  var x = range(97, 100)
2334      ->mapnew((_, v) => nr2char(v)
2335          ->toupper())
2336      ->reverse()
2337  return x
2338enddef
2339
2340def Test_line_continuation_in_lambda()
2341  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
2342
2343  var lines =<< trim END
2344      vim9script
2345      var res = [{n: 1, m: 2, s: 'xxx'}]
2346                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
2347                    v.n,
2348                    v.m,
2349                    substitute(v.s, '.*', 'yyy', '')
2350                    ))
2351      assert_equal(['1:2:yyy'], res)
2352  END
2353  CheckScriptSuccess(lines)
2354enddef
2355
2356def Test_list_lambda()
2357  timer_start(1000, (_) => 0)
2358  var body = execute(timer_info()[0].callback
2359         ->string()
2360         ->substitute("('", ' ', '')
2361         ->substitute("')", '', '')
2362         ->substitute('function\zs', ' ', ''))
2363  assert_match('def <lambda>\d\+(_: any): number\n1  return 0\n   enddef', body)
2364enddef
2365
2366def Test_lambda_block_variable()
2367  var lines =<< trim END
2368      vim9script
2369      var flist: list<func>
2370      for i in range(10)
2371          var inloop = i
2372          flist[i] = () => inloop
2373      endfor
2374  END
2375  CheckScriptSuccess(lines)
2376
2377  lines =<< trim END
2378      vim9script
2379      if true
2380        var outloop = 5
2381        var flist: list<func>
2382        for i in range(10)
2383          flist[i] = () => outloop
2384        endfor
2385      endif
2386  END
2387  CheckScriptSuccess(lines)
2388
2389  lines =<< trim END
2390      vim9script
2391      if true
2392        var outloop = 5
2393      endif
2394      var flist: list<func>
2395      for i in range(10)
2396        flist[i] = () => outloop
2397      endfor
2398  END
2399  CheckScriptFailure(lines, 'E1001: Variable not found: outloop', 1)
2400
2401  lines =<< trim END
2402      vim9script
2403      for i in range(10)
2404        var Ref = () => 0
2405      endfor
2406      assert_equal(0, ((i) => 0)(0))
2407  END
2408  CheckScriptSuccess(lines)
2409enddef
2410
2411def Test_legacy_lambda()
2412  legacy echo {x -> 'hello ' .. x}('foo')
2413
2414  var lines =<< trim END
2415      echo {x -> 'hello ' .. x}('foo')
2416  END
2417  CheckDefAndScriptFailure(lines, 'E720:')
2418
2419  lines =<< trim END
2420      vim9script
2421      def Func()
2422        echo (() => 'no error')()
2423      enddef
2424      legacy call s:Func()
2425  END
2426  CheckScriptSuccess(lines)
2427enddef
2428
2429def Test_legacy()
2430  var lines =<< trim END
2431      vim9script
2432      func g:LegacyFunction()
2433        let g:legacyvar = 1
2434      endfunc
2435      def Testit()
2436        legacy call g:LegacyFunction()
2437      enddef
2438      Testit()
2439      assert_equal(1, g:legacyvar)
2440      unlet g:legacyvar
2441      delfunc g:LegacyFunction
2442  END
2443  CheckScriptSuccess(lines)
2444enddef
2445
2446def Test_legacy_errors()
2447  for cmd in ['if', 'elseif', 'else', 'endif',
2448              'for', 'endfor', 'continue', 'break',
2449              'while', 'endwhile',
2450              'try', 'catch', 'finally', 'endtry']
2451    CheckDefFailure(['legacy ' .. cmd .. ' expr'], 'E1189:')
2452  endfor
2453enddef
2454
2455def DoFilterThis(a: string): list<string>
2456  # closure nested inside another closure using argument
2457  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
2458  return ['x', 'y', 'a', 'x2', 'c']->Filter()
2459enddef
2460
2461def Test_nested_closure_using_argument()
2462  assert_equal(['x', 'x2'], DoFilterThis('x'))
2463enddef
2464
2465def Test_triple_nested_closure()
2466  var what = 'x'
2467  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
2468  var Filter = (l) => filter(l, (_, v) => Match(v, what))
2469  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
2470enddef
2471
2472func Test_silent_echo()
2473  CheckScreendump
2474
2475  let lines =<< trim END
2476    vim9script
2477    def EchoNothing()
2478      silent echo ''
2479    enddef
2480    defcompile
2481  END
2482  call writefile(lines, 'XTest_silent_echo')
2483
2484  " Check that the balloon shows up after a mouse move
2485  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
2486  call term_sendkeys(buf, ":abc")
2487  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
2488
2489  " clean up
2490  call StopVimInTerminal(buf)
2491  call delete('XTest_silent_echo')
2492endfunc
2493
2494def SilentlyError()
2495  execute('silent! invalid')
2496  g:did_it = 'yes'
2497enddef
2498
2499func UserError()
2500  silent! invalid
2501endfunc
2502
2503def SilentlyUserError()
2504  UserError()
2505  g:did_it = 'yes'
2506enddef
2507
2508" This can't be a :def function, because the assert would not be reached.
2509func Test_ignore_silent_error()
2510  let g:did_it = 'no'
2511  call SilentlyError()
2512  call assert_equal('yes', g:did_it)
2513
2514  let g:did_it = 'no'
2515  call SilentlyUserError()
2516  call assert_equal('yes', g:did_it)
2517
2518  unlet g:did_it
2519endfunc
2520
2521def Test_ignore_silent_error_in_filter()
2522  var lines =<< trim END
2523      vim9script
2524      def Filter(winid: number, key: string): bool
2525          if key == 'o'
2526              silent! eval [][0]
2527              return true
2528          endif
2529          return popup_filter_menu(winid, key)
2530      enddef
2531
2532      popup_create('popup', {filter: Filter})
2533      feedkeys("o\r", 'xnt')
2534  END
2535  CheckScriptSuccess(lines)
2536enddef
2537
2538def Fibonacci(n: number): number
2539  if n < 2
2540    return n
2541  else
2542    return Fibonacci(n - 1) + Fibonacci(n - 2)
2543  endif
2544enddef
2545
2546def Test_recursive_call()
2547  Fibonacci(20)->assert_equal(6765)
2548enddef
2549
2550def TreeWalk(dir: string): list<any>
2551  return readdir(dir)->mapnew((_, val) =>
2552            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2553               ? {[val]: TreeWalk(dir .. '/' .. val)}
2554               : val
2555             )
2556enddef
2557
2558def Test_closure_in_map()
2559  mkdir('XclosureDir/tdir', 'p')
2560  writefile(['111'], 'XclosureDir/file1')
2561  writefile(['222'], 'XclosureDir/file2')
2562  writefile(['333'], 'XclosureDir/tdir/file3')
2563
2564  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2565
2566  delete('XclosureDir', 'rf')
2567enddef
2568
2569def Test_invalid_function_name()
2570  var lines =<< trim END
2571      vim9script
2572      def s: list<string>
2573  END
2574  CheckScriptFailure(lines, 'E129:')
2575
2576  lines =<< trim END
2577      vim9script
2578      def g: list<string>
2579  END
2580  CheckScriptFailure(lines, 'E129:')
2581
2582  lines =<< trim END
2583      vim9script
2584      def <SID>: list<string>
2585  END
2586  CheckScriptFailure(lines, 'E884:')
2587
2588  lines =<< trim END
2589      vim9script
2590      def F list<string>
2591  END
2592  CheckScriptFailure(lines, 'E488:')
2593enddef
2594
2595def Test_partial_call()
2596  var lines =<< trim END
2597      var Xsetlist: func
2598      Xsetlist = function('setloclist', [0])
2599      Xsetlist([], ' ', {title: 'test'})
2600      getloclist(0, {title: 1})->assert_equal({title: 'test'})
2601
2602      Xsetlist = function('setloclist', [0, [], ' '])
2603      Xsetlist({title: 'test'})
2604      getloclist(0, {title: 1})->assert_equal({title: 'test'})
2605
2606      Xsetlist = function('setqflist')
2607      Xsetlist([], ' ', {title: 'test'})
2608      getqflist({title: 1})->assert_equal({title: 'test'})
2609
2610      Xsetlist = function('setqflist', [[], ' '])
2611      Xsetlist({title: 'test'})
2612      getqflist({title: 1})->assert_equal({title: 'test'})
2613
2614      var Len: func: number = function('len', ['word'])
2615      assert_equal(4, Len())
2616
2617      var RepeatFunc = function('repeat', ['o'])
2618      assert_equal('ooooo', RepeatFunc(5))
2619  END
2620  CheckDefAndScriptSuccess(lines)
2621enddef
2622
2623def Test_cmd_modifier()
2624  tab echo '0'
2625  CheckDefFailure(['5tab echo 3'], 'E16:')
2626enddef
2627
2628def Test_restore_modifiers()
2629  # check that when compiling a :def function command modifiers are not messed
2630  # up.
2631  var lines =<< trim END
2632      vim9script
2633      set eventignore=
2634      autocmd QuickFixCmdPost * copen
2635      def AutocmdsDisabled()
2636        eval 1 + 2
2637      enddef
2638      func Func()
2639        noautocmd call s:AutocmdsDisabled()
2640        let g:ei_after = &eventignore
2641      endfunc
2642      Func()
2643  END
2644  CheckScriptSuccess(lines)
2645  g:ei_after->assert_equal('')
2646enddef
2647
2648def StackTop()
2649  eval 1 + 2
2650  eval 2 + 3
2651  # call not on fourth line
2652  StackBot()
2653enddef
2654
2655def StackBot()
2656  # throw an error
2657  eval [][0]
2658enddef
2659
2660def Test_callstack_def()
2661  try
2662    StackTop()
2663  catch
2664    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2665  endtry
2666enddef
2667
2668" Re-using spot for variable used in block
2669def Test_block_scoped_var()
2670  var lines =<< trim END
2671      vim9script
2672      def Func()
2673        var x = ['a', 'b', 'c']
2674        if 1
2675          var y = 'x'
2676          map(x, (_, _) => y)
2677        endif
2678        var z = x
2679        assert_equal(['x', 'x', 'x'], z)
2680      enddef
2681      Func()
2682  END
2683  CheckScriptSuccess(lines)
2684enddef
2685
2686def Test_reset_did_emsg()
2687  var lines =<< trim END
2688      @s = 'blah'
2689      au BufWinLeave * #
2690      def Func()
2691        var winid = popup_create('popup', {})
2692        exe '*s'
2693        popup_close(winid)
2694      enddef
2695      Func()
2696  END
2697  CheckScriptFailure(lines, 'E492:', 8)
2698  delfunc! g:Func
2699enddef
2700
2701def Test_did_emsg_reset()
2702  # executing an autocommand resets did_emsg, this should not result in a
2703  # builtin function considered failing
2704  var lines =<< trim END
2705      vim9script
2706      au BufWinLeave * #
2707      def Func()
2708          popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()})
2709          eval [][0]
2710      enddef
2711      nno <F3> <cmd>call <sid>Func()<cr>
2712      feedkeys("\<F3>\e", 'xt')
2713  END
2714  writefile(lines, 'XemsgReset')
2715  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2716  delete('XemsgReset')
2717  nunmap <F3>
2718  au! BufWinLeave
2719enddef
2720
2721def Test_abort_with_silent_call()
2722  var lines =<< trim END
2723      vim9script
2724      g:result = 'none'
2725      def Func()
2726        g:result += 3
2727        g:result = 'yes'
2728      enddef
2729      # error is silenced, but function aborts on error
2730      silent! Func()
2731      assert_equal('none', g:result)
2732      unlet g:result
2733  END
2734  CheckScriptSuccess(lines)
2735enddef
2736
2737def Test_continues_with_silent_error()
2738  var lines =<< trim END
2739      vim9script
2740      g:result = 'none'
2741      def Func()
2742        silent!  g:result += 3
2743        g:result = 'yes'
2744      enddef
2745      # error is silenced, function does not abort
2746      Func()
2747      assert_equal('yes', g:result)
2748      unlet g:result
2749  END
2750  CheckScriptSuccess(lines)
2751enddef
2752
2753def Test_abort_even_with_silent()
2754  var lines =<< trim END
2755      vim9script
2756      g:result = 'none'
2757      def Func()
2758        eval {-> ''}() .. '' .. {}['X']
2759        g:result = 'yes'
2760      enddef
2761      silent! Func()
2762      assert_equal('none', g:result)
2763      unlet g:result
2764  END
2765  CheckScriptSuccess(lines)
2766enddef
2767
2768def Test_cmdmod_silent_restored()
2769  var lines =<< trim END
2770      vim9script
2771      def Func()
2772        g:result = 'none'
2773        silent! g:result += 3
2774        g:result = 'none'
2775        g:result += 3
2776      enddef
2777      Func()
2778  END
2779  # can't use CheckScriptFailure, it ignores the :silent!
2780  var fname = 'Xdefsilent'
2781  writefile(lines, fname)
2782  var caught = 'no'
2783  try
2784    exe 'source ' .. fname
2785  catch /E1030:/
2786    caught = 'yes'
2787    assert_match('Func, line 4', v:throwpoint)
2788  endtry
2789  assert_equal('yes', caught)
2790  delete(fname)
2791enddef
2792
2793def Test_cmdmod_silent_nested()
2794  var lines =<< trim END
2795      vim9script
2796      var result = ''
2797
2798      def Error()
2799          result ..= 'Eb'
2800          eval [][0]
2801          result ..= 'Ea'
2802      enddef
2803
2804      def Crash()
2805          result ..= 'Cb'
2806          sil! Error()
2807          result ..= 'Ca'
2808      enddef
2809
2810      Crash()
2811      assert_equal('CbEbEaCa', result)
2812  END
2813  CheckScriptSuccess(lines)
2814enddef
2815
2816def Test_dict_member_with_silent()
2817  var lines =<< trim END
2818      vim9script
2819      g:result = 'none'
2820      var d: dict<any>
2821      def Func()
2822        try
2823          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2824        catch
2825        endtry
2826      enddef
2827      silent! Func()
2828      assert_equal('0', g:result)
2829      unlet g:result
2830  END
2831  CheckScriptSuccess(lines)
2832enddef
2833
2834def Test_skip_cmds_with_silent()
2835  var lines =<< trim END
2836      vim9script
2837
2838      def Func(b: bool)
2839        Crash()
2840      enddef
2841
2842      def Crash()
2843        sil! :/not found/d _
2844        sil! :/not found/put _
2845      enddef
2846
2847      Func(true)
2848  END
2849  CheckScriptSuccess(lines)
2850enddef
2851
2852def Test_opfunc()
2853  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2854  def g:Opfunc(_: any): string
2855    setline(1, 'ASDF')
2856    return ''
2857  enddef
2858  new
2859  setline(1, 'asdf')
2860  feedkeys("\<F3>$", 'x')
2861  assert_equal('ASDF', getline(1))
2862
2863  bwipe!
2864  nunmap <F3>
2865enddef
2866
2867" this was crashing on exit
2868def Test_nested_lambda_in_closure()
2869  var lines =<< trim END
2870      vim9script
2871      command WriteDone writefile(['Done'], 'XnestedDone')
2872      def Outer()
2873          def g:Inner()
2874              echo map([1, 2, 3], {_, v -> v + 1})
2875          enddef
2876          g:Inner()
2877      enddef
2878      defcompile
2879      # not reached
2880  END
2881  if !RunVim([], lines, '--clean -c WriteDone -c quit')
2882    return
2883  endif
2884  assert_equal(['Done'], readfile('XnestedDone'))
2885  delete('XnestedDone')
2886enddef
2887
2888def Test_check_func_arg_types()
2889  var lines =<< trim END
2890      vim9script
2891      def F1(x: string): string
2892        return x
2893      enddef
2894
2895      def F2(x: number): number
2896        return x + 1
2897      enddef
2898
2899      def G(g: func): dict<func>
2900        return {f: g}
2901      enddef
2902
2903      def H(d: dict<func>): string
2904        return d.f('a')
2905      enddef
2906  END
2907
2908  CheckScriptSuccess(lines + ['echo H(G(F1))'])
2909  CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
2910enddef
2911
2912def Test_compile_error()
2913  var lines =<< trim END
2914    def g:Broken()
2915      echo 'a' + {}
2916    enddef
2917    call g:Broken()
2918  END
2919  # First call: compilation error
2920  CheckScriptFailure(lines, 'E1051: Wrong argument type for +')
2921
2922  # Second call won't try compiling again
2923  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2924  delfunc g:Broken
2925
2926  # No error when compiling with :silent!
2927  lines =<< trim END
2928    def g:Broken()
2929      echo 'a' + []
2930    enddef
2931    silent! defcompile
2932  END
2933  CheckScriptSuccess(lines)
2934
2935  # Calling the function won't try compiling again
2936  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2937  delfunc g:Broken
2938enddef
2939
2940def Test_ignored_argument()
2941  var lines =<< trim END
2942      vim9script
2943      def Ignore(_, _): string
2944        return 'yes'
2945      enddef
2946      assert_equal('yes', Ignore(1, 2))
2947
2948      func Ok(_)
2949        return a:_
2950      endfunc
2951      assert_equal('ok', Ok('ok'))
2952
2953      func Oktoo()
2954        let _ = 'too'
2955        return _
2956      endfunc
2957      assert_equal('too', Oktoo())
2958
2959      assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1)))
2960  END
2961  CheckScriptSuccess(lines)
2962
2963  lines =<< trim END
2964      def Ignore(_: string): string
2965        return _
2966      enddef
2967      defcompile
2968  END
2969  CheckScriptFailure(lines, 'E1181:', 1)
2970
2971  lines =<< trim END
2972      var _ = 1
2973  END
2974  CheckDefAndScriptFailure(lines, 'E1181:', 1)
2975
2976  lines =<< trim END
2977      var x = _
2978  END
2979  CheckDefAndScriptFailure(lines, 'E1181:', 1)
2980enddef
2981
2982def Test_too_many_arguments()
2983  var lines =<< trim END
2984    echo [0, 1, 2]->map(() => 123)
2985  END
2986  CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1)
2987
2988  lines =<< trim END
2989    echo [0, 1, 2]->map((_) => 123)
2990  END
2991  CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1)
2992enddef
2993
2994def Test_closing_brace_at_start_of_line()
2995  var lines =<< trim END
2996      def Func()
2997      enddef
2998      Func(
2999      )
3000  END
3001  call CheckDefAndScriptSuccess(lines)
3002enddef
3003
3004if has('python3')
3005  def Test_python3_heredoc()
3006    py3 << trim EOF
3007      import vim
3008      vim.vars['didit'] = 'yes'
3009    EOF
3010    assert_equal('yes', g:didit)
3011
3012    python3 << trim EOF
3013      import vim
3014      vim.vars['didit'] = 'again'
3015    EOF
3016    assert_equal('again', g:didit)
3017  enddef
3018endif
3019
3020" This messes up syntax highlight, keep near the end.
3021if has('lua')
3022  def Test_lua_heredoc()
3023    g:d = {}
3024    lua << trim EOF
3025        x = vim.eval('g:d')
3026        x['key'] = 'val'
3027    EOF
3028    assert_equal('val', g:d.key)
3029  enddef
3030endif
3031
3032
3033" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
3034