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