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  # TODO: use the "text" argument
2254  var lines =<< trim END
2255      vim9script
2256      def F(text: string): func(string): func(string): string
2257        return (arg: string): func(string): string => ((sep: string): string => {
2258            return sep .. arg
2259          })
2260      enddef
2261      assert_equal('--there', F('unused')('there')('--'))
2262  END
2263  CheckScriptSuccess(lines)
2264
2265  lines =<< trim END
2266      vim9script
2267      echo range(4)->mapnew((_, v) => {
2268        return range(v) ->mapnew((_, s) => {
2269          return string(s)
2270          })
2271        })
2272  END
2273  CheckScriptSuccess(lines)
2274
2275  lines =<< trim END
2276      vim9script
2277
2278      def s:func()
2279        range(10)
2280          ->mapnew((_, _) => ({
2281            key: range(10)->mapnew((_, _) => {
2282              return ' '
2283            }),
2284          }))
2285      enddef
2286
2287      defcomp
2288  END
2289  CheckScriptSuccess(lines)
2290enddef
2291
2292def Shadowed(): list<number>
2293  var FuncList: list<func: number> = [() => 42]
2294  return FuncList->mapnew((_, Shadowed) => Shadowed())
2295enddef
2296
2297def Test_lambda_arg_shadows_func()
2298  assert_equal([42], Shadowed())
2299enddef
2300
2301def Line_continuation_in_def(dir: string = ''): string
2302  var path: string = empty(dir)
2303          \ ? 'empty'
2304          \ : 'full'
2305  return path
2306enddef
2307
2308def Test_line_continuation_in_def()
2309  Line_continuation_in_def('.')->assert_equal('full')
2310enddef
2311
2312def Test_script_var_in_lambda()
2313  var lines =<< trim END
2314      vim9script
2315      var script = 'test'
2316      assert_equal(['test'], map(['one'], (_, _) => script))
2317  END
2318  CheckScriptSuccess(lines)
2319enddef
2320
2321def Line_continuation_in_lambda(): list<string>
2322  var x = range(97, 100)
2323      ->mapnew((_, v) => nr2char(v)
2324          ->toupper())
2325      ->reverse()
2326  return x
2327enddef
2328
2329def Test_line_continuation_in_lambda()
2330  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
2331
2332  var lines =<< trim END
2333      vim9script
2334      var res = [{n: 1, m: 2, s: 'xxx'}]
2335                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
2336                    v.n,
2337                    v.m,
2338                    substitute(v.s, '.*', 'yyy', '')
2339                    ))
2340      assert_equal(['1:2:yyy'], res)
2341  END
2342  CheckScriptSuccess(lines)
2343enddef
2344
2345def Test_list_lambda()
2346  timer_start(1000, (_) => 0)
2347  var body = execute(timer_info()[0].callback
2348         ->string()
2349         ->substitute("('", ' ', '')
2350         ->substitute("')", '', '')
2351         ->substitute('function\zs', ' ', ''))
2352  assert_match('def <lambda>\d\+(_: any): number\n1  return 0\n   enddef', body)
2353enddef
2354
2355def Test_lamba_block_variable()
2356  var lines =<< trim END
2357      vim9script
2358      var flist: list<func>
2359      for i in range(10)
2360          var inloop = i
2361          flist[i] = () => inloop
2362      endfor
2363  END
2364  CheckScriptSuccess(lines)
2365
2366  lines =<< trim END
2367      vim9script
2368      if true
2369        var outloop = 5
2370        var flist: list<func>
2371        for i in range(10)
2372          flist[i] = () => outloop
2373        endfor
2374      endif
2375  END
2376  CheckScriptSuccess(lines)
2377
2378  lines =<< trim END
2379      vim9script
2380      if true
2381        var outloop = 5
2382      endif
2383      var flist: list<func>
2384      for i in range(10)
2385        flist[i] = () => outloop
2386      endfor
2387  END
2388  CheckScriptFailure(lines, 'E1001: Variable not found: outloop', 1)
2389enddef
2390
2391def Test_legacy_lambda()
2392  legacy echo {x -> 'hello ' .. x}('foo')
2393
2394  var lines =<< trim END
2395      echo {x -> 'hello ' .. x}('foo')
2396  END
2397  CheckDefAndScriptFailure(lines, 'E720:')
2398
2399  lines =<< trim END
2400      vim9script
2401      def Func()
2402        echo (() => 'no error')()
2403      enddef
2404      legacy call s:Func()
2405  END
2406  CheckScriptSuccess(lines)
2407enddef
2408
2409def Test_legacy()
2410  var lines =<< trim END
2411      vim9script
2412      func g:LegacyFunction()
2413        let g:legacyvar = 1
2414      endfunc
2415      def Testit()
2416        legacy call g:LegacyFunction()
2417      enddef
2418      Testit()
2419      assert_equal(1, g:legacyvar)
2420      unlet g:legacyvar
2421      delfunc g:LegacyFunction
2422  END
2423  CheckScriptSuccess(lines)
2424enddef
2425
2426def Test_legacy_errors()
2427  for cmd in ['if', 'elseif', 'else', 'endif',
2428              'for', 'endfor', 'continue', 'break',
2429              'while', 'endwhile',
2430              'try', 'catch', 'finally', 'endtry']
2431    CheckDefFailure(['legacy ' .. cmd .. ' expr'], 'E1189:')
2432  endfor
2433enddef
2434
2435def DoFilterThis(a: string): list<string>
2436  # closure nested inside another closure using argument
2437  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
2438  return ['x', 'y', 'a', 'x2', 'c']->Filter()
2439enddef
2440
2441def Test_nested_closure_using_argument()
2442  assert_equal(['x', 'x2'], DoFilterThis('x'))
2443enddef
2444
2445def Test_triple_nested_closure()
2446  var what = 'x'
2447  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
2448  var Filter = (l) => filter(l, (_, v) => Match(v, what))
2449  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
2450enddef
2451
2452func Test_silent_echo()
2453  CheckScreendump
2454
2455  let lines =<< trim END
2456    vim9script
2457    def EchoNothing()
2458      silent echo ''
2459    enddef
2460    defcompile
2461  END
2462  call writefile(lines, 'XTest_silent_echo')
2463
2464  " Check that the balloon shows up after a mouse move
2465  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
2466  call term_sendkeys(buf, ":abc")
2467  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
2468
2469  " clean up
2470  call StopVimInTerminal(buf)
2471  call delete('XTest_silent_echo')
2472endfunc
2473
2474def SilentlyError()
2475  execute('silent! invalid')
2476  g:did_it = 'yes'
2477enddef
2478
2479func UserError()
2480  silent! invalid
2481endfunc
2482
2483def SilentlyUserError()
2484  UserError()
2485  g:did_it = 'yes'
2486enddef
2487
2488" This can't be a :def function, because the assert would not be reached.
2489func Test_ignore_silent_error()
2490  let g:did_it = 'no'
2491  call SilentlyError()
2492  call assert_equal('yes', g:did_it)
2493
2494  let g:did_it = 'no'
2495  call SilentlyUserError()
2496  call assert_equal('yes', g:did_it)
2497
2498  unlet g:did_it
2499endfunc
2500
2501def Test_ignore_silent_error_in_filter()
2502  var lines =<< trim END
2503      vim9script
2504      def Filter(winid: number, key: string): bool
2505          if key == 'o'
2506              silent! eval [][0]
2507              return true
2508          endif
2509          return popup_filter_menu(winid, key)
2510      enddef
2511
2512      popup_create('popup', {filter: Filter})
2513      feedkeys("o\r", 'xnt')
2514  END
2515  CheckScriptSuccess(lines)
2516enddef
2517
2518def Fibonacci(n: number): number
2519  if n < 2
2520    return n
2521  else
2522    return Fibonacci(n - 1) + Fibonacci(n - 2)
2523  endif
2524enddef
2525
2526def Test_recursive_call()
2527  Fibonacci(20)->assert_equal(6765)
2528enddef
2529
2530def TreeWalk(dir: string): list<any>
2531  return readdir(dir)->mapnew((_, val) =>
2532            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2533               ? {[val]: TreeWalk(dir .. '/' .. val)}
2534               : val
2535             )
2536enddef
2537
2538def Test_closure_in_map()
2539  mkdir('XclosureDir/tdir', 'p')
2540  writefile(['111'], 'XclosureDir/file1')
2541  writefile(['222'], 'XclosureDir/file2')
2542  writefile(['333'], 'XclosureDir/tdir/file3')
2543
2544  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2545
2546  delete('XclosureDir', 'rf')
2547enddef
2548
2549def Test_invalid_function_name()
2550  var lines =<< trim END
2551      vim9script
2552      def s: list<string>
2553  END
2554  CheckScriptFailure(lines, 'E129:')
2555
2556  lines =<< trim END
2557      vim9script
2558      def g: list<string>
2559  END
2560  CheckScriptFailure(lines, 'E129:')
2561
2562  lines =<< trim END
2563      vim9script
2564      def <SID>: list<string>
2565  END
2566  CheckScriptFailure(lines, 'E884:')
2567
2568  lines =<< trim END
2569      vim9script
2570      def F list<string>
2571  END
2572  CheckScriptFailure(lines, 'E488:')
2573enddef
2574
2575def Test_partial_call()
2576  var Xsetlist = function('setloclist', [0])
2577  Xsetlist([], ' ', {title: 'test'})
2578  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2579
2580  Xsetlist = function('setloclist', [0, [], ' '])
2581  Xsetlist({title: 'test'})
2582  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2583
2584  Xsetlist = function('setqflist')
2585  Xsetlist([], ' ', {title: 'test'})
2586  getqflist({title: 1})->assert_equal({title: 'test'})
2587
2588  Xsetlist = function('setqflist', [[], ' '])
2589  Xsetlist({title: 'test'})
2590  getqflist({title: 1})->assert_equal({title: 'test'})
2591
2592  var Len: func: number = function('len', ['word'])
2593  assert_equal(4, Len())
2594enddef
2595
2596def Test_cmd_modifier()
2597  tab echo '0'
2598  CheckDefFailure(['5tab echo 3'], 'E16:')
2599enddef
2600
2601def Test_restore_modifiers()
2602  # check that when compiling a :def function command modifiers are not messed
2603  # up.
2604  var lines =<< trim END
2605      vim9script
2606      set eventignore=
2607      autocmd QuickFixCmdPost * copen
2608      def AutocmdsDisabled()
2609        eval 1 + 2
2610      enddef
2611      func Func()
2612        noautocmd call s:AutocmdsDisabled()
2613        let g:ei_after = &eventignore
2614      endfunc
2615      Func()
2616  END
2617  CheckScriptSuccess(lines)
2618  g:ei_after->assert_equal('')
2619enddef
2620
2621def StackTop()
2622  eval 1 + 2
2623  eval 2 + 3
2624  # call not on fourth line
2625  StackBot()
2626enddef
2627
2628def StackBot()
2629  # throw an error
2630  eval [][0]
2631enddef
2632
2633def Test_callstack_def()
2634  try
2635    StackTop()
2636  catch
2637    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2638  endtry
2639enddef
2640
2641" Re-using spot for variable used in block
2642def Test_block_scoped_var()
2643  var lines =<< trim END
2644      vim9script
2645      def Func()
2646        var x = ['a', 'b', 'c']
2647        if 1
2648          var y = 'x'
2649          map(x, (_, _) => y)
2650        endif
2651        var z = x
2652        assert_equal(['x', 'x', 'x'], z)
2653      enddef
2654      Func()
2655  END
2656  CheckScriptSuccess(lines)
2657enddef
2658
2659def Test_reset_did_emsg()
2660  var lines =<< trim END
2661      @s = 'blah'
2662      au BufWinLeave * #
2663      def Func()
2664        var winid = popup_create('popup', {})
2665        exe '*s'
2666        popup_close(winid)
2667      enddef
2668      Func()
2669  END
2670  CheckScriptFailure(lines, 'E492:', 8)
2671  delfunc! g:Func
2672enddef
2673
2674def Test_did_emsg_reset()
2675  # executing an autocommand resets did_emsg, this should not result in a
2676  # builtin function considered failing
2677  var lines =<< trim END
2678      vim9script
2679      au BufWinLeave * #
2680      def Func()
2681          popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()})
2682          eval [][0]
2683      enddef
2684      nno <F3> <cmd>call <sid>Func()<cr>
2685      feedkeys("\<F3>\e", 'xt')
2686  END
2687  writefile(lines, 'XemsgReset')
2688  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2689  delete('XemsgReset')
2690  nunmap <F3>
2691  au! BufWinLeave
2692enddef
2693
2694def Test_abort_with_silent_call()
2695  var lines =<< trim END
2696      vim9script
2697      g:result = 'none'
2698      def Func()
2699        g:result += 3
2700        g:result = 'yes'
2701      enddef
2702      # error is silenced, but function aborts on error
2703      silent! Func()
2704      assert_equal('none', g:result)
2705      unlet g:result
2706  END
2707  CheckScriptSuccess(lines)
2708enddef
2709
2710def Test_continues_with_silent_error()
2711  var lines =<< trim END
2712      vim9script
2713      g:result = 'none'
2714      def Func()
2715        silent!  g:result += 3
2716        g:result = 'yes'
2717      enddef
2718      # error is silenced, function does not abort
2719      Func()
2720      assert_equal('yes', g:result)
2721      unlet g:result
2722  END
2723  CheckScriptSuccess(lines)
2724enddef
2725
2726def Test_abort_even_with_silent()
2727  var lines =<< trim END
2728      vim9script
2729      g:result = 'none'
2730      def Func()
2731        eval {-> ''}() .. '' .. {}['X']
2732        g:result = 'yes'
2733      enddef
2734      silent! Func()
2735      assert_equal('none', g:result)
2736      unlet g:result
2737  END
2738  CheckScriptSuccess(lines)
2739enddef
2740
2741def Test_cmdmod_silent_restored()
2742  var lines =<< trim END
2743      vim9script
2744      def Func()
2745        g:result = 'none'
2746        silent! g:result += 3
2747        g:result = 'none'
2748        g:result += 3
2749      enddef
2750      Func()
2751  END
2752  # can't use CheckScriptFailure, it ignores the :silent!
2753  var fname = 'Xdefsilent'
2754  writefile(lines, fname)
2755  var caught = 'no'
2756  try
2757    exe 'source ' .. fname
2758  catch /E1030:/
2759    caught = 'yes'
2760    assert_match('Func, line 4', v:throwpoint)
2761  endtry
2762  assert_equal('yes', caught)
2763  delete(fname)
2764enddef
2765
2766def Test_cmdmod_silent_nested()
2767  var lines =<< trim END
2768      vim9script
2769      var result = ''
2770
2771      def Error()
2772          result ..= 'Eb'
2773          eval [][0]
2774          result ..= 'Ea'
2775      enddef
2776
2777      def Crash()
2778          result ..= 'Cb'
2779          sil! Error()
2780          result ..= 'Ca'
2781      enddef
2782
2783      Crash()
2784      assert_equal('CbEbEaCa', result)
2785  END
2786  CheckScriptSuccess(lines)
2787enddef
2788
2789def Test_dict_member_with_silent()
2790  var lines =<< trim END
2791      vim9script
2792      g:result = 'none'
2793      var d: dict<any>
2794      def Func()
2795        try
2796          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2797        catch
2798        endtry
2799      enddef
2800      silent! Func()
2801      assert_equal('0', g:result)
2802      unlet g:result
2803  END
2804  CheckScriptSuccess(lines)
2805enddef
2806
2807def Test_skip_cmds_with_silent()
2808  var lines =<< trim END
2809      vim9script
2810
2811      def Func(b: bool)
2812        Crash()
2813      enddef
2814
2815      def Crash()
2816        sil! :/not found/d _
2817        sil! :/not found/put _
2818      enddef
2819
2820      Func(true)
2821  END
2822  CheckScriptSuccess(lines)
2823enddef
2824
2825def Test_opfunc()
2826  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2827  def g:Opfunc(_: any): string
2828    setline(1, 'ASDF')
2829    return ''
2830  enddef
2831  new
2832  setline(1, 'asdf')
2833  feedkeys("\<F3>$", 'x')
2834  assert_equal('ASDF', getline(1))
2835
2836  bwipe!
2837  nunmap <F3>
2838enddef
2839
2840" this was crashing on exit
2841def Test_nested_lambda_in_closure()
2842  var lines =<< trim END
2843      vim9script
2844      command WriteDone writefile(['Done'], 'XnestedDone')
2845      def Outer()
2846          def g:Inner()
2847              echo map([1, 2, 3], {_, v -> v + 1})
2848          enddef
2849          g:Inner()
2850      enddef
2851      defcompile
2852      # not reached
2853  END
2854  if !RunVim([], lines, '--clean -c WriteDone -c quit')
2855    return
2856  endif
2857  assert_equal(['Done'], readfile('XnestedDone'))
2858  delete('XnestedDone')
2859enddef
2860
2861def Test_check_func_arg_types()
2862  var lines =<< trim END
2863      vim9script
2864      def F1(x: string): string
2865        return x
2866      enddef
2867
2868      def F2(x: number): number
2869        return x + 1
2870      enddef
2871
2872      def G(g: func): dict<func>
2873        return {f: g}
2874      enddef
2875
2876      def H(d: dict<func>): string
2877        return d.f('a')
2878      enddef
2879  END
2880
2881  CheckScriptSuccess(lines + ['echo H(G(F1))'])
2882  CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
2883enddef
2884
2885def Test_compile_error()
2886  var lines =<< trim END
2887    def g:Broken()
2888      echo 'a' + {}
2889    enddef
2890    call g:Broken()
2891  END
2892  # First call: compilation error
2893  CheckScriptFailure(lines, 'E1051: Wrong argument type for +')
2894
2895  # Second call won't try compiling again
2896  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2897  delfunc g:Broken
2898
2899  # No error when compiling with :silent!
2900  lines =<< trim END
2901    def g:Broken()
2902      echo 'a' + []
2903    enddef
2904    silent! defcompile
2905  END
2906  CheckScriptSuccess(lines)
2907
2908  # Calling the function won't try compiling again
2909  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2910  delfunc g:Broken
2911enddef
2912
2913def Test_ignored_argument()
2914  var lines =<< trim END
2915      vim9script
2916      def Ignore(_, _): string
2917        return 'yes'
2918      enddef
2919      assert_equal('yes', Ignore(1, 2))
2920
2921      func Ok(_)
2922        return a:_
2923      endfunc
2924      assert_equal('ok', Ok('ok'))
2925
2926      func Oktoo()
2927        let _ = 'too'
2928        return _
2929      endfunc
2930      assert_equal('too', Oktoo())
2931
2932      assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1)))
2933  END
2934  CheckScriptSuccess(lines)
2935
2936  lines =<< trim END
2937      def Ignore(_: string): string
2938        return _
2939      enddef
2940      defcompile
2941  END
2942  CheckScriptFailure(lines, 'E1181:', 1)
2943
2944  lines =<< trim END
2945      var _ = 1
2946  END
2947  CheckDefAndScriptFailure(lines, 'E1181:', 1)
2948
2949  lines =<< trim END
2950      var x = _
2951  END
2952  CheckDefAndScriptFailure(lines, 'E1181:', 1)
2953enddef
2954
2955def Test_too_many_arguments()
2956  var lines =<< trim END
2957    echo [0, 1, 2]->map(() => 123)
2958  END
2959  CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1)
2960
2961  lines =<< trim END
2962    echo [0, 1, 2]->map((_) => 123)
2963  END
2964  CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1)
2965enddef
2966
2967def Test_closing_brace_at_start_of_line()
2968  var lines =<< trim END
2969      def Func()
2970      enddef
2971      Func(
2972      )
2973  END
2974  call CheckDefAndScriptSuccess(lines)
2975enddef
2976
2977if has('python3')
2978  def Test_python3_heredoc()
2979    py3 << trim EOF
2980      import vim
2981      vim.vars['didit'] = 'yes'
2982    EOF
2983    assert_equal('yes', g:didit)
2984
2985    python3 << trim EOF
2986      import vim
2987      vim.vars['didit'] = 'again'
2988    EOF
2989    assert_equal('again', g:didit)
2990  enddef
2991endif
2992
2993" This messes up syntax highlight, keep near the end.
2994if has('lua')
2995  def Test_lua_heredoc()
2996    g:d = {}
2997    lua << trim EOF
2998        x = vim.eval('g:d')
2999        x['key'] = 'val'
3000    EOF
3001    assert_equal('val', g:d.key)
3002  enddef
3003endif
3004
3005
3006" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
3007