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