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()
21endfunc
22
23def TestCompilingError()
24  var lines =<< trim END
25    vim9script
26    def Fails()
27      echo nothing
28    enddef
29    defcompile
30  END
31  call writefile(lines, 'XTest_compile_error')
32  var buf = RunVimInTerminal('-S XTest_compile_error',
33              {rows: 10, wait_for_ruler: 0})
34  var text = ''
35  for loop in range(100)
36    text = ''
37    for i in range(1, 9)
38      text ..= term_getline(buf, i)
39    endfor
40    if text =~ 'Variable not found: nothing'
41      break
42    endif
43    sleep 20m
44  endfor
45  assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing', text)
46
47  # clean up
48  call StopVimInTerminal(buf)
49  call delete('XTest_compile_error')
50enddef
51
52def CallRecursive(n: number): number
53  return CallRecursive(n + 1)
54enddef
55
56def CallMapRecursive(l: list<number>): number
57  return map(l, (_, v) => CallMapRecursive([v]))[0]
58enddef
59
60def Test_funcdepth_error()
61  set maxfuncdepth=10
62
63  var caught = false
64  try
65    CallRecursive(1)
66  catch /E132:/
67    caught = true
68  endtry
69  assert_true(caught)
70
71  caught = false
72  try
73    CallMapRecursive([1])
74  catch /E132:/
75    caught = true
76  endtry
77  assert_true(caught)
78
79  set maxfuncdepth&
80enddef
81
82def Test_endfunc_enddef()
83  var lines =<< trim END
84    def Test()
85      echo 'test'
86      endfunc
87    enddef
88  END
89  CheckScriptFailure(lines, 'E1151:', 3)
90
91  lines =<< trim END
92    def Test()
93      func Nested()
94        echo 'test'
95      enddef
96    enddef
97  END
98  CheckScriptFailure(lines, 'E1152:', 4)
99enddef
100
101def Test_missing_endfunc_enddef()
102  var lines =<< trim END
103    vim9script
104    def Test()
105      echo 'test'
106    endef
107  END
108  CheckScriptFailure(lines, 'E1057:', 2)
109
110  lines =<< trim END
111    vim9script
112    func Some()
113      echo 'test'
114    enfffunc
115  END
116  CheckScriptFailure(lines, 'E126:', 2)
117enddef
118
119def Test_white_space_before_paren()
120  var lines =<< trim END
121    vim9script
122    def Test ()
123      echo 'test'
124    enddef
125  END
126  CheckScriptFailure(lines, 'E1068:', 2)
127
128  lines =<< trim END
129    vim9script
130    func Test ()
131      echo 'test'
132    endfunc
133  END
134  CheckScriptFailure(lines, 'E1068:', 2)
135
136  lines =<< trim END
137    def Test ()
138      echo 'test'
139    enddef
140  END
141  CheckScriptFailure(lines, 'E1068:', 1)
142
143  lines =<< trim END
144    func Test ()
145      echo 'test'
146    endfunc
147  END
148  CheckScriptSuccess(lines)
149enddef
150
151def Test_enddef_dict_key()
152  var d = {
153    enddef: 'x',
154    endfunc: 'y',
155  }
156  assert_equal({enddef: 'x', endfunc: 'y'}, d)
157enddef
158
159def ReturnString(): string
160  return 'string'
161enddef
162
163def ReturnNumber(): number
164  return 123
165enddef
166
167let g:notNumber = 'string'
168
169def ReturnGlobal(): number
170  return g:notNumber
171enddef
172
173def Test_return_something()
174  ReturnString()->assert_equal('string')
175  ReturnNumber()->assert_equal(123)
176  assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal')
177enddef
178
179def Test_check_argument_type()
180  var lines =<< trim END
181      vim9script
182      def Val(a: number, b: number): number
183        return 0
184      enddef
185      def Func()
186        var x: any = true
187        Val(0, x)
188      enddef
189      disass Func
190      Func()
191  END
192  CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got bool', 2)
193enddef
194
195def Test_missing_return()
196  CheckDefFailure(['def Missing(): number',
197                   '  if g:cond',
198                   '    echo "no return"',
199                   '  else',
200                   '    return 0',
201                   '  endif'
202                   'enddef'], 'E1027:')
203  CheckDefFailure(['def Missing(): number',
204                   '  if g:cond',
205                   '    return 1',
206                   '  else',
207                   '    echo "no return"',
208                   '  endif'
209                   'enddef'], 'E1027:')
210  CheckDefFailure(['def Missing(): number',
211                   '  if g:cond',
212                   '    return 1',
213                   '  else',
214                   '    return 2',
215                   '  endif'
216                   '  return 3'
217                   'enddef'], 'E1095:')
218enddef
219
220def Test_return_bool()
221  var lines =<< trim END
222      vim9script
223      def MenuFilter(id: number, key: string): bool
224        return popup_filter_menu(id, key)
225      enddef
226      def YesnoFilter(id: number, key: string): bool
227        return popup_filter_yesno(id, key)
228      enddef
229      defcompile
230  END
231  CheckScriptSuccess(lines)
232enddef
233
234let s:nothing = 0
235def ReturnNothing()
236  s:nothing = 1
237  if true
238    return
239  endif
240  s:nothing = 2
241enddef
242
243def Test_return_nothing()
244  ReturnNothing()
245  s:nothing->assert_equal(1)
246enddef
247
248def Test_return_invalid()
249  var lines =<< trim END
250    vim9script
251    def Func(): invalid
252      return xxx
253    enddef
254    defcompile
255  END
256  CheckScriptFailure(lines, 'E1010:', 2)
257enddef
258
259func Increment()
260  let g:counter += 1
261endfunc
262
263def Test_call_ufunc_count()
264  g:counter = 1
265  Increment()
266  Increment()
267  Increment()
268  # works with and without :call
269  g:counter->assert_equal(4)
270  eval g:counter->assert_equal(4)
271  unlet g:counter
272enddef
273
274def MyVarargs(arg: string, ...rest: list<string>): string
275  var res = arg
276  for s in rest
277    res ..= ',' .. s
278  endfor
279  return res
280enddef
281
282def Test_call_varargs()
283  MyVarargs('one')->assert_equal('one')
284  MyVarargs('one', 'two')->assert_equal('one,two')
285  MyVarargs('one', 'two', 'three')->assert_equal('one,two,three')
286enddef
287
288def MyDefaultArgs(name = 'string'): string
289  return name
290enddef
291
292def MyDefaultSecond(name: string, second: bool  = true): string
293  return second ? name : 'none'
294enddef
295
296def Test_call_default_args()
297  MyDefaultArgs()->assert_equal('string')
298  MyDefaultArgs('one')->assert_equal('one')
299  assert_fails('MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args')
300
301  MyDefaultSecond('test')->assert_equal('test')
302  MyDefaultSecond('test', true)->assert_equal('test')
303  MyDefaultSecond('test', false)->assert_equal('none')
304
305  CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:')
306  delfunc g:Func
307  CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: Argument 1: type mismatch, expected number but got string')
308  delfunc g:Func
309enddef
310
311def FuncWithComment(  # comment
312  a: number, #comment
313  b: bool, # comment
314  c: string) #comment
315  assert_equal(4, a)
316  assert_equal(true, b)
317  assert_equal('yes', c)
318enddef
319
320def Test_func_with_comments()
321  FuncWithComment(4, true, 'yes')
322
323  var lines =<< trim END
324      def Func(# comment
325        arg: string)
326      enddef
327  END
328  CheckScriptFailure(lines, 'E125:', 1)
329
330  lines =<< trim END
331      def Func(
332        arg: string# comment
333        )
334      enddef
335  END
336  CheckScriptFailure(lines, 'E475:', 2)
337
338  lines =<< trim END
339      def Func(
340        arg: string
341        )# comment
342      enddef
343  END
344  CheckScriptFailure(lines, 'E488:', 3)
345enddef
346
347def Test_nested_function()
348  def Nested(arg: string): string
349    return 'nested ' .. arg
350  enddef
351  Nested('function')->assert_equal('nested function')
352
353  CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
354  CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
355
356  CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
357  CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
358  CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
359
360  var lines =<< trim END
361      def Outer()
362        def Inner()
363          # comment
364        enddef
365        def Inner()
366        enddef
367      enddef
368  END
369  CheckDefFailure(lines, 'E1073:')
370
371  lines =<< trim END
372      def Outer()
373        def Inner()
374          # comment
375        enddef
376        def! Inner()
377        enddef
378      enddef
379  END
380  CheckDefFailure(lines, 'E1117:')
381
382  # nested function inside conditional
383  # TODO: should it work when "thecount" is inside the "if"?
384  lines =<< trim END
385      vim9script
386      var thecount = 0
387      if true
388        def Test(): number
389          def TheFunc(): number
390            thecount += 1
391            return thecount
392          enddef
393          return TheFunc()
394        enddef
395      endif
396      defcompile
397      assert_equal(1, Test())
398      assert_equal(2, Test())
399  END
400  CheckScriptSuccess(lines)
401enddef
402
403def Test_not_nested_function()
404  echo printf('%d',
405      function('len')('xxx'))
406enddef
407
408func Test_call_default_args_from_func()
409  call MyDefaultArgs()->assert_equal('string')
410  call MyDefaultArgs('one')->assert_equal('one')
411  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args_from_func')
412endfunc
413
414def Test_nested_global_function()
415  var lines =<< trim END
416      vim9script
417      def Outer()
418          def g:Inner(): string
419              return 'inner'
420          enddef
421      enddef
422      defcompile
423      Outer()
424      g:Inner()->assert_equal('inner')
425      delfunc g:Inner
426      Outer()
427      g:Inner()->assert_equal('inner')
428      delfunc g:Inner
429      Outer()
430      g:Inner()->assert_equal('inner')
431      delfunc g:Inner
432  END
433  CheckScriptSuccess(lines)
434
435  lines =<< trim END
436      vim9script
437      def Outer()
438          def g:Inner(): string
439              return 'inner'
440          enddef
441      enddef
442      defcompile
443      Outer()
444      Outer()
445  END
446  CheckScriptFailure(lines, "E122:")
447  delfunc g:Inner
448
449  lines =<< trim END
450      vim9script
451      def Outer()
452        def g:Inner()
453          echo map([1, 2, 3], (_, v) => v + 1)
454        enddef
455        g:Inner()
456      enddef
457      Outer()
458  END
459  CheckScriptSuccess(lines)
460  delfunc g:Inner
461
462  lines =<< trim END
463      vim9script
464      def Func()
465        echo 'script'
466      enddef
467      def Outer()
468        def Func()
469          echo 'inner'
470        enddef
471      enddef
472      defcompile
473  END
474  CheckScriptFailure(lines, "E1073:")
475enddef
476
477def DefListAll()
478  def
479enddef
480
481def DefListOne()
482  def DefListOne
483enddef
484
485def DefListMatches()
486  def /DefList
487enddef
488
489def Test_nested_def_list()
490  var funcs = split(execute('call DefListAll()'), "\n")
491  assert_true(len(funcs) > 10)
492  assert_true(funcs->index('def DefListAll()') >= 0)
493
494  funcs = split(execute('call DefListOne()'), "\n")
495  assert_equal(['   def DefListOne()', '1    def DefListOne', '   enddef'], funcs)
496
497  funcs = split(execute('call DefListMatches()'), "\n")
498  assert_true(len(funcs) >= 3)
499  assert_true(funcs->index('def DefListAll()') >= 0)
500  assert_true(funcs->index('def DefListOne()') >= 0)
501  assert_true(funcs->index('def DefListMatches()') >= 0)
502
503  var lines =<< trim END
504    vim9script
505    def Func()
506      def +Func+
507    enddef
508    defcompile
509  END
510  CheckScriptFailure(lines, 'E476:', 1)
511enddef
512
513def Test_global_local_function()
514  var lines =<< trim END
515      vim9script
516      def g:Func(): string
517          return 'global'
518      enddef
519      def Func(): string
520          return 'local'
521      enddef
522      g:Func()->assert_equal('global')
523      Func()->assert_equal('local')
524      delfunc g:Func
525  END
526  CheckScriptSuccess(lines)
527
528  lines =<< trim END
529      vim9script
530      def g:Funcy()
531        echo 'funcy'
532      enddef
533      s:Funcy()
534  END
535  CheckScriptFailure(lines, 'E117:')
536enddef
537
538def Test_local_function_shadows_global()
539  var lines =<< trim END
540      vim9script
541      def g:Gfunc(): string
542        return 'global'
543      enddef
544      def AnotherFunc(): number
545        var Gfunc = function('len')
546        return Gfunc('testing')
547      enddef
548      g:Gfunc()->assert_equal('global')
549      AnotherFunc()->assert_equal(7)
550      delfunc g:Gfunc
551  END
552  CheckScriptSuccess(lines)
553
554  lines =<< trim END
555      vim9script
556      def g:Func(): string
557        return 'global'
558      enddef
559      def AnotherFunc()
560        g:Func = function('len')
561      enddef
562      AnotherFunc()
563  END
564  CheckScriptFailure(lines, 'E705:')
565  delfunc g:Func
566enddef
567
568func TakesOneArg(arg)
569  echo a:arg
570endfunc
571
572def Test_call_wrong_args()
573  CheckDefFailure(['TakesOneArg()'], 'E119:')
574  CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
575  CheckDefFailure(['bufnr(xxx)'], 'E1001:')
576  CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:')
577
578  var lines =<< trim END
579    vim9script
580    def Func(s: string)
581      echo s
582    enddef
583    Func([])
584  END
585  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 5)
586
587  lines =<< trim END
588    vim9script
589    def FuncOne(nr: number)
590      echo nr
591    enddef
592    def FuncTwo()
593      FuncOne()
594    enddef
595    defcompile
596  END
597  writefile(lines, 'Xscript')
598  var didCatch = false
599  try
600    source Xscript
601  catch
602    assert_match('E119: Not enough arguments for function: <SNR>\d\+_FuncOne', v:exception)
603    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
604    didCatch = true
605  endtry
606  assert_true(didCatch)
607
608  lines =<< trim END
609    vim9script
610    def FuncOne(nr: number)
611      echo nr
612    enddef
613    def FuncTwo()
614      FuncOne(1, 2)
615    enddef
616    defcompile
617  END
618  writefile(lines, 'Xscript')
619  didCatch = false
620  try
621    source Xscript
622  catch
623    assert_match('E118: Too many arguments for function: <SNR>\d\+_FuncOne', v:exception)
624    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
625    didCatch = true
626  endtry
627  assert_true(didCatch)
628
629  delete('Xscript')
630enddef
631
632def Test_call_funcref_wrong_args()
633  var head =<< trim END
634      vim9script
635      def Func3(a1: string, a2: number, a3: list<number>)
636        echo a1 .. a2 .. a3[0]
637      enddef
638      def Testme()
639        var funcMap: dict<func> = {func: Func3}
640  END
641  var tail =<< trim END
642      enddef
643      Testme()
644  END
645  CheckScriptSuccess(head + ["funcMap['func']('str', 123, [1, 2, 3])"] + tail)
646
647  CheckScriptFailure(head + ["funcMap['func']('str', 123)"] + tail, 'E119:')
648  CheckScriptFailure(head + ["funcMap['func']('str', 123, [1], 4)"] + tail, 'E118:')
649
650  var lines =<< trim END
651      vim9script
652      var Ref: func(number): any
653      Ref = (j) => !j
654      echo Ref(false)
655  END
656  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4)
657
658  lines =<< trim END
659      vim9script
660      var Ref: func(number): any
661      Ref = (j) => !j
662      call Ref(false)
663  END
664  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4)
665enddef
666
667def Test_call_lambda_args()
668  CheckDefFailure(['echo ((i) => 0)()'],
669                  'E119: Not enough arguments for function: ((i) => 0)()')
670
671  var lines =<< trim END
672      var Ref = (x: number, y: number) => x + y
673      echo Ref(1, 'x')
674  END
675  CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string')
676
677  lines =<< trim END
678    var Ref: func(job, string, number)
679    Ref = (x, y) => 0
680  END
681  CheckDefAndScriptFailure(lines, 'E1012:')
682
683  lines =<< trim END
684    var Ref: func(job, string)
685    Ref = (x, y, z) => 0
686  END
687  CheckDefAndScriptFailure(lines, 'E1012:')
688enddef
689
690def Test_lambda_return_type()
691  var lines =<< trim END
692    var Ref = (): => 123
693  END
694  CheckDefAndScriptFailure(lines, 'E1157:', 1)
695enddef
696
697def Test_lambda_uses_assigned_var()
698  CheckDefSuccess([
699        'var x: any = "aaa"'
700        'x = filter(["bbb"], (_, v) => v =~ x)'])
701enddef
702
703" Default arg and varargs
704def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
705  var res = one .. ',' .. two
706  for s in rest
707    res ..= ',' .. s
708  endfor
709  return res
710enddef
711
712def Test_call_def_varargs()
713  assert_fails('MyDefVarargs()', 'E119:', '', 1, 'Test_call_def_varargs')
714  MyDefVarargs('one')->assert_equal('one,foo')
715  MyDefVarargs('one', 'two')->assert_equal('one,two')
716  MyDefVarargs('one', 'two', 'three')->assert_equal('one,two,three')
717  CheckDefFailure(['MyDefVarargs("one", 22)'],
718      'E1013: Argument 2: type mismatch, expected string but got number')
719  CheckDefFailure(['MyDefVarargs("one", "two", 123)'],
720      'E1013: Argument 3: type mismatch, expected string but got number')
721
722  var lines =<< trim END
723      vim9script
724      def Func(...l: list<string>)
725        echo l
726      enddef
727      Func('a', 'b', 'c')
728  END
729  CheckScriptSuccess(lines)
730
731  lines =<< trim END
732      vim9script
733      def Func(...l: list<string>)
734        echo l
735      enddef
736      Func()
737  END
738  CheckScriptSuccess(lines)
739
740  lines =<< trim END
741      vim9script
742      def Func(...l: any)
743        echo l
744      enddef
745      Func(0)
746  END
747  CheckScriptSuccess(lines)
748
749  lines =<< trim END
750      vim9script
751      def Func(..._l: list<string>)
752        echo _l
753      enddef
754      Func('a', 'b', 'c')
755  END
756  CheckScriptSuccess(lines)
757
758  lines =<< trim END
759      vim9script
760      def Func(...l: list<string>)
761        echo l
762      enddef
763      Func(1, 2, 3)
764  END
765  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
766
767  lines =<< trim END
768      vim9script
769      def Func(...l: list<string>)
770        echo l
771      enddef
772      Func('a', 9)
773  END
774  CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch')
775
776  lines =<< trim END
777      vim9script
778      def Func(...l: list<string>)
779        echo l
780      enddef
781      Func(1, 'a')
782  END
783  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
784
785  lines =<< trim END
786      vim9script
787      def Func(  # some comment
788                ...l = []
789                )
790        echo l
791      enddef
792  END
793  CheckScriptFailure(lines, 'E1160:')
794enddef
795
796let s:value = ''
797
798def FuncOneDefArg(opt = 'text')
799  s:value = opt
800enddef
801
802def FuncTwoDefArg(nr = 123, opt = 'text'): string
803  return nr .. opt
804enddef
805
806def FuncVarargs(...arg: list<string>): string
807  return join(arg, ',')
808enddef
809
810def Test_func_type_varargs()
811  var RefDefArg: func(?string)
812  RefDefArg = FuncOneDefArg
813  RefDefArg()
814  s:value->assert_equal('text')
815  RefDefArg('some')
816  s:value->assert_equal('some')
817
818  var RefDef2Arg: func(?number, ?string): string
819  RefDef2Arg = FuncTwoDefArg
820  RefDef2Arg()->assert_equal('123text')
821  RefDef2Arg(99)->assert_equal('99text')
822  RefDef2Arg(77, 'some')->assert_equal('77some')
823
824  CheckDefFailure(['var RefWrong: func(string?)'], 'E1010:')
825  CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:')
826
827  var RefVarargs: func(...list<string>): string
828  RefVarargs = FuncVarargs
829  RefVarargs()->assert_equal('')
830  RefVarargs('one')->assert_equal('one')
831  RefVarargs('one', 'two')->assert_equal('one,two')
832
833  CheckDefFailure(['var RefWrong: func(...list<string>, string)'], 'E110:')
834  CheckDefFailure(['var RefWrong: func(...list<string>, ?string)'], 'E110:')
835enddef
836
837" Only varargs
838def MyVarargsOnly(...args: list<string>): string
839  return join(args, ',')
840enddef
841
842def Test_call_varargs_only()
843  MyVarargsOnly()->assert_equal('')
844  MyVarargsOnly('one')->assert_equal('one')
845  MyVarargsOnly('one', 'two')->assert_equal('one,two')
846  CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: Argument 1: type mismatch, expected string but got number')
847  CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number')
848enddef
849
850def Test_using_var_as_arg()
851  writefile(['def Func(x: number)',  'var x = 234', 'enddef', 'defcompile'], 'Xdef')
852  assert_fails('so Xdef', 'E1006:', '', 1, 'Func')
853  delete('Xdef')
854enddef
855
856def DictArg(arg: dict<string>)
857  arg['key'] = 'value'
858enddef
859
860def ListArg(arg: list<string>)
861  arg[0] = 'value'
862enddef
863
864def Test_assign_to_argument()
865  # works for dict and list
866  var d: dict<string> = {}
867  DictArg(d)
868  d['key']->assert_equal('value')
869  var l: list<string> = []
870  ListArg(l)
871  l[0]->assert_equal('value')
872
873  CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:')
874  delfunc! g:Func
875enddef
876
877" These argument names are reserved in legacy functions.
878def WithReservedNames(firstline: string, lastline: string): string
879  return firstline .. lastline
880enddef
881
882def Test_argument_names()
883  assert_equal('OK', WithReservedNames('O', 'K'))
884enddef
885
886def Test_call_func_defined_later()
887  g:DefinedLater('one')->assert_equal('one')
888  assert_fails('NotDefined("one")', 'E117:', '', 2, 'Test_call_func_defined_later')
889enddef
890
891func DefinedLater(arg)
892  return a:arg
893endfunc
894
895def Test_call_funcref()
896  g:SomeFunc('abc')->assert_equal(3)
897  assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call
898  assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref')
899
900  var lines =<< trim END
901    vim9script
902    def RetNumber(): number
903      return 123
904    enddef
905    var Funcref: func: number = function('RetNumber')
906    Funcref()->assert_equal(123)
907  END
908  CheckScriptSuccess(lines)
909
910  lines =<< trim END
911    vim9script
912    def RetNumber(): number
913      return 123
914    enddef
915    def Bar(F: func: number): number
916      return F()
917    enddef
918    var Funcref = function('RetNumber')
919    Bar(Funcref)->assert_equal(123)
920  END
921  CheckScriptSuccess(lines)
922
923  lines =<< trim END
924    vim9script
925    def UseNumber(nr: number)
926      echo nr
927    enddef
928    var Funcref: func(number) = function('UseNumber')
929    Funcref(123)
930  END
931  CheckScriptSuccess(lines)
932
933  lines =<< trim END
934    vim9script
935    def UseNumber(nr: number)
936      echo nr
937    enddef
938    var Funcref: func(string) = function('UseNumber')
939  END
940  CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)')
941
942  lines =<< trim END
943    vim9script
944    def EchoNr(nr = 34)
945      g:echo = nr
946    enddef
947    var Funcref: func(?number) = function('EchoNr')
948    Funcref()
949    g:echo->assert_equal(34)
950    Funcref(123)
951    g:echo->assert_equal(123)
952  END
953  CheckScriptSuccess(lines)
954
955  lines =<< trim END
956    vim9script
957    def EchoList(...l: list<number>)
958      g:echo = l
959    enddef
960    var Funcref: func(...list<number>) = function('EchoList')
961    Funcref()
962    g:echo->assert_equal([])
963    Funcref(1, 2, 3)
964    g:echo->assert_equal([1, 2, 3])
965  END
966  CheckScriptSuccess(lines)
967
968  lines =<< trim END
969    vim9script
970    def OptAndVar(nr: number, opt = 12, ...l: list<number>): number
971      g:optarg = opt
972      g:listarg = l
973      return nr
974    enddef
975    var Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar')
976    Funcref(10)->assert_equal(10)
977    g:optarg->assert_equal(12)
978    g:listarg->assert_equal([])
979
980    Funcref(11, 22)->assert_equal(11)
981    g:optarg->assert_equal(22)
982    g:listarg->assert_equal([])
983
984    Funcref(17, 18, 1, 2, 3)->assert_equal(17)
985    g:optarg->assert_equal(18)
986    g:listarg->assert_equal([1, 2, 3])
987  END
988  CheckScriptSuccess(lines)
989enddef
990
991let SomeFunc = function('len')
992let NotAFunc = 'text'
993
994def CombineFuncrefTypes()
995  # same arguments, different return type
996  var Ref1: func(bool): string
997  var Ref2: func(bool): number
998  var Ref3: func(bool): any
999  Ref3 = g:cond ? Ref1 : Ref2
1000
1001  # different number of arguments
1002  var Refa1: func(bool): number
1003  var Refa2: func(bool, number): number
1004  var Refa3: func: number
1005  Refa3 = g:cond ? Refa1 : Refa2
1006
1007  # different argument types
1008  var Refb1: func(bool, string): number
1009  var Refb2: func(string, number): number
1010  var Refb3: func(any, any): number
1011  Refb3 = g:cond ? Refb1 : Refb2
1012enddef
1013
1014def FuncWithForwardCall()
1015  return g:DefinedEvenLater("yes")
1016enddef
1017
1018def DefinedEvenLater(arg: string): string
1019  return arg
1020enddef
1021
1022def Test_error_in_nested_function()
1023  # Error in called function requires unwinding the call stack.
1024  assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall')
1025enddef
1026
1027def Test_return_type_wrong()
1028  CheckScriptFailure([
1029        'def Func(): number',
1030        'return "a"',
1031        'enddef',
1032        'defcompile'], 'expected number but got string')
1033  delfunc! g:Func
1034  CheckScriptFailure([
1035        'def Func(): string',
1036        'return 1',
1037        'enddef',
1038        'defcompile'], 'expected string but got number')
1039  delfunc! g:Func
1040  CheckScriptFailure([
1041        'def Func(): void',
1042        'return "a"',
1043        'enddef',
1044        'defcompile'],
1045        'E1096: Returning a value in a function without a return type')
1046  delfunc! g:Func
1047  CheckScriptFailure([
1048        'def Func()',
1049        'return "a"',
1050        'enddef',
1051        'defcompile'],
1052        'E1096: Returning a value in a function without a return type')
1053  delfunc! g:Func
1054
1055  CheckScriptFailure([
1056        'def Func(): number',
1057        'return',
1058        'enddef',
1059        'defcompile'], 'E1003:')
1060  delfunc! g:Func
1061
1062  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
1063  delfunc! g:Func
1064  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
1065  delfunc! g:Func
1066  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
1067  delfunc! g:Func
1068
1069  CheckScriptFailure([
1070        'vim9script',
1071        'def FuncB()',
1072        '  return 123',
1073        'enddef',
1074        'def FuncA()',
1075        '   FuncB()',
1076        'enddef',
1077        'defcompile'], 'E1096:')
1078enddef
1079
1080def Test_arg_type_wrong()
1081  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
1082  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
1083  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
1084  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
1085enddef
1086
1087def Test_vim9script_call()
1088  var lines =<< trim END
1089    vim9script
1090    var name = ''
1091    def MyFunc(arg: string)
1092       name = arg
1093    enddef
1094    MyFunc('foobar')
1095    name->assert_equal('foobar')
1096
1097    var str = 'barfoo'
1098    str->MyFunc()
1099    name->assert_equal('barfoo')
1100
1101    g:value = 'value'
1102    g:value->MyFunc()
1103    name->assert_equal('value')
1104
1105    var listvar = []
1106    def ListFunc(arg: list<number>)
1107       listvar = arg
1108    enddef
1109    [1, 2, 3]->ListFunc()
1110    listvar->assert_equal([1, 2, 3])
1111
1112    var dictvar = {}
1113    def DictFunc(arg: dict<number>)
1114       dictvar = arg
1115    enddef
1116    {a: 1, b: 2}->DictFunc()
1117    dictvar->assert_equal({a: 1, b: 2})
1118    def CompiledDict()
1119      {a: 3, b: 4}->DictFunc()
1120    enddef
1121    CompiledDict()
1122    dictvar->assert_equal({a: 3, b: 4})
1123
1124    {a: 3, b: 4}->DictFunc()
1125    dictvar->assert_equal({a: 3, b: 4})
1126
1127    ('text')->MyFunc()
1128    name->assert_equal('text')
1129    ("some")->MyFunc()
1130    name->assert_equal('some')
1131
1132    # line starting with single quote is not a mark
1133    # line starting with double quote can be a method call
1134    'asdfasdf'->MyFunc()
1135    name->assert_equal('asdfasdf')
1136    "xyz"->MyFunc()
1137    name->assert_equal('xyz')
1138
1139    def UseString()
1140      'xyork'->MyFunc()
1141    enddef
1142    UseString()
1143    name->assert_equal('xyork')
1144
1145    def UseString2()
1146      "knife"->MyFunc()
1147    enddef
1148    UseString2()
1149    name->assert_equal('knife')
1150
1151    # prepending a colon makes it a mark
1152    new
1153    setline(1, ['aaa', 'bbb', 'ccc'])
1154    normal! 3Gmt1G
1155    :'t
1156    getcurpos()[1]->assert_equal(3)
1157    bwipe!
1158
1159    MyFunc(
1160        'continued'
1161        )
1162    assert_equal('continued',
1163            name
1164            )
1165
1166    call MyFunc(
1167        'more'
1168          ..
1169          'lines'
1170        )
1171    assert_equal(
1172        'morelines',
1173        name)
1174  END
1175  writefile(lines, 'Xcall.vim')
1176  source Xcall.vim
1177  delete('Xcall.vim')
1178enddef
1179
1180def Test_vim9script_call_fail_decl()
1181  var lines =<< trim END
1182    vim9script
1183    var name = ''
1184    def MyFunc(arg: string)
1185       var name = 123
1186    enddef
1187    defcompile
1188  END
1189  CheckScriptFailure(lines, 'E1054:')
1190enddef
1191
1192def Test_vim9script_call_fail_type()
1193  var lines =<< trim END
1194    vim9script
1195    def MyFunc(arg: string)
1196      echo arg
1197    enddef
1198    MyFunc(1234)
1199  END
1200  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
1201enddef
1202
1203def Test_vim9script_call_fail_const()
1204  var lines =<< trim END
1205    vim9script
1206    const var = ''
1207    def MyFunc(arg: string)
1208       var = 'asdf'
1209    enddef
1210    defcompile
1211  END
1212  writefile(lines, 'Xcall_const.vim')
1213  assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
1214  delete('Xcall_const.vim')
1215
1216  lines =<< trim END
1217      const g:Aconst = 77
1218      def Change()
1219        # comment
1220        g:Aconst = 99
1221      enddef
1222      call Change()
1223      unlet g:Aconst
1224  END
1225  CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2)
1226enddef
1227
1228" Test that inside :function a Python function can be defined, :def is not
1229" recognized.
1230func Test_function_python()
1231  CheckFeature python3
1232  let py = 'python3'
1233  execute py "<< EOF"
1234def do_something():
1235  return 1
1236EOF
1237endfunc
1238
1239def Test_delfunc()
1240  var lines =<< trim END
1241    vim9script
1242    def g:GoneSoon()
1243      echo 'hello'
1244    enddef
1245
1246    def CallGoneSoon()
1247      GoneSoon()
1248    enddef
1249    defcompile
1250
1251    delfunc g:GoneSoon
1252    CallGoneSoon()
1253  END
1254  writefile(lines, 'XToDelFunc')
1255  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1256  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1257
1258  delete('XToDelFunc')
1259enddef
1260
1261def Test_redef_failure()
1262  writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
1263  so Xdef
1264  writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
1265  so Xdef
1266  writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
1267  assert_fails('so Xdef', 'E1027:', '', 1, 'Func0')
1268  writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
1269  so Xdef
1270  delete('Xdef')
1271
1272  g:Func0()->assert_equal(0)
1273  g:Func1()->assert_equal('Func1')
1274  g:Func2()->assert_equal('Func2')
1275
1276  delfunc! Func0
1277  delfunc! Func1
1278  delfunc! Func2
1279enddef
1280
1281def Test_vim9script_func()
1282  var lines =<< trim END
1283    vim9script
1284    func Func(arg)
1285      echo a:arg
1286    endfunc
1287    Func('text')
1288  END
1289  writefile(lines, 'XVim9Func')
1290  so XVim9Func
1291
1292  delete('XVim9Func')
1293enddef
1294
1295let s:funcResult = 0
1296
1297def FuncNoArgNoRet()
1298  s:funcResult = 11
1299enddef
1300
1301def FuncNoArgRetNumber(): number
1302  s:funcResult = 22
1303  return 1234
1304enddef
1305
1306def FuncNoArgRetString(): string
1307  s:funcResult = 45
1308  return 'text'
1309enddef
1310
1311def FuncOneArgNoRet(arg: number)
1312  s:funcResult = arg
1313enddef
1314
1315def FuncOneArgRetNumber(arg: number): number
1316  s:funcResult = arg
1317  return arg
1318enddef
1319
1320def FuncTwoArgNoRet(one: bool, two: number)
1321  s:funcResult = two
1322enddef
1323
1324def FuncOneArgRetString(arg: string): string
1325  return arg
1326enddef
1327
1328def FuncOneArgRetAny(arg: any): any
1329  return arg
1330enddef
1331
1332def Test_func_type()
1333  var Ref1: func()
1334  s:funcResult = 0
1335  Ref1 = FuncNoArgNoRet
1336  Ref1()
1337  s:funcResult->assert_equal(11)
1338
1339  var Ref2: func
1340  s:funcResult = 0
1341  Ref2 = FuncNoArgNoRet
1342  Ref2()
1343  s:funcResult->assert_equal(11)
1344
1345  s:funcResult = 0
1346  Ref2 = FuncOneArgNoRet
1347  Ref2(12)
1348  s:funcResult->assert_equal(12)
1349
1350  s:funcResult = 0
1351  Ref2 = FuncNoArgRetNumber
1352  Ref2()->assert_equal(1234)
1353  s:funcResult->assert_equal(22)
1354
1355  s:funcResult = 0
1356  Ref2 = FuncOneArgRetNumber
1357  Ref2(13)->assert_equal(13)
1358  s:funcResult->assert_equal(13)
1359enddef
1360
1361def Test_repeat_return_type()
1362  var res = 0
1363  for n in repeat([1], 3)
1364    res += n
1365  endfor
1366  res->assert_equal(3)
1367
1368  res = 0
1369  for n in add([1, 2], 3)
1370    res += n
1371  endfor
1372  res->assert_equal(6)
1373enddef
1374
1375def Test_argv_return_type()
1376  next fileone filetwo
1377  var res = ''
1378  for name in argv()
1379    res ..= name
1380  endfor
1381  res->assert_equal('fileonefiletwo')
1382enddef
1383
1384def Test_func_type_part()
1385  var RefVoid: func: void
1386  RefVoid = FuncNoArgNoRet
1387  RefVoid = FuncOneArgNoRet
1388  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
1389  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
1390
1391  var RefAny: func(): any
1392  RefAny = FuncNoArgRetNumber
1393  RefAny = FuncNoArgRetString
1394  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
1395  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
1396
1397  var RefAnyNoArgs: func: any = RefAny
1398
1399  var RefNr: func: number
1400  RefNr = FuncNoArgRetNumber
1401  RefNr = FuncOneArgRetNumber
1402  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1403  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1404
1405  var RefStr: func: string
1406  RefStr = FuncNoArgRetString
1407  RefStr = FuncOneArgRetString
1408  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1409  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1410enddef
1411
1412def Test_func_type_fails()
1413  CheckDefFailure(['var ref1: func()'], 'E704:')
1414
1415  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1416  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1417  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1418  CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1419  CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1420  CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1421
1422  CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
1423  CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
1424  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:')
1425  CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:')
1426enddef
1427
1428def Test_func_return_type()
1429  var nr: number
1430  nr = FuncNoArgRetNumber()
1431  nr->assert_equal(1234)
1432
1433  nr = FuncOneArgRetAny(122)
1434  nr->assert_equal(122)
1435
1436  var str: string
1437  str = FuncOneArgRetAny('yes')
1438  str->assert_equal('yes')
1439
1440  CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
1441enddef
1442
1443def Test_func_common_type()
1444  def FuncOne(n: number): number
1445    return n
1446  enddef
1447  def FuncTwo(s: string): number
1448    return len(s)
1449  enddef
1450  def FuncThree(n: number, s: string): number
1451    return n + len(s)
1452  enddef
1453  var list = [FuncOne, FuncTwo, FuncThree]
1454  assert_equal(8, list[0](8))
1455  assert_equal(4, list[1]('word'))
1456  assert_equal(7, list[2](3, 'word'))
1457enddef
1458
1459def MultiLine(
1460    arg1: string,
1461    arg2 = 1234,
1462    ...rest: list<string>
1463      ): string
1464  return arg1 .. arg2 .. join(rest, '-')
1465enddef
1466
1467def MultiLineComment(
1468    arg1: string, # comment
1469    arg2 = 1234, # comment
1470    ...rest: list<string> # comment
1471      ): string # comment
1472  return arg1 .. arg2 .. join(rest, '-')
1473enddef
1474
1475def Test_multiline()
1476  MultiLine('text')->assert_equal('text1234')
1477  MultiLine('text', 777)->assert_equal('text777')
1478  MultiLine('text', 777, 'one')->assert_equal('text777one')
1479  MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1480enddef
1481
1482func Test_multiline_not_vim9()
1483  call MultiLine('text')->assert_equal('text1234')
1484  call MultiLine('text', 777)->assert_equal('text777')
1485  call MultiLine('text', 777, 'one')->assert_equal('text777one')
1486  call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1487endfunc
1488
1489
1490" When using CheckScriptFailure() for the below test, E1010 is generated instead
1491" of E1056.
1492func Test_E1056_1059()
1493  let caught_1056 = 0
1494  try
1495    def F():
1496      return 1
1497    enddef
1498  catch /E1056:/
1499    let caught_1056 = 1
1500  endtry
1501  eval caught_1056->assert_equal(1)
1502
1503  let caught_1059 = 0
1504  try
1505    def F5(items : list)
1506      echo 'a'
1507    enddef
1508  catch /E1059:/
1509    let caught_1059 = 1
1510  endtry
1511  eval caught_1059->assert_equal(1)
1512endfunc
1513
1514func DelMe()
1515  echo 'DelMe'
1516endfunc
1517
1518def Test_error_reporting()
1519  # comment lines at the start of the function
1520  var lines =<< trim END
1521    " comment
1522    def Func()
1523      # comment
1524      # comment
1525      invalid
1526    enddef
1527    defcompile
1528  END
1529  writefile(lines, 'Xdef')
1530  try
1531    source Xdef
1532    assert_report('should have failed')
1533  catch /E476:/
1534    v:exception->assert_match('Invalid command: invalid')
1535    v:throwpoint->assert_match(', line 3$')
1536  endtry
1537  delfunc! g:Func
1538
1539  # comment lines after the start of the function
1540  lines =<< trim END
1541    " comment
1542    def Func()
1543      var x = 1234
1544      # comment
1545      # comment
1546      invalid
1547    enddef
1548    defcompile
1549  END
1550  writefile(lines, 'Xdef')
1551  try
1552    source Xdef
1553    assert_report('should have failed')
1554  catch /E476:/
1555    v:exception->assert_match('Invalid command: invalid')
1556    v:throwpoint->assert_match(', line 4$')
1557  endtry
1558  delfunc! g:Func
1559
1560  lines =<< trim END
1561    vim9script
1562    def Func()
1563      var db = {foo: 1, bar: 2}
1564      # comment
1565      var x = db.asdf
1566    enddef
1567    defcompile
1568    Func()
1569  END
1570  writefile(lines, 'Xdef')
1571  try
1572    source Xdef
1573    assert_report('should have failed')
1574  catch /E716:/
1575    v:throwpoint->assert_match('_Func, line 3$')
1576  endtry
1577  delfunc! g:Func
1578
1579  delete('Xdef')
1580enddef
1581
1582def Test_deleted_function()
1583  CheckDefExecFailure([
1584      'var RefMe: func = function("g:DelMe")',
1585      'delfunc g:DelMe',
1586      'echo RefMe()'], 'E117:')
1587enddef
1588
1589def Test_unknown_function()
1590  CheckDefExecFailure([
1591      'var Ref: func = function("NotExist")',
1592      'delfunc g:NotExist'], 'E700:')
1593enddef
1594
1595def RefFunc(Ref: func(any): any): string
1596  return Ref('more')
1597enddef
1598
1599def Test_closure_simple()
1600  var local = 'some '
1601  RefFunc((s) => local .. s)->assert_equal('some more')
1602enddef
1603
1604def MakeRef()
1605  var local = 'some '
1606  g:Ref = (s) => local .. s
1607enddef
1608
1609def Test_closure_ref_after_return()
1610  MakeRef()
1611  g:Ref('thing')->assert_equal('some thing')
1612  unlet g:Ref
1613enddef
1614
1615def MakeTwoRefs()
1616  var local = ['some']
1617  g:Extend = (s) => local->add(s)
1618  g:Read = () => local
1619enddef
1620
1621def Test_closure_two_refs()
1622  MakeTwoRefs()
1623  join(g:Read(), ' ')->assert_equal('some')
1624  g:Extend('more')
1625  join(g:Read(), ' ')->assert_equal('some more')
1626  g:Extend('even')
1627  join(g:Read(), ' ')->assert_equal('some more even')
1628
1629  unlet g:Extend
1630  unlet g:Read
1631enddef
1632
1633def ReadRef(Ref: func(): list<string>): string
1634  return join(Ref(), ' ')
1635enddef
1636
1637def ExtendRef(Ref: func(string): list<string>, add: string)
1638  Ref(add)
1639enddef
1640
1641def Test_closure_two_indirect_refs()
1642  MakeTwoRefs()
1643  ReadRef(g:Read)->assert_equal('some')
1644  ExtendRef(g:Extend, 'more')
1645  ReadRef(g:Read)->assert_equal('some more')
1646  ExtendRef(g:Extend, 'even')
1647  ReadRef(g:Read)->assert_equal('some more even')
1648
1649  unlet g:Extend
1650  unlet g:Read
1651enddef
1652
1653def MakeArgRefs(theArg: string)
1654  var local = 'loc_val'
1655  g:UseArg = (s) => theArg .. '/' .. local .. '/' .. s
1656enddef
1657
1658def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1659  var local = 'the_loc'
1660  g:UseVararg = (s) => theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)
1661enddef
1662
1663def Test_closure_using_argument()
1664  MakeArgRefs('arg_val')
1665  g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val')
1666
1667  MakeArgRefsVarargs('arg_val', 'one', 'two')
1668  g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two')
1669
1670  unlet g:UseArg
1671  unlet g:UseVararg
1672enddef
1673
1674def MakeGetAndAppendRefs()
1675  var local = 'a'
1676
1677  def Append(arg: string)
1678    local ..= arg
1679  enddef
1680  g:Append = Append
1681
1682  def Get(): string
1683    return local
1684  enddef
1685  g:Get = Get
1686enddef
1687
1688def Test_closure_append_get()
1689  MakeGetAndAppendRefs()
1690  g:Get()->assert_equal('a')
1691  g:Append('-b')
1692  g:Get()->assert_equal('a-b')
1693  g:Append('-c')
1694  g:Get()->assert_equal('a-b-c')
1695
1696  unlet g:Append
1697  unlet g:Get
1698enddef
1699
1700def Test_nested_closure()
1701  var local = 'text'
1702  def Closure(arg: string): string
1703    return local .. arg
1704  enddef
1705  Closure('!!!')->assert_equal('text!!!')
1706enddef
1707
1708func GetResult(Ref)
1709  return a:Ref('some')
1710endfunc
1711
1712def Test_call_closure_not_compiled()
1713  var text = 'text'
1714  g:Ref = (s) =>  s .. text
1715  GetResult(g:Ref)->assert_equal('sometext')
1716enddef
1717
1718def Test_double_closure_fails()
1719  var lines =<< trim END
1720    vim9script
1721    def Func()
1722      var name = 0
1723      for i in range(2)
1724          timer_start(0, () => name)
1725      endfor
1726    enddef
1727    Func()
1728  END
1729  CheckScriptSuccess(lines)
1730enddef
1731
1732def Test_nested_closure_used()
1733  var lines =<< trim END
1734      vim9script
1735      def Func()
1736        var x = 'hello'
1737        var Closure = () => x
1738        g:Myclosure = () => Closure()
1739      enddef
1740      Func()
1741      assert_equal('hello', g:Myclosure())
1742  END
1743  CheckScriptSuccess(lines)
1744enddef
1745
1746def Test_nested_closure_fails()
1747  var lines =<< trim END
1748    vim9script
1749    def FuncA()
1750      FuncB(0)
1751    enddef
1752    def FuncB(n: number): list<string>
1753      return map([0], (_, v) => n)
1754    enddef
1755    FuncA()
1756  END
1757  CheckScriptFailure(lines, 'E1012:')
1758enddef
1759
1760def Test_global_closure()
1761  var lines =<< trim END
1762      vim9script
1763      def ReverseEveryNLines(n: number, line1: number, line2: number)
1764        var mods = 'sil keepj keepp lockm '
1765        var range = ':' .. line1 .. ',' .. line2
1766        def g:Offset(): number
1767            var offset = (line('.') - line1 + 1) % n
1768            return offset != 0 ? offset : n
1769        enddef
1770        exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()'
1771      enddef
1772
1773      new
1774      repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1)
1775      ReverseEveryNLines(3, 1, 9)
1776  END
1777  CheckScriptSuccess(lines)
1778  var expected = repeat(['ccc', 'bbb', 'aaa'], 3)
1779  assert_equal(expected, getline(1, 9))
1780  bwipe!
1781enddef
1782
1783def Test_global_closure_called_directly()
1784  var lines =<< trim END
1785      vim9script
1786      def Outer()
1787        var x = 1
1788        def g:Inner()
1789          var y = x
1790          x += 1
1791          assert_equal(1, y)
1792        enddef
1793        g:Inner()
1794        assert_equal(2, x)
1795      enddef
1796      Outer()
1797  END
1798  CheckScriptSuccess(lines)
1799  delfunc g:Inner
1800enddef
1801
1802def Test_failure_in_called_function()
1803  # this was using the frame index as the return value
1804  var lines =<< trim END
1805      vim9script
1806      au TerminalWinOpen * eval [][0]
1807      def PopupTerm(a: any)
1808        # make sure typvals on stack are string
1809        ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join()
1810        FireEvent()
1811      enddef
1812      def FireEvent()
1813          do TerminalWinOpen
1814      enddef
1815      # use try/catch to make eval fail
1816      try
1817          call PopupTerm(0)
1818      catch
1819      endtry
1820      au! TerminalWinOpen
1821  END
1822  CheckScriptSuccess(lines)
1823enddef
1824
1825def Test_nested_lambda()
1826  var lines =<< trim END
1827    vim9script
1828    def Func()
1829      var x = 4
1830      var Lambda1 = () => 7
1831      var Lambda2 = () => [Lambda1(), x]
1832      var res = Lambda2()
1833      assert_equal([7, 4], res)
1834    enddef
1835    Func()
1836  END
1837  CheckScriptSuccess(lines)
1838enddef
1839
1840def Shadowed(): list<number>
1841  var FuncList: list<func: number> = [() => 42]
1842  return FuncList->mapnew((_, Shadowed) => Shadowed())
1843enddef
1844
1845def Test_lambda_arg_shadows_func()
1846  assert_equal([42], Shadowed())
1847enddef
1848
1849def Line_continuation_in_def(dir: string = ''): string
1850  var path: string = empty(dir)
1851          \ ? 'empty'
1852          \ : 'full'
1853  return path
1854enddef
1855
1856def Test_line_continuation_in_def()
1857  Line_continuation_in_def('.')->assert_equal('full')
1858enddef
1859
1860def Test_script_var_in_lambda()
1861  var lines =<< trim END
1862      vim9script
1863      var script = 'test'
1864      assert_equal(['test'], map(['one'], () => script))
1865  END
1866  CheckScriptSuccess(lines)
1867enddef
1868
1869def Line_continuation_in_lambda(): list<string>
1870  var x = range(97, 100)
1871      ->mapnew((_, v) => nr2char(v)
1872          ->toupper())
1873      ->reverse()
1874  return x
1875enddef
1876
1877def Test_line_continuation_in_lambda()
1878  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
1879
1880  var lines =<< trim END
1881      vim9script
1882      var res = [{n: 1, m: 2, s: 'xxx'}]
1883                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
1884                    v.n,
1885                    v.m,
1886                    substitute(v.s, '.*', 'yyy', '')
1887                    ))
1888      assert_equal(['1:2:yyy'], res)
1889  END
1890  CheckScriptSuccess(lines)
1891enddef
1892
1893def Test_list_lambda()
1894  timer_start(1000, (_) => 0)
1895  var body = execute(timer_info()[0].callback
1896         ->string()
1897         ->substitute("('", ' ', '')
1898         ->substitute("')", '', '')
1899         ->substitute('function\zs', ' ', ''))
1900  assert_match('def <lambda>\d\+(_: any, ...): number\n1  return 0\n   enddef', body)
1901enddef
1902
1903def DoFilterThis(a: string): list<string>
1904  # closure nested inside another closure using argument
1905  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
1906  return ['x', 'y', 'a', 'x2', 'c']->Filter()
1907enddef
1908
1909def Test_nested_closure_using_argument()
1910  assert_equal(['x', 'x2'], DoFilterThis('x'))
1911enddef
1912
1913def Test_triple_nested_closure()
1914  var what = 'x'
1915  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
1916  var Filter = (l) => filter(l, (_, v) => Match(v, what))
1917  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
1918enddef
1919
1920func Test_silent_echo()
1921  CheckScreendump
1922
1923  let lines =<< trim END
1924    vim9script
1925    def EchoNothing()
1926      silent echo ''
1927    enddef
1928    defcompile
1929  END
1930  call writefile(lines, 'XTest_silent_echo')
1931
1932  " Check that the balloon shows up after a mouse move
1933  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1934  call term_sendkeys(buf, ":abc")
1935  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1936
1937  " clean up
1938  call StopVimInTerminal(buf)
1939  call delete('XTest_silent_echo')
1940endfunc
1941
1942def SilentlyError()
1943  execute('silent! invalid')
1944  g:did_it = 'yes'
1945enddef
1946
1947func UserError()
1948  silent! invalid
1949endfunc
1950
1951def SilentlyUserError()
1952  UserError()
1953  g:did_it = 'yes'
1954enddef
1955
1956" This can't be a :def function, because the assert would not be reached.
1957func Test_ignore_silent_error()
1958  let g:did_it = 'no'
1959  call SilentlyError()
1960  call assert_equal('yes', g:did_it)
1961
1962  let g:did_it = 'no'
1963  call SilentlyUserError()
1964  call assert_equal('yes', g:did_it)
1965
1966  unlet g:did_it
1967endfunc
1968
1969def Test_ignore_silent_error_in_filter()
1970  var lines =<< trim END
1971      vim9script
1972      def Filter(winid: number, key: string): bool
1973          if key == 'o'
1974              silent! eval [][0]
1975              return true
1976          endif
1977          return popup_filter_menu(winid, key)
1978      enddef
1979
1980      popup_create('popup', {filter: Filter})
1981      feedkeys("o\r", 'xnt')
1982  END
1983  CheckScriptSuccess(lines)
1984enddef
1985
1986def Fibonacci(n: number): number
1987  if n < 2
1988    return n
1989  else
1990    return Fibonacci(n - 1) + Fibonacci(n - 2)
1991  endif
1992enddef
1993
1994def Test_recursive_call()
1995  Fibonacci(20)->assert_equal(6765)
1996enddef
1997
1998def TreeWalk(dir: string): list<any>
1999  return readdir(dir)->mapnew((_, val) =>
2000            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2001               ? {[val]: TreeWalk(dir .. '/' .. val)}
2002               : val
2003             )
2004enddef
2005
2006def Test_closure_in_map()
2007  mkdir('XclosureDir/tdir', 'p')
2008  writefile(['111'], 'XclosureDir/file1')
2009  writefile(['222'], 'XclosureDir/file2')
2010  writefile(['333'], 'XclosureDir/tdir/file3')
2011
2012  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2013
2014  delete('XclosureDir', 'rf')
2015enddef
2016
2017def Test_invalid_function_name()
2018  var lines =<< trim END
2019      vim9script
2020      def s: list<string>
2021  END
2022  CheckScriptFailure(lines, 'E129:')
2023
2024  lines =<< trim END
2025      vim9script
2026      def g: list<string>
2027  END
2028  CheckScriptFailure(lines, 'E129:')
2029
2030  lines =<< trim END
2031      vim9script
2032      def <SID>: list<string>
2033  END
2034  CheckScriptFailure(lines, 'E884:')
2035
2036  lines =<< trim END
2037      vim9script
2038      def F list<string>
2039  END
2040  CheckScriptFailure(lines, 'E488:')
2041enddef
2042
2043def Test_partial_call()
2044  var Xsetlist = function('setloclist', [0])
2045  Xsetlist([], ' ', {title: 'test'})
2046  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2047
2048  Xsetlist = function('setloclist', [0, [], ' '])
2049  Xsetlist({title: 'test'})
2050  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2051
2052  Xsetlist = function('setqflist')
2053  Xsetlist([], ' ', {title: 'test'})
2054  getqflist({title: 1})->assert_equal({title: 'test'})
2055
2056  Xsetlist = function('setqflist', [[], ' '])
2057  Xsetlist({title: 'test'})
2058  getqflist({title: 1})->assert_equal({title: 'test'})
2059
2060  var Len: func: number = function('len', ['word'])
2061  assert_equal(4, Len())
2062enddef
2063
2064def Test_cmd_modifier()
2065  tab echo '0'
2066  CheckDefFailure(['5tab echo 3'], 'E16:')
2067enddef
2068
2069def Test_restore_modifiers()
2070  # check that when compiling a :def function command modifiers are not messed
2071  # up.
2072  var lines =<< trim END
2073      vim9script
2074      set eventignore=
2075      autocmd QuickFixCmdPost * copen
2076      def AutocmdsDisabled()
2077        eval 0
2078      enddef
2079      func Func()
2080        noautocmd call s:AutocmdsDisabled()
2081        let g:ei_after = &eventignore
2082      endfunc
2083      Func()
2084  END
2085  CheckScriptSuccess(lines)
2086  g:ei_after->assert_equal('')
2087enddef
2088
2089def StackTop()
2090  eval 1
2091  eval 2
2092  # call not on fourth line
2093  StackBot()
2094enddef
2095
2096def StackBot()
2097  # throw an error
2098  eval [][0]
2099enddef
2100
2101def Test_callstack_def()
2102  try
2103    StackTop()
2104  catch
2105    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2106  endtry
2107enddef
2108
2109" Re-using spot for variable used in block
2110def Test_block_scoped_var()
2111  var lines =<< trim END
2112      vim9script
2113      def Func()
2114        var x = ['a', 'b', 'c']
2115        if 1
2116          var y = 'x'
2117          map(x, () => y)
2118        endif
2119        var z = x
2120        assert_equal(['x', 'x', 'x'], z)
2121      enddef
2122      Func()
2123  END
2124  CheckScriptSuccess(lines)
2125enddef
2126
2127def Test_reset_did_emsg()
2128  var lines =<< trim END
2129      @s = 'blah'
2130      au BufWinLeave * #
2131      def Func()
2132        var winid = popup_create('popup', {})
2133        exe '*s'
2134        popup_close(winid)
2135      enddef
2136      Func()
2137  END
2138  CheckScriptFailure(lines, 'E492:', 8)
2139  delfunc! g:Func
2140enddef
2141
2142def Test_did_emsg_reset()
2143  # executing an autocommand resets did_emsg, this should not result in a
2144  # builtin function considered failing
2145  var lines =<< trim END
2146      vim9script
2147      au BufWinLeave * #
2148      def Func()
2149          popup_menu('', {callback: () => popup_create('', {})->popup_close()})
2150          eval [][0]
2151      enddef
2152      nno <F3> <cmd>call <sid>Func()<cr>
2153      feedkeys("\<F3>\e", 'xt')
2154  END
2155  writefile(lines, 'XemsgReset')
2156  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2157  delete('XemsgReset')
2158  nunmap <F3>
2159  au! BufWinLeave
2160enddef
2161
2162def Test_abort_with_silent_call()
2163  var lines =<< trim END
2164      vim9script
2165      g:result = 'none'
2166      def Func()
2167        g:result += 3
2168        g:result = 'yes'
2169      enddef
2170      # error is silenced, but function aborts on error
2171      silent! Func()
2172      assert_equal('none', g:result)
2173      unlet g:result
2174  END
2175  CheckScriptSuccess(lines)
2176enddef
2177
2178def Test_continues_with_silent_error()
2179  var lines =<< trim END
2180      vim9script
2181      g:result = 'none'
2182      def Func()
2183        silent!  g:result += 3
2184        g:result = 'yes'
2185      enddef
2186      # error is silenced, function does not abort
2187      Func()
2188      assert_equal('yes', g:result)
2189      unlet g:result
2190  END
2191  CheckScriptSuccess(lines)
2192enddef
2193
2194def Test_abort_even_with_silent()
2195  var lines =<< trim END
2196      vim9script
2197      g:result = 'none'
2198      def Func()
2199        eval {-> ''}() .. '' .. {}['X']
2200        g:result = 'yes'
2201      enddef
2202      silent! Func()
2203      assert_equal('none', g:result)
2204      unlet g:result
2205  END
2206  CheckScriptSuccess(lines)
2207enddef
2208
2209def Test_cmdmod_silent_restored()
2210  var lines =<< trim END
2211      vim9script
2212      def Func()
2213        g:result = 'none'
2214        silent! g:result += 3
2215        g:result = 'none'
2216        g:result += 3
2217      enddef
2218      Func()
2219  END
2220  # can't use CheckScriptFailure, it ignores the :silent!
2221  var fname = 'Xdefsilent'
2222  writefile(lines, fname)
2223  var caught = 'no'
2224  try
2225    exe 'source ' .. fname
2226  catch /E1030:/
2227    caught = 'yes'
2228    assert_match('Func, line 4', v:throwpoint)
2229  endtry
2230  assert_equal('yes', caught)
2231  delete(fname)
2232enddef
2233
2234def Test_dict_member_with_silent()
2235  var lines =<< trim END
2236      vim9script
2237      g:result = 'none'
2238      var d: dict<any>
2239      def Func()
2240        try
2241          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2242        catch
2243        endtry
2244      enddef
2245      silent! Func()
2246      assert_equal('0', g:result)
2247      unlet g:result
2248  END
2249  CheckScriptSuccess(lines)
2250enddef
2251
2252def Test_skip_cmds_with_silent()
2253  var lines =<< trim END
2254      vim9script
2255
2256      def Func(b: bool)
2257        Crash()
2258      enddef
2259
2260      def Crash()
2261        sil! :/not found/d _
2262        sil! :/not found/put _
2263      enddef
2264
2265      Func(true)
2266  END
2267  CheckScriptSuccess(lines)
2268enddef
2269
2270def Test_opfunc()
2271  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2272  def g:Opfunc(_: any): string
2273    setline(1, 'ASDF')
2274    return ''
2275  enddef
2276  new
2277  setline(1, 'asdf')
2278  feedkeys("\<F3>$", 'x')
2279  assert_equal('ASDF', getline(1))
2280
2281  bwipe!
2282  nunmap <F3>
2283enddef
2284
2285" this was crashing on exit
2286def Test_nested_lambda_in_closure()
2287  var lines =<< trim END
2288      vim9script
2289      def Outer()
2290          def g:Inner()
2291              echo map([1, 2, 3], {_, v -> v + 1})
2292          enddef
2293          g:Inner()
2294      enddef
2295      defcompile
2296      writefile(['Done'], 'XnestedDone')
2297      quit
2298  END
2299  if !RunVim([], lines, '--clean')
2300    return
2301  endif
2302  assert_equal(['Done'], readfile('XnestedDone'))
2303  delete('XnestedDone')
2304enddef
2305
2306
2307
2308" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
2309