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')
1025enddef
1026
1027" Test that inside :function a Python function can be defined, :def is not
1028" recognized.
1029func Test_function_python()
1030  CheckFeature python3
1031  let py = 'python3'
1032  execute py "<< EOF"
1033def do_something():
1034  return 1
1035EOF
1036endfunc
1037
1038def Test_delfunc()
1039  var lines =<< trim END
1040    vim9script
1041    def g:GoneSoon()
1042      echo 'hello'
1043    enddef
1044
1045    def CallGoneSoon()
1046      GoneSoon()
1047    enddef
1048    defcompile
1049
1050    delfunc g:GoneSoon
1051    CallGoneSoon()
1052  END
1053  writefile(lines, 'XToDelFunc')
1054  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1055  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1056
1057  delete('XToDelFunc')
1058enddef
1059
1060def Test_redef_failure()
1061  writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
1062  so Xdef
1063  writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
1064  so Xdef
1065  writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
1066  assert_fails('so Xdef', 'E1027:', '', 1, 'Func0')
1067  writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
1068  so Xdef
1069  delete('Xdef')
1070
1071  g:Func0()->assert_equal(0)
1072  g:Func1()->assert_equal('Func1')
1073  g:Func2()->assert_equal('Func2')
1074
1075  delfunc! Func0
1076  delfunc! Func1
1077  delfunc! Func2
1078enddef
1079
1080def Test_vim9script_func()
1081  var lines =<< trim END
1082    vim9script
1083    func Func(arg)
1084      echo a:arg
1085    endfunc
1086    Func('text')
1087  END
1088  writefile(lines, 'XVim9Func')
1089  so XVim9Func
1090
1091  delete('XVim9Func')
1092enddef
1093
1094let s:funcResult = 0
1095
1096def FuncNoArgNoRet()
1097  s:funcResult = 11
1098enddef
1099
1100def FuncNoArgRetNumber(): number
1101  s:funcResult = 22
1102  return 1234
1103enddef
1104
1105def FuncNoArgRetString(): string
1106  s:funcResult = 45
1107  return 'text'
1108enddef
1109
1110def FuncOneArgNoRet(arg: number)
1111  s:funcResult = arg
1112enddef
1113
1114def FuncOneArgRetNumber(arg: number): number
1115  s:funcResult = arg
1116  return arg
1117enddef
1118
1119def FuncTwoArgNoRet(one: bool, two: number)
1120  s:funcResult = two
1121enddef
1122
1123def FuncOneArgRetString(arg: string): string
1124  return arg
1125enddef
1126
1127def FuncOneArgRetAny(arg: any): any
1128  return arg
1129enddef
1130
1131def Test_func_type()
1132  var Ref1: func()
1133  s:funcResult = 0
1134  Ref1 = FuncNoArgNoRet
1135  Ref1()
1136  s:funcResult->assert_equal(11)
1137
1138  var Ref2: func
1139  s:funcResult = 0
1140  Ref2 = FuncNoArgNoRet
1141  Ref2()
1142  s:funcResult->assert_equal(11)
1143
1144  s:funcResult = 0
1145  Ref2 = FuncOneArgNoRet
1146  Ref2(12)
1147  s:funcResult->assert_equal(12)
1148
1149  s:funcResult = 0
1150  Ref2 = FuncNoArgRetNumber
1151  Ref2()->assert_equal(1234)
1152  s:funcResult->assert_equal(22)
1153
1154  s:funcResult = 0
1155  Ref2 = FuncOneArgRetNumber
1156  Ref2(13)->assert_equal(13)
1157  s:funcResult->assert_equal(13)
1158enddef
1159
1160def Test_repeat_return_type()
1161  var res = 0
1162  for n in repeat([1], 3)
1163    res += n
1164  endfor
1165  res->assert_equal(3)
1166
1167  res = 0
1168  for n in add([1, 2], 3)
1169    res += n
1170  endfor
1171  res->assert_equal(6)
1172enddef
1173
1174def Test_argv_return_type()
1175  next fileone filetwo
1176  var res = ''
1177  for name in argv()
1178    res ..= name
1179  endfor
1180  res->assert_equal('fileonefiletwo')
1181enddef
1182
1183def Test_func_type_part()
1184  var RefVoid: func: void
1185  RefVoid = FuncNoArgNoRet
1186  RefVoid = FuncOneArgNoRet
1187  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
1188  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
1189
1190  var RefAny: func(): any
1191  RefAny = FuncNoArgRetNumber
1192  RefAny = FuncNoArgRetString
1193  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
1194  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
1195
1196  var RefAnyNoArgs: func: any = RefAny
1197
1198  var RefNr: func: number
1199  RefNr = FuncNoArgRetNumber
1200  RefNr = FuncOneArgRetNumber
1201  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1202  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1203
1204  var RefStr: func: string
1205  RefStr = FuncNoArgRetString
1206  RefStr = FuncOneArgRetString
1207  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1208  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1209enddef
1210
1211def Test_func_type_fails()
1212  CheckDefFailure(['var ref1: func()'], 'E704:')
1213
1214  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1215  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1216  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1217  CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1218  CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1219  CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1220
1221  CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
1222  CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
1223  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:')
1224  CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:')
1225enddef
1226
1227def Test_func_return_type()
1228  var nr: number
1229  nr = FuncNoArgRetNumber()
1230  nr->assert_equal(1234)
1231
1232  nr = FuncOneArgRetAny(122)
1233  nr->assert_equal(122)
1234
1235  var str: string
1236  str = FuncOneArgRetAny('yes')
1237  str->assert_equal('yes')
1238
1239  CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
1240enddef
1241
1242def Test_func_common_type()
1243  def FuncOne(n: number): number
1244    return n
1245  enddef
1246  def FuncTwo(s: string): number
1247    return len(s)
1248  enddef
1249  def FuncThree(n: number, s: string): number
1250    return n + len(s)
1251  enddef
1252  var list = [FuncOne, FuncTwo, FuncThree]
1253  assert_equal(8, list[0](8))
1254  assert_equal(4, list[1]('word'))
1255  assert_equal(7, list[2](3, 'word'))
1256enddef
1257
1258def MultiLine(
1259    arg1: string,
1260    arg2 = 1234,
1261    ...rest: list<string>
1262      ): string
1263  return arg1 .. arg2 .. join(rest, '-')
1264enddef
1265
1266def MultiLineComment(
1267    arg1: string, # comment
1268    arg2 = 1234, # comment
1269    ...rest: list<string> # comment
1270      ): string # comment
1271  return arg1 .. arg2 .. join(rest, '-')
1272enddef
1273
1274def Test_multiline()
1275  MultiLine('text')->assert_equal('text1234')
1276  MultiLine('text', 777)->assert_equal('text777')
1277  MultiLine('text', 777, 'one')->assert_equal('text777one')
1278  MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1279enddef
1280
1281func Test_multiline_not_vim9()
1282  call MultiLine('text')->assert_equal('text1234')
1283  call MultiLine('text', 777)->assert_equal('text777')
1284  call MultiLine('text', 777, 'one')->assert_equal('text777one')
1285  call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1286endfunc
1287
1288
1289" When using CheckScriptFailure() for the below test, E1010 is generated instead
1290" of E1056.
1291func Test_E1056_1059()
1292  let caught_1056 = 0
1293  try
1294    def F():
1295      return 1
1296    enddef
1297  catch /E1056:/
1298    let caught_1056 = 1
1299  endtry
1300  eval caught_1056->assert_equal(1)
1301
1302  let caught_1059 = 0
1303  try
1304    def F5(items : list)
1305      echo 'a'
1306    enddef
1307  catch /E1059:/
1308    let caught_1059 = 1
1309  endtry
1310  eval caught_1059->assert_equal(1)
1311endfunc
1312
1313func DelMe()
1314  echo 'DelMe'
1315endfunc
1316
1317def Test_error_reporting()
1318  # comment lines at the start of the function
1319  var lines =<< trim END
1320    " comment
1321    def Func()
1322      # comment
1323      # comment
1324      invalid
1325    enddef
1326    defcompile
1327  END
1328  writefile(lines, 'Xdef')
1329  try
1330    source Xdef
1331    assert_report('should have failed')
1332  catch /E476:/
1333    v:exception->assert_match('Invalid command: invalid')
1334    v:throwpoint->assert_match(', line 3$')
1335  endtry
1336  delfunc! g:Func
1337
1338  # comment lines after the start of the function
1339  lines =<< trim END
1340    " comment
1341    def Func()
1342      var x = 1234
1343      # comment
1344      # comment
1345      invalid
1346    enddef
1347    defcompile
1348  END
1349  writefile(lines, 'Xdef')
1350  try
1351    source Xdef
1352    assert_report('should have failed')
1353  catch /E476:/
1354    v:exception->assert_match('Invalid command: invalid')
1355    v:throwpoint->assert_match(', line 4$')
1356  endtry
1357  delfunc! g:Func
1358
1359  lines =<< trim END
1360    vim9script
1361    def Func()
1362      var db = {foo: 1, bar: 2}
1363      # comment
1364      var x = db.asdf
1365    enddef
1366    defcompile
1367    Func()
1368  END
1369  writefile(lines, 'Xdef')
1370  try
1371    source Xdef
1372    assert_report('should have failed')
1373  catch /E716:/
1374    v:throwpoint->assert_match('_Func, line 3$')
1375  endtry
1376  delfunc! g:Func
1377
1378  delete('Xdef')
1379enddef
1380
1381def Test_deleted_function()
1382  CheckDefExecFailure([
1383      'var RefMe: func = function("g:DelMe")',
1384      'delfunc g:DelMe',
1385      'echo RefMe()'], 'E117:')
1386enddef
1387
1388def Test_unknown_function()
1389  CheckDefExecFailure([
1390      'var Ref: func = function("NotExist")',
1391      'delfunc g:NotExist'], 'E700:')
1392enddef
1393
1394def RefFunc(Ref: func(string): string): string
1395  return Ref('more')
1396enddef
1397
1398def Test_closure_simple()
1399  var local = 'some '
1400  RefFunc({s -> local .. s})->assert_equal('some more')
1401enddef
1402
1403def MakeRef()
1404  var local = 'some '
1405  g:Ref = {s -> local .. s}
1406enddef
1407
1408def Test_closure_ref_after_return()
1409  MakeRef()
1410  g:Ref('thing')->assert_equal('some thing')
1411  unlet g:Ref
1412enddef
1413
1414def MakeTwoRefs()
1415  var local = ['some']
1416  g:Extend = {s -> local->add(s)}
1417  g:Read = {-> local}
1418enddef
1419
1420def Test_closure_two_refs()
1421  MakeTwoRefs()
1422  join(g:Read(), ' ')->assert_equal('some')
1423  g:Extend('more')
1424  join(g:Read(), ' ')->assert_equal('some more')
1425  g:Extend('even')
1426  join(g:Read(), ' ')->assert_equal('some more even')
1427
1428  unlet g:Extend
1429  unlet g:Read
1430enddef
1431
1432def ReadRef(Ref: func(): list<string>): string
1433  return join(Ref(), ' ')
1434enddef
1435
1436def ExtendRef(Ref: func(string): list<string>, add: string)
1437  Ref(add)
1438enddef
1439
1440def Test_closure_two_indirect_refs()
1441  MakeTwoRefs()
1442  ReadRef(g:Read)->assert_equal('some')
1443  ExtendRef(g:Extend, 'more')
1444  ReadRef(g:Read)->assert_equal('some more')
1445  ExtendRef(g:Extend, 'even')
1446  ReadRef(g:Read)->assert_equal('some more even')
1447
1448  unlet g:Extend
1449  unlet g:Read
1450enddef
1451
1452def MakeArgRefs(theArg: string)
1453  var local = 'loc_val'
1454  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
1455enddef
1456
1457def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1458  var local = 'the_loc'
1459  g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)}
1460enddef
1461
1462def Test_closure_using_argument()
1463  MakeArgRefs('arg_val')
1464  g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val')
1465
1466  MakeArgRefsVarargs('arg_val', 'one', 'two')
1467  g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two')
1468
1469  unlet g:UseArg
1470  unlet g:UseVararg
1471enddef
1472
1473def MakeGetAndAppendRefs()
1474  var local = 'a'
1475
1476  def Append(arg: string)
1477    local ..= arg
1478  enddef
1479  g:Append = Append
1480
1481  def Get(): string
1482    return local
1483  enddef
1484  g:Get = Get
1485enddef
1486
1487def Test_closure_append_get()
1488  MakeGetAndAppendRefs()
1489  g:Get()->assert_equal('a')
1490  g:Append('-b')
1491  g:Get()->assert_equal('a-b')
1492  g:Append('-c')
1493  g:Get()->assert_equal('a-b-c')
1494
1495  unlet g:Append
1496  unlet g:Get
1497enddef
1498
1499def Test_nested_closure()
1500  var local = 'text'
1501  def Closure(arg: string): string
1502    return local .. arg
1503  enddef
1504  Closure('!!!')->assert_equal('text!!!')
1505enddef
1506
1507func GetResult(Ref)
1508  return a:Ref('some')
1509endfunc
1510
1511def Test_call_closure_not_compiled()
1512  var text = 'text'
1513  g:Ref = {s ->  s .. text}
1514  GetResult(g:Ref)->assert_equal('sometext')
1515enddef
1516
1517def Test_double_closure_fails()
1518  var lines =<< trim END
1519    vim9script
1520    def Func()
1521      var name = 0
1522      for i in range(2)
1523          timer_start(0, {-> name})
1524      endfor
1525    enddef
1526    Func()
1527  END
1528  CheckScriptSuccess(lines)
1529enddef
1530
1531def Test_nested_closure_used()
1532  var lines =<< trim END
1533      vim9script
1534      def Func()
1535        var x = 'hello'
1536        var Closure = {-> x}
1537        g:Myclosure = {-> Closure()}
1538      enddef
1539      Func()
1540      assert_equal('hello', g:Myclosure())
1541  END
1542  CheckScriptSuccess(lines)
1543enddef
1544
1545def Test_nested_closure_fails()
1546  var lines =<< trim END
1547    vim9script
1548    def FuncA()
1549      FuncB(0)
1550    enddef
1551    def FuncB(n: number): list<string>
1552      return map([0], {_, v -> n})
1553    enddef
1554    FuncA()
1555  END
1556  CheckScriptFailure(lines, 'E1012:')
1557enddef
1558
1559def Test_global_closure()
1560  var lines =<< trim END
1561      vim9script
1562      def ReverseEveryNLines(n: number, line1: number, line2: number)
1563        var mods = 'sil keepj keepp lockm '
1564        var range = ':' .. line1 .. ',' .. line2
1565        def g:Offset(): number
1566            var offset = (line('.') - line1 + 1) % n
1567            return offset != 0 ? offset : n
1568        enddef
1569        exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()'
1570      enddef
1571
1572      new
1573      repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1)
1574      ReverseEveryNLines(3, 1, 9)
1575  END
1576  CheckScriptSuccess(lines)
1577  var expected = repeat(['ccc', 'bbb', 'aaa'], 3)
1578  assert_equal(expected, getline(1, 9))
1579  bwipe!
1580enddef
1581
1582def Test_global_closure_called_directly()
1583  var lines =<< trim END
1584      vim9script
1585      def Outer()
1586        var x = 1
1587        def g:Inner()
1588          var y = x
1589          x += 1
1590          assert_equal(1, y)
1591        enddef
1592        g:Inner()
1593        assert_equal(2, x)
1594      enddef
1595      Outer()
1596  END
1597  CheckScriptSuccess(lines)
1598  delfunc g:Inner
1599enddef
1600
1601def Test_failure_in_called_function()
1602  # this was using the frame index as the return value
1603  var lines =<< trim END
1604      vim9script
1605      au TerminalWinOpen * eval [][0]
1606      def PopupTerm(a: any)
1607        # make sure typvals on stack are string
1608        ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join()
1609        FireEvent()
1610      enddef
1611      def FireEvent()
1612          do TerminalWinOpen
1613      enddef
1614      # use try/catch to make eval fail
1615      try
1616          call PopupTerm(0)
1617      catch
1618      endtry
1619      au! TerminalWinOpen
1620  END
1621  CheckScriptSuccess(lines)
1622enddef
1623
1624def Test_nested_lambda()
1625  var lines =<< trim END
1626    vim9script
1627    def Func()
1628      var x = 4
1629      var Lambda1 = {-> 7}
1630      var Lambda2 = {-> [Lambda1(), x]}
1631      var res = Lambda2()
1632      assert_equal([7, 4], res)
1633    enddef
1634    Func()
1635  END
1636  CheckScriptSuccess(lines)
1637enddef
1638
1639def Shadowed(): list<number>
1640  var FuncList: list<func: number> = [{ -> 42}]
1641  return FuncList->map({_, Shadowed -> Shadowed()})
1642enddef
1643
1644def Test_lambda_arg_shadows_func()
1645  assert_equal([42], Shadowed())
1646enddef
1647
1648def Line_continuation_in_def(dir: string = ''): string
1649  var path: string = empty(dir)
1650          \ ? 'empty'
1651          \ : 'full'
1652  return path
1653enddef
1654
1655def Test_line_continuation_in_def()
1656  Line_continuation_in_def('.')->assert_equal('full')
1657enddef
1658
1659def Test_script_var_in_lambda()
1660  var lines =<< trim END
1661      vim9script
1662      var script = 'test'
1663      assert_equal(['test'], map(['one'], {-> script}))
1664  END
1665  CheckScriptSuccess(lines)
1666enddef
1667
1668def Line_continuation_in_lambda(): list<string>
1669  var x = range(97, 100)
1670      ->map({_, v -> nr2char(v)
1671          ->toupper()})
1672      ->reverse()
1673  return x
1674enddef
1675
1676def Test_line_continuation_in_lambda()
1677  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
1678enddef
1679
1680func Test_silent_echo()
1681  CheckScreendump
1682
1683  let lines =<< trim END
1684    vim9script
1685    def EchoNothing()
1686      silent echo ''
1687    enddef
1688    defcompile
1689  END
1690  call writefile(lines, 'XTest_silent_echo')
1691
1692  " Check that the balloon shows up after a mouse move
1693  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1694  call term_sendkeys(buf, ":abc")
1695  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1696
1697  " clean up
1698  call StopVimInTerminal(buf)
1699  call delete('XTest_silent_echo')
1700endfunc
1701
1702def SilentlyError()
1703  execute('silent! invalid')
1704  g:did_it = 'yes'
1705enddef
1706
1707func UserError()
1708  silent! invalid
1709endfunc
1710
1711def SilentlyUserError()
1712  UserError()
1713  g:did_it = 'yes'
1714enddef
1715
1716" This can't be a :def function, because the assert would not be reached.
1717func Test_ignore_silent_error()
1718  let g:did_it = 'no'
1719  call SilentlyError()
1720  call assert_equal('yes', g:did_it)
1721
1722  let g:did_it = 'no'
1723  call SilentlyUserError()
1724  call assert_equal('yes', g:did_it)
1725
1726  unlet g:did_it
1727endfunc
1728
1729def Test_ignore_silent_error_in_filter()
1730  var lines =<< trim END
1731      vim9script
1732      def Filter(winid: number, key: string): bool
1733          if key == 'o'
1734              silent! eval [][0]
1735              return true
1736          endif
1737          return popup_filter_menu(winid, key)
1738      enddef
1739
1740      popup_create('popup', {filter: Filter})
1741      feedkeys("o\r", 'xnt')
1742  END
1743  CheckScriptSuccess(lines)
1744enddef
1745
1746def Fibonacci(n: number): number
1747  if n < 2
1748    return n
1749  else
1750    return Fibonacci(n - 1) + Fibonacci(n - 2)
1751  endif
1752enddef
1753
1754def Test_recursive_call()
1755  Fibonacci(20)->assert_equal(6765)
1756enddef
1757
1758def TreeWalk(dir: string): list<any>
1759  return readdir(dir)->map({_, val ->
1760            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
1761               ? {[val]: TreeWalk(dir .. '/' .. val)}
1762               : val
1763             })
1764enddef
1765
1766def Test_closure_in_map()
1767  mkdir('XclosureDir/tdir', 'p')
1768  writefile(['111'], 'XclosureDir/file1')
1769  writefile(['222'], 'XclosureDir/file2')
1770  writefile(['333'], 'XclosureDir/tdir/file3')
1771
1772  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
1773
1774  delete('XclosureDir', 'rf')
1775enddef
1776
1777def Test_invalid_function_name()
1778  var lines =<< trim END
1779      vim9script
1780      def s: list<string>
1781  END
1782  CheckScriptFailure(lines, 'E129:')
1783
1784  lines =<< trim END
1785      vim9script
1786      def g: list<string>
1787  END
1788  CheckScriptFailure(lines, 'E129:')
1789
1790  lines =<< trim END
1791      vim9script
1792      def <SID>: list<string>
1793  END
1794  CheckScriptFailure(lines, 'E884:')
1795
1796  lines =<< trim END
1797      vim9script
1798      def F list<string>
1799  END
1800  CheckScriptFailure(lines, 'E488:')
1801enddef
1802
1803def Test_partial_call()
1804  var Xsetlist = function('setloclist', [0])
1805  Xsetlist([], ' ', {title: 'test'})
1806  getloclist(0, {title: 1})->assert_equal({title: 'test'})
1807
1808  Xsetlist = function('setloclist', [0, [], ' '])
1809  Xsetlist({title: 'test'})
1810  getloclist(0, {title: 1})->assert_equal({title: 'test'})
1811
1812  Xsetlist = function('setqflist')
1813  Xsetlist([], ' ', {title: 'test'})
1814  getqflist({title: 1})->assert_equal({title: 'test'})
1815
1816  Xsetlist = function('setqflist', [[], ' '])
1817  Xsetlist({title: 'test'})
1818  getqflist({title: 1})->assert_equal({title: 'test'})
1819
1820  var Len: func: number = function('len', ['word'])
1821  assert_equal(4, Len())
1822enddef
1823
1824def Test_cmd_modifier()
1825  tab echo '0'
1826  CheckDefFailure(['5tab echo 3'], 'E16:')
1827enddef
1828
1829def Test_restore_modifiers()
1830  # check that when compiling a :def function command modifiers are not messed
1831  # up.
1832  var lines =<< trim END
1833      vim9script
1834      set eventignore=
1835      autocmd QuickFixCmdPost * copen
1836      def AutocmdsDisabled()
1837        eval 0
1838      enddef
1839      func Func()
1840        noautocmd call s:AutocmdsDisabled()
1841        let g:ei_after = &eventignore
1842      endfunc
1843      Func()
1844  END
1845  CheckScriptSuccess(lines)
1846  g:ei_after->assert_equal('')
1847enddef
1848
1849def StackTop()
1850  eval 1
1851  eval 2
1852  # call not on fourth line
1853  StackBot()
1854enddef
1855
1856def StackBot()
1857  # throw an error
1858  eval [][0]
1859enddef
1860
1861def Test_callstack_def()
1862  try
1863    StackTop()
1864  catch
1865    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
1866  endtry
1867enddef
1868
1869" Re-using spot for variable used in block
1870def Test_block_scoped_var()
1871  var lines =<< trim END
1872      vim9script
1873      def Func()
1874        var x = ['a', 'b', 'c']
1875        if 1
1876          var y = 'x'
1877          map(x, {-> y})
1878        endif
1879        var z = x
1880        assert_equal(['x', 'x', 'x'], z)
1881      enddef
1882      Func()
1883  END
1884  CheckScriptSuccess(lines)
1885enddef
1886
1887def Test_reset_did_emsg()
1888  var lines =<< trim END
1889      @s = 'blah'
1890      au BufWinLeave * #
1891      def Func()
1892        var winid = popup_create('popup', {})
1893        exe '*s'
1894        popup_close(winid)
1895      enddef
1896      Func()
1897  END
1898  CheckScriptFailure(lines, 'E492:', 8)
1899  delfunc! g:Func
1900enddef
1901
1902def Test_did_emsg_reset()
1903  # executing an autocommand resets did_emsg, this should not result in a
1904  # builtin function considered failing
1905  var lines =<< trim END
1906      vim9script
1907      au BufWinLeave * #
1908      def Func()
1909          popup_menu('', {callback: {-> popup_create('', {})->popup_close()}})
1910          eval [][0]
1911      enddef
1912      nno <F3> <cmd>call <sid>Func()<cr>
1913      feedkeys("\<F3>\e", 'xt')
1914  END
1915  writefile(lines, 'XemsgReset')
1916  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
1917  delete('XemsgReset')
1918  nunmap <F3>
1919  au! BufWinLeave
1920enddef
1921
1922def Test_abort_with_silent_call()
1923  var lines =<< trim END
1924      vim9script
1925      g:result = 'none'
1926      def Func()
1927        g:result += 3
1928        g:result = 'yes'
1929      enddef
1930      # error is silenced, but function aborts on error
1931      silent! Func()
1932      assert_equal('none', g:result)
1933      unlet g:result
1934  END
1935  CheckScriptSuccess(lines)
1936enddef
1937
1938def Test_continues_with_silent_error()
1939  var lines =<< trim END
1940      vim9script
1941      g:result = 'none'
1942      def Func()
1943        silent!  g:result += 3
1944        g:result = 'yes'
1945      enddef
1946      # error is silenced, function does not abort
1947      Func()
1948      assert_equal('yes', g:result)
1949      unlet g:result
1950  END
1951  CheckScriptSuccess(lines)
1952enddef
1953
1954def Test_abort_even_with_silent()
1955  var lines =<< trim END
1956      vim9script
1957      g:result = 'none'
1958      def Func()
1959        eval {-> ''}() .. '' .. {}['X']
1960        g:result = 'yes'
1961      enddef
1962      silent! Func()
1963      assert_equal('none', g:result)
1964      unlet g:result
1965  END
1966  CheckScriptSuccess(lines)
1967enddef
1968
1969def Test_cmdmod_silent_restored()
1970  var lines =<< trim END
1971      vim9script
1972      def Func()
1973        g:result = 'none'
1974        silent! g:result += 3
1975        g:result = 'none'
1976        g:result += 3
1977      enddef
1978      Func()
1979  END
1980  # can't use CheckScriptFailure, it ignores the :silent!
1981  var fname = 'Xdefsilent'
1982  writefile(lines, fname)
1983  var caught = 'no'
1984  try
1985    exe 'source ' .. fname
1986  catch /E1030:/
1987    caught = 'yes'
1988    assert_match('Func, line 4', v:throwpoint)
1989  endtry
1990  assert_equal('yes', caught)
1991  delete(fname)
1992enddef
1993
1994def Test_dict_member_with_silent()
1995  var lines =<< trim END
1996      vim9script
1997      g:result = 'none'
1998      var d: dict<any>
1999      def Func()
2000        try
2001          g:result = map([], {_, v -> {}[v]})->join() .. d['']
2002        catch
2003        endtry
2004      enddef
2005      silent! Func()
2006      assert_equal('0', g:result)
2007      unlet g:result
2008  END
2009  CheckScriptSuccess(lines)
2010enddef
2011
2012def Test_opfunc()
2013  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2014  def g:Opfunc(_: any): string
2015    setline(1, 'ASDF')
2016    return ''
2017  enddef
2018  new
2019  setline(1, 'asdf')
2020  feedkeys("\<F3>$", 'x')
2021  assert_equal('ASDF', getline(1))
2022
2023  bwipe!
2024  nunmap <F3>
2025enddef
2026
2027" this was crashing on exit
2028def Test_nested_lambda_in_closure()
2029  var lines =<< trim END
2030      vim9script
2031      def Outer()
2032          def g:Inner()
2033              echo map([1, 2, 3], {_, v -> v + 1})
2034          enddef
2035          g:Inner()
2036      enddef
2037      defcompile
2038      writefile(['Done'], 'XnestedDone')
2039      quit
2040  END
2041  if !RunVim([], lines, '--clean')
2042    return
2043  endif
2044  assert_equal(['Done'], readfile('XnestedDone'))
2045  delete('XnestedDone')
2046enddef
2047
2048
2049
2050" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
2051