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