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