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