1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source view_util.vim
5
6" Check that "lines" inside ":def" results in an "error" message.
7func CheckDefFailure(lines, error)
8  call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef')
9  call assert_fails('so Xdef', a:error, a:lines)
10  call delete('Xdef')
11endfunc
12
13func CheckScriptFailure(lines, error)
14  call writefile(a:lines, 'Xdef')
15  call assert_fails('so Xdef', a:error, a:lines)
16  call delete('Xdef')
17endfunc
18
19func Test_def_basic()
20  def SomeFunc(): string
21    return 'yes'
22  enddef
23  call assert_equal('yes', SomeFunc())
24endfunc
25
26def ReturnString(): string
27  return 'string'
28enddef
29
30def ReturnNumber(): number
31  return 123
32enddef
33
34let g:notNumber = 'string'
35
36def ReturnGlobal(): number
37  return g:notNumber
38enddef
39
40def Test_return_something()
41  assert_equal('string', ReturnString())
42  assert_equal(123, ReturnNumber())
43  assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
44enddef
45
46let s:nothing = 0
47def ReturnNothing()
48  s:nothing = 1
49  if true
50    return
51  endif
52  s:nothing = 2
53enddef
54
55def Test_return_nothing()
56  ReturnNothing()
57  assert_equal(1, s:nothing)
58enddef
59
60func Increment()
61  let g:counter += 1
62endfunc
63
64def Test_call_ufunc_count()
65  g:counter = 1
66  Increment()
67  Increment()
68  Increment()
69  " works with and without :call
70  assert_equal(4, g:counter)
71  call assert_equal(4, g:counter)
72  unlet g:counter
73enddef
74
75def MyVarargs(arg: string, ...rest: list<string>): string
76  let res = arg
77  for s in rest
78    res ..= ',' .. s
79  endfor
80  return res
81enddef
82
83def Test_call_varargs()
84  assert_equal('one', MyVarargs('one'))
85  assert_equal('one,two', MyVarargs('one', 'two'))
86  assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
87enddef
88
89def MyDefaultArgs(name = 'string'): string
90  return name
91enddef
92
93def Test_call_default_args()
94  assert_equal('string', MyDefaultArgs())
95  assert_equal('one', MyDefaultArgs('one'))
96  assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
97
98  call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:')
99  call CheckScriptFailure(['def Func(arg: number = "text")', 'enddef'], 'E1013: argument 1: type mismatch, expected number but got string')
100enddef
101
102func Test_call_default_args_from_func()
103  call assert_equal('string', MyDefaultArgs())
104  call assert_equal('one', MyDefaultArgs('one'))
105  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
106endfunc
107
108func TakesOneArg(arg)
109  echo a:arg
110endfunc
111
112def Test_call_wrong_args()
113  call CheckDefFailure(['TakesOneArg()'], 'E119:')
114  call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
115  call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
116enddef
117
118" Default arg and varargs
119def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
120  let res = one .. ',' .. two
121  for s in rest
122    res ..= ',' .. s
123  endfor
124  return res
125enddef
126
127def Test_call_def_varargs()
128  call assert_fails('call MyDefVarargs()', 'E119:')
129  assert_equal('one,foo', MyDefVarargs('one'))
130  assert_equal('one,two', MyDefVarargs('one', 'two'))
131  assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
132  call CheckDefFailure(['MyDefVarargs("one", 22)'], 'E1013: argument 2: type mismatch, expected string but got number')
133enddef
134
135let s:value = ''
136
137def FuncOneDefArg(opt = 'text')
138  s:value = opt
139enddef
140
141def FuncTwoDefArg(nr = 123, opt = 'text'): string
142  return nr .. opt
143enddef
144
145def FuncVarargs(...arg: list<string>): string
146  return join(arg, ',')
147enddef
148
149def Test_func_type_varargs()
150  let RefDefArg: func(?string)
151  RefDefArg = FuncOneDefArg
152  RefDefArg()
153  assert_equal('text', s:value)
154  RefDefArg('some')
155  assert_equal('some', s:value)
156
157  let RefDef2Arg: func(?number, ?string): string
158  RefDef2Arg = FuncTwoDefArg
159  assert_equal('123text', RefDef2Arg())
160  assert_equal('99text', RefDef2Arg(99))
161  assert_equal('77some', RefDef2Arg(77, 'some'))
162
163  call CheckDefFailure(['let RefWrong: func(string?)'], 'E1010:')
164  call CheckDefFailure(['let RefWrong: func(?string, string)'], 'E1007:')
165
166  let RefVarargs: func(...list<string>): string
167  RefVarargs = FuncVarargs
168  assert_equal('', RefVarargs())
169  assert_equal('one', RefVarargs('one'))
170  assert_equal('one,two', RefVarargs('one', 'two'))
171
172  call CheckDefFailure(['let RefWrong: func(...list<string>, string)'], 'E110:')
173  call CheckDefFailure(['let RefWrong: func(...list<string>, ?string)'], 'E110:')
174enddef
175
176" Only varargs
177def MyVarargsOnly(...args: list<string>): string
178  return join(args, ',')
179enddef
180
181def Test_call_varargs_only()
182  assert_equal('', MyVarargsOnly())
183  assert_equal('one', MyVarargsOnly('one'))
184  assert_equal('one,two', MyVarargsOnly('one', 'two'))
185  call CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: argument 1: type mismatch, expected string but got number')
186  call CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: argument 2: type mismatch, expected string but got number')
187enddef
188
189def Test_using_var_as_arg()
190  call writefile(['def Func(x: number)',  'let x = 234', 'enddef'], 'Xdef')
191  call assert_fails('so Xdef', 'E1006:')
192  call delete('Xdef')
193enddef
194
195def Test_call_func_defined_later()
196  call assert_equal('one', g:DefinedLater('one'))
197  call assert_fails('call NotDefined("one")', 'E117:')
198enddef
199
200func DefinedLater(arg)
201  return a:arg
202endfunc
203
204def Test_call_funcref()
205  assert_equal(3, g:SomeFunc('abc'))
206  assert_fails('NotAFunc()', 'E117:')
207  assert_fails('g:NotAFunc()', 'E117:')
208enddef
209
210let SomeFunc = function('len')
211let NotAFunc = 'text'
212
213def CombineFuncrefTypes()
214  " same arguments, different return type
215  let Ref1: func(bool): string
216  let Ref2: func(bool): number
217  let Ref3: func(bool): any
218  Ref3 = g:cond ? Ref1 : Ref2
219
220  " different number of arguments
221  let Refa1: func(bool): number
222  let Refa2: func(bool, number): number
223  let Refa3: func: number
224  Refa3 = g:cond ? Refa1 : Refa2
225
226  " different argument types
227  let Refb1: func(bool, string): number
228  let Refb2: func(string, number): number
229  let Refb3: func(any, any): number
230  Refb3 = g:cond ? Refb1 : Refb2
231enddef
232
233def FuncWithForwardCall()
234  return g:DefinedEvenLater("yes")
235enddef
236
237def DefinedEvenLater(arg: string): string
238  return arg
239enddef
240
241def Test_error_in_nested_function()
242  " Error in called function requires unwinding the call stack.
243  assert_fails('call FuncWithForwardCall()', 'E1029')
244enddef
245
246def Test_return_type_wrong()
247  CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
248  CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
249  CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string')
250  CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string')
251
252  CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
253
254  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
255  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
256  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
257enddef
258
259def Test_arg_type_wrong()
260  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
261  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
262  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
263  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
264enddef
265
266def Test_vim9script_call()
267  let lines =<< trim END
268    vim9script
269    let var = ''
270    def MyFunc(arg: string)
271       var = arg
272    enddef
273    MyFunc('foobar')
274    assert_equal('foobar', var)
275
276    let str = 'barfoo'
277    str->MyFunc()
278    assert_equal('barfoo', var)
279
280    let g:value = 'value'
281    g:value->MyFunc()
282    assert_equal('value', var)
283
284    let listvar = []
285    def ListFunc(arg: list<number>)
286       listvar = arg
287    enddef
288    [1, 2, 3]->ListFunc()
289    assert_equal([1, 2, 3], listvar)
290
291    let dictvar = {}
292    def DictFunc(arg: dict<number>)
293       dictvar = arg
294    enddef
295    {'a': 1, 'b': 2}->DictFunc()
296    assert_equal(#{a: 1, b: 2}, dictvar)
297    def CompiledDict()
298      {'a': 3, 'b': 4}->DictFunc()
299    enddef
300    CompiledDict()
301    assert_equal(#{a: 3, b: 4}, dictvar)
302
303    #{a: 3, b: 4}->DictFunc()
304    assert_equal(#{a: 3, b: 4}, dictvar)
305
306    ('text')->MyFunc()
307    assert_equal('text', var)
308    ("some")->MyFunc()
309    assert_equal('some', var)
310  END
311  writefile(lines, 'Xcall.vim')
312  source Xcall.vim
313  delete('Xcall.vim')
314enddef
315
316def Test_vim9script_call_fail_decl()
317  let lines =<< trim END
318    vim9script
319    let var = ''
320    def MyFunc(arg: string)
321       let var = 123
322    enddef
323  END
324  writefile(lines, 'Xcall_decl.vim')
325  assert_fails('source Xcall_decl.vim', 'E1054:')
326  delete('Xcall_decl.vim')
327enddef
328
329def Test_vim9script_call_fail_const()
330  let lines =<< trim END
331    vim9script
332    const var = ''
333    def MyFunc(arg: string)
334       var = 'asdf'
335    enddef
336  END
337  writefile(lines, 'Xcall_const.vim')
338  assert_fails('source Xcall_const.vim', 'E46:')
339  delete('Xcall_const.vim')
340enddef
341
342" Test that inside :function a Python function can be defined, :def is not
343" recognized.
344func Test_function_python()
345  CheckFeature python3
346  let py = 'python3'
347  execute py "<< EOF"
348def do_something():
349  return 1
350EOF
351endfunc
352
353def Test_delfunc()
354  let lines =<< trim END
355    vim9script
356    def GoneSoon()
357      echo 'hello'
358    enddef
359
360    def CallGoneSoon()
361      GoneSoon()
362    enddef
363
364    delfunc GoneSoon
365    CallGoneSoon()
366  END
367  writefile(lines, 'XToDelFunc')
368  assert_fails('so XToDelFunc', 'E933')
369  assert_fails('so XToDelFunc', 'E933')
370
371  delete('XToDelFunc')
372enddef
373
374def Test_redef_failure()
375  call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
376  so Xdef
377  call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
378  so Xdef
379  call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
380  call assert_fails('so Xdef', 'E1027:')
381  call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
382  so Xdef
383  call delete('Xdef')
384
385  call assert_equal(0, g:Func0())
386  call assert_equal('Func1', g:Func1())
387  call assert_equal('Func2', g:Func2())
388
389  delfunc! Func0
390  delfunc! Func1
391  delfunc! Func2
392enddef
393
394def Test_vim9script_func()
395  let lines =<< trim END
396    vim9script
397    func Func(arg)
398      echo a:arg
399    endfunc
400    Func('text')
401  END
402  writefile(lines, 'XVim9Func')
403  so XVim9Func
404
405  delete('XVim9Func')
406enddef
407
408" Test for internal functions returning different types
409func Test_InternalFuncRetType()
410  let lines =<< trim END
411    def RetFloat(): float
412      return ceil(1.456)
413    enddef
414
415    def RetListAny(): list<any>
416      return items({'k' : 'v'})
417    enddef
418
419    def RetListString(): list<string>
420      return split('a:b:c', ':')
421    enddef
422
423    def RetListDictAny(): list<dict<any>>
424      return getbufinfo()
425    enddef
426
427    def RetDictNumber(): dict<number>
428      return wordcount()
429    enddef
430
431    def RetDictString(): dict<string>
432      return environ()
433    enddef
434  END
435  call writefile(lines, 'Xscript')
436  source Xscript
437
438  call assert_equal(2.0, RetFloat())
439  call assert_equal([['k', 'v']], RetListAny())
440  call assert_equal(['a', 'b', 'c'], RetListString())
441  call assert_notequal([], RetListDictAny())
442  call assert_notequal({}, RetDictNumber())
443  call assert_notequal({}, RetDictString())
444  call delete('Xscript')
445endfunc
446
447" Test for passing too many or too few arguments to internal functions
448func Test_internalfunc_arg_error()
449  let l =<< trim END
450    def! FArgErr(): float
451      return ceil(1.1, 2)
452    enddef
453  END
454  call writefile(l, 'Xinvalidarg')
455  call assert_fails('so Xinvalidarg', 'E118:')
456  let l =<< trim END
457    def! FArgErr(): float
458      return ceil()
459    enddef
460  END
461  call writefile(l, 'Xinvalidarg')
462  call assert_fails('so Xinvalidarg', 'E119:')
463  call delete('Xinvalidarg')
464endfunc
465
466let s:funcResult = 0
467
468def FuncNoArgNoRet()
469  funcResult = 11
470enddef
471
472def FuncNoArgRetNumber(): number
473  funcResult = 22
474  return 1234
475enddef
476
477def FuncNoArgRetString(): string
478  funcResult = 45
479  return 'text'
480enddef
481
482def FuncOneArgNoRet(arg: number)
483  funcResult = arg
484enddef
485
486def FuncOneArgRetNumber(arg: number): number
487  funcResult = arg
488  return arg
489enddef
490
491def FuncTwoArgNoRet(one: bool, two: number)
492  funcResult = two
493enddef
494
495def FuncOneArgRetString(arg: string): string
496  return arg
497enddef
498
499def FuncOneArgRetAny(arg: any): any
500  return arg
501enddef
502
503def Test_func_type()
504  let Ref1: func()
505  funcResult = 0
506  Ref1 = FuncNoArgNoRet
507  Ref1()
508  assert_equal(11, funcResult)
509
510  let Ref2: func
511  funcResult = 0
512  Ref2 = FuncNoArgNoRet
513  Ref2()
514  assert_equal(11, funcResult)
515
516  funcResult = 0
517  Ref2 = FuncOneArgNoRet
518  Ref2(12)
519  assert_equal(12, funcResult)
520
521  funcResult = 0
522  Ref2 = FuncNoArgRetNumber
523  assert_equal(1234, Ref2())
524  assert_equal(22, funcResult)
525
526  funcResult = 0
527  Ref2 = FuncOneArgRetNumber
528  assert_equal(13, Ref2(13))
529  assert_equal(13, funcResult)
530enddef
531
532def Test_func_type_part()
533  let RefVoid: func: void
534  RefVoid = FuncNoArgNoRet
535  RefVoid = FuncOneArgNoRet
536  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
537  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
538
539  let RefAny: func(): any
540  RefAny = FuncNoArgRetNumber
541  RefAny = FuncNoArgRetString
542  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
543  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
544
545  let RefNr: func: number
546  RefNr = FuncNoArgRetNumber
547  RefNr = FuncOneArgRetNumber
548  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
549  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
550
551  let RefStr: func: string
552  RefStr = FuncNoArgRetString
553  RefStr = FuncOneArgRetString
554  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
555  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
556enddef
557
558def Test_func_type_fails()
559  CheckDefFailure(['let ref1: func()'], 'E704:')
560
561  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
562  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)')
563  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number')
564  CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)')
565  CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)')
566  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)')
567
568  call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
569  call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
570  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:')
571  call CheckDefFailure(['let RefWrong: func(bool):string'], 'E1069:')
572enddef
573
574def Test_func_return_type()
575  let nr: number
576  nr = FuncNoArgRetNumber()
577  assert_equal(1234, nr)
578
579  nr = FuncOneArgRetAny(122)
580  assert_equal(122, nr)
581
582  let str: string
583  str = FuncOneArgRetAny('yes')
584  assert_equal('yes', str)
585
586  CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1013: type mismatch, expected string but got number')
587enddef
588
589def MultiLine(
590    arg1: string,
591    arg2 = 1234,
592    ...rest: list<string>
593      ): string
594  return arg1 .. arg2 .. join(rest, '-')
595enddef
596
597def MultiLineComment(
598    arg1: string, # comment
599    arg2 = 1234, # comment
600    ...rest: list<string> # comment
601      ): string # comment
602  return arg1 .. arg2 .. join(rest, '-')
603enddef
604
605def Test_multiline()
606  assert_equal('text1234', MultiLine('text'))
607  assert_equal('text777', MultiLine('text', 777))
608  assert_equal('text777one', MultiLine('text', 777, 'one'))
609  assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
610enddef
611
612func Test_multiline_not_vim9()
613  call assert_equal('text1234', MultiLine('text'))
614  call assert_equal('text777', MultiLine('text', 777))
615  call assert_equal('text777one', MultiLine('text', 777, 'one'))
616  call assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
617endfunc
618
619
620" When using CheckScriptFailure() for the below test, E1010 is generated instead
621" of E1056.
622func Test_E1056_1059()
623  let caught_1056 = 0
624  try
625    def F():
626      return 1
627    enddef
628  catch /E1056:/
629    let caught_1056 = 1
630  endtry
631  call assert_equal(1, caught_1056)
632
633  let caught_1059 = 0
634  try
635    def F5(items : list)
636      echo 'a'
637    enddef
638  catch /E1059:/
639    let caught_1059 = 1
640  endtry
641  call assert_equal(1, caught_1059)
642endfunc
643
644" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
645