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