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, 'E1012:')
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, 'E1012:')
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, 'E1012:')
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, 'E1012: 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, 'E1012: 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'], 'E1012: type mismatch, expected func() but got func(): number')
923  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: 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'], 'E1012: type mismatch, expected func(): any but got func()')
929  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: 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'], 'E1012: type mismatch, expected func(): number but got func()')
935  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: 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'], 'E1012: type mismatch, expected func(): string but got func()')
941  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: 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'], 'E1012: type mismatch, expected func() but got func(): number')
948  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: type mismatch, expected func() but got func(number)')
949  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: type mismatch, expected func() but got func(number): number')
950  CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(bool) but got func(bool, number)')
951  CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(?bool) but got func(bool, number)')
952  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: 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)'], 'E1005:')
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()'], 'E1012: 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    assert_report('should have failed')
1049  catch /E476:/
1050    assert_match('Invalid command: invalid', v:exception)
1051    assert_match(', line 3$', v:throwpoint)
1052  endtry
1053
1054  # comment lines after the start of the function
1055  lines =<< trim END
1056    " comment
1057    def Func()
1058      let x = 1234
1059      # comment
1060      # comment
1061      invalid
1062    enddef
1063    defcompile
1064  END
1065  call writefile(lines, 'Xdef')
1066  try
1067    source Xdef
1068    assert_report('should have failed')
1069  catch /E476:/
1070    assert_match('Invalid command: invalid', v:exception)
1071    assert_match(', line 4$', v:throwpoint)
1072  endtry
1073
1074  lines =<< trim END
1075    vim9script
1076    def Func()
1077      let db = #{foo: 1, bar: 2}
1078      # comment
1079      let x = db.asdf
1080    enddef
1081    defcompile
1082    Func()
1083  END
1084  call writefile(lines, 'Xdef')
1085  try
1086    source Xdef
1087    assert_report('should have failed')
1088  catch /E716:/
1089    assert_match('_Func, line 3$', v:throwpoint)
1090  endtry
1091
1092  call delete('Xdef')
1093enddef
1094
1095def Test_deleted_function()
1096  CheckDefExecFailure([
1097      'let RefMe: func = function("g:DelMe")',
1098      'delfunc g:DelMe',
1099      'echo RefMe()'], 'E117:')
1100enddef
1101
1102def Test_unknown_function()
1103  CheckDefExecFailure([
1104      'let Ref: func = function("NotExist")',
1105      'delfunc g:NotExist'], 'E700:')
1106enddef
1107
1108def RefFunc(Ref: func(string): string): string
1109  return Ref('more')
1110enddef
1111
1112def Test_closure_simple()
1113  let local = 'some '
1114  assert_equal('some more', RefFunc({s -> local .. s}))
1115enddef
1116
1117def MakeRef()
1118  let local = 'some '
1119  g:Ref = {s -> local .. s}
1120enddef
1121
1122def Test_closure_ref_after_return()
1123  MakeRef()
1124  assert_equal('some thing', g:Ref('thing'))
1125  unlet g:Ref
1126enddef
1127
1128def MakeTwoRefs()
1129  let local = ['some']
1130  g:Extend = {s -> local->add(s)}
1131  g:Read = {-> local}
1132enddef
1133
1134def Test_closure_two_refs()
1135  MakeTwoRefs()
1136  assert_equal('some', join(g:Read(), ' '))
1137  g:Extend('more')
1138  assert_equal('some more', join(g:Read(), ' '))
1139  g:Extend('even')
1140  assert_equal('some more even', join(g:Read(), ' '))
1141
1142  unlet g:Extend
1143  unlet g:Read
1144enddef
1145
1146def ReadRef(Ref: func(): list<string>): string
1147  return join(Ref(), ' ')
1148enddef
1149
1150def ExtendRef(Ref: func(string), add: string)
1151  Ref(add)
1152enddef
1153
1154def Test_closure_two_indirect_refs()
1155  MakeTwoRefs()
1156  assert_equal('some', ReadRef(g:Read))
1157  ExtendRef(g:Extend, 'more')
1158  assert_equal('some more', ReadRef(g:Read))
1159  ExtendRef(g:Extend, 'even')
1160  assert_equal('some more even', ReadRef(g:Read))
1161
1162  unlet g:Extend
1163  unlet g:Read
1164enddef
1165
1166def MakeArgRefs(theArg: string)
1167  let local = 'loc_val'
1168  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
1169enddef
1170
1171def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1172  let local = 'the_loc'
1173  g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)}
1174enddef
1175
1176def Test_closure_using_argument()
1177  MakeArgRefs('arg_val')
1178  assert_equal('arg_val/loc_val/call_val', g:UseArg('call_val'))
1179
1180  MakeArgRefsVarargs('arg_val', 'one', 'two')
1181  assert_equal('arg_val/the_loc/call_val/one two', g:UseVararg('call_val'))
1182
1183  unlet g:UseArg
1184  unlet g:UseVararg
1185enddef
1186
1187def MakeGetAndAppendRefs()
1188  let local = 'a'
1189
1190  def Append(arg: string)
1191    local ..= arg
1192  enddef
1193  g:Append = Append
1194
1195  def Get(): string
1196    return local
1197  enddef
1198  g:Get = Get
1199enddef
1200
1201def Test_closure_append_get()
1202  MakeGetAndAppendRefs()
1203  assert_equal('a', g:Get())
1204  g:Append('-b')
1205  assert_equal('a-b', g:Get())
1206  g:Append('-c')
1207  assert_equal('a-b-c', g:Get())
1208
1209  unlet g:Append
1210  unlet g:Get
1211enddef
1212
1213def Test_nested_closure()
1214  let local = 'text'
1215  def Closure(arg: string): string
1216    return local .. arg
1217  enddef
1218  assert_equal('text!!!', Closure('!!!'))
1219enddef
1220
1221func GetResult(Ref)
1222  return a:Ref('some')
1223endfunc
1224
1225def Test_call_closure_not_compiled()
1226  let text = 'text'
1227  g:Ref = {s ->  s .. text}
1228  assert_equal('sometext', GetResult(g:Ref))
1229enddef
1230
1231def Test_sort_return_type()
1232  let res: list<number>
1233  res = [1, 2, 3]->sort()
1234enddef
1235
1236def Test_getqflist_return_type()
1237  let l = getqflist()
1238  assert_equal([], l)
1239
1240  let d = getqflist(#{items: 0})
1241  assert_equal(#{items: []}, d)
1242enddef
1243
1244def Test_getloclist_return_type()
1245  let l = getloclist(1)
1246  assert_equal([], l)
1247
1248  let d = getloclist(1, #{items: 0})
1249  assert_equal(#{items: []}, d)
1250enddef
1251
1252def Test_copy_return_type()
1253  let l = copy([1, 2, 3])
1254  let res = 0
1255  for n in l
1256    res += n
1257  endfor
1258  assert_equal(6, res)
1259
1260  let dl = deepcopy([1, 2, 3])
1261  res = 0
1262  for n in dl
1263    res += n
1264  endfor
1265  assert_equal(6, res)
1266enddef
1267
1268def Test_extend_return_type()
1269  let l = extend([1, 2], [3])
1270  let res = 0
1271  for n in l
1272    res += n
1273  endfor
1274  assert_equal(6, res)
1275enddef
1276
1277def Test_insert_return_type()
1278  let l = insert([2, 1], 3)
1279  let res = 0
1280  for n in l
1281    res += n
1282  endfor
1283  assert_equal(6, res)
1284enddef
1285
1286def Test_keys_return_type()
1287  const var: list<string> = #{a: 1, b: 2}->keys()
1288  assert_equal(['a', 'b'], var)
1289enddef
1290
1291def Test_reverse_return_type()
1292  let l = reverse([1, 2, 3])
1293  let res = 0
1294  for n in l
1295    res += n
1296  endfor
1297  assert_equal(6, res)
1298enddef
1299
1300def Test_remove_return_type()
1301  let l = remove(#{one: [1, 2], two: [3, 4]}, 'one')
1302  let res = 0
1303  for n in l
1304    res += n
1305  endfor
1306  assert_equal(3, res)
1307enddef
1308
1309def Test_filter_return_type()
1310  let l = filter([1, 2, 3], {-> 1})
1311  let res = 0
1312  for n in l
1313    res += n
1314  endfor
1315  assert_equal(6, res)
1316enddef
1317
1318def Test_bufnr()
1319  let buf = bufnr()
1320  assert_equal(buf, bufnr('%'))
1321enddef
1322
1323def Test_getreg_return_type()
1324  let s1: string = getreg('"')
1325  let s2: string = getreg('"', 1)
1326  let s3: list<string> = getreg('"', 1, 1)
1327enddef
1328
1329def Wrong_dict_key_type(items: list<number>): list<number>
1330  return filter(items, {_, val -> get({val: 1}, 'x')})
1331enddef
1332
1333def Test_wrong_dict_key_type()
1334  assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1029:')
1335enddef
1336
1337def Line_continuation_in_def(dir: string = ''): string
1338    let path: string = empty(dir)
1339            \ ? 'empty'
1340            \ : 'full'
1341    return path
1342enddef
1343
1344def Test_line_continuation_in_def()
1345  assert_equal('full', Line_continuation_in_def('.'))
1346enddef
1347
1348def Line_continuation_in_lambda(): list<number>
1349  let x = range(97, 100)
1350      ->map({_, v -> nr2char(v)
1351          ->toupper()})
1352      ->reverse()
1353  return x
1354enddef
1355
1356def Test_line_continuation_in_lambda()
1357  assert_equal(['D', 'C', 'B', 'A'], Line_continuation_in_lambda())
1358enddef
1359
1360func Test_silent_echo()
1361  CheckScreendump
1362
1363  let lines =<< trim END
1364    vim9script
1365    def EchoNothing()
1366      silent echo ''
1367    enddef
1368    defcompile
1369  END
1370  call writefile(lines, 'XTest_silent_echo')
1371
1372  " Check that the balloon shows up after a mouse move
1373  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1374  call term_sendkeys(buf, ":abc")
1375  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1376
1377  " clean up
1378  call StopVimInTerminal(buf)
1379  call delete('XTest_silent_echo')
1380endfunc
1381
1382def Test_search()
1383  new
1384  setline(1, ['foo', 'bar'])
1385  let val = 0
1386  assert_equal(2, search('bar', 'W', 0, 0, {-> val == 1}))
1387enddef
1388
1389def Test_readdir()
1390   eval expand('.')->readdir({e -> e[0] !=# '.'})
1391   eval expand('.')->readdirex({e -> e.name[0] !=# '.'})
1392enddef
1393
1394def Fibonacci(n: number): number
1395  if n < 2
1396    return n
1397  else
1398    return Fibonacci(n - 1) + Fibonacci(n - 2)
1399  endif
1400enddef
1401
1402def Test_recursive_call()
1403  assert_equal(6765, Fibonacci(20))
1404enddef
1405
1406def TreeWalk(dir: string): list<any>
1407  return readdir(dir)->map({_, val ->
1408            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
1409               ? {val: TreeWalk(dir .. '/' .. val)}
1410               : val
1411             })
1412enddef
1413
1414def Test_closure_in_map()
1415  mkdir('XclosureDir/tdir', 'p')
1416  writefile(['111'], 'XclosureDir/file1')
1417  writefile(['222'], 'XclosureDir/file2')
1418  writefile(['333'], 'XclosureDir/tdir/file3')
1419
1420  assert_equal(['file1', 'file2', {'tdir': ['file3']}], TreeWalk('XclosureDir'))
1421
1422  delete('XclosureDir', 'rf')
1423enddef
1424
1425def Test_partial_call()
1426  let Xsetlist = function('setloclist', [0])
1427  Xsetlist([], ' ', {'title': 'test'})
1428  assert_equal({'title': 'test'}, getloclist(0, {'title': 1}))
1429
1430  Xsetlist = function('setloclist', [0, [], ' '])
1431  Xsetlist({'title': 'test'})
1432  assert_equal({'title': 'test'}, getloclist(0, {'title': 1}))
1433
1434  Xsetlist = function('setqflist')
1435  Xsetlist([], ' ', {'title': 'test'})
1436  assert_equal({'title': 'test'}, getqflist({'title': 1}))
1437
1438  Xsetlist = function('setqflist', [[], ' '])
1439  Xsetlist({'title': 'test'})
1440  assert_equal({'title': 'test'}, getqflist({'title': 1}))
1441enddef
1442
1443def Test_cmd_modifier()
1444  tab echo '0'
1445  call CheckDefFailure(['5tab echo 3'], 'E16:')
1446enddef
1447
1448def Test_restore_modifiers()
1449  # check that when compiling a :def function command modifiers are not messed
1450  # up.
1451  let lines =<< trim END
1452      vim9script
1453      set eventignore=
1454      autocmd QuickFixCmdPost * copen
1455      def AutocmdsDisabled()
1456          eval 0
1457      enddef
1458      func Func()
1459        noautocmd call s:AutocmdsDisabled()
1460        let g:ei_after = &eventignore
1461      endfunc
1462      Func()
1463  END
1464  CheckScriptSuccess(lines)
1465  assert_equal('', g:ei_after)
1466enddef
1467
1468
1469" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
1470