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