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