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