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