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