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:')
99enddef
100
101func Test_call_default_args_from_func()
102  call assert_equal('string', MyDefaultArgs())
103  call assert_equal('one', MyDefaultArgs('one'))
104  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
105endfunc
106
107func TakesOneArg(arg)
108  echo a:arg
109endfunc
110
111def Test_call_wrong_args()
112  call CheckDefFailure(['TakesOneArg()'], 'E119:')
113  call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
114  call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
115enddef
116
117" Default arg and varargs
118def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
119  let res = one .. ',' .. two
120  for s in rest
121    res ..= ',' .. s
122  endfor
123  return res
124enddef
125
126def Test_call_def_varargs()
127  call assert_fails('call MyDefVarargs()', 'E119:')
128  assert_equal('one,foo', MyDefVarargs('one'))
129  assert_equal('one,two', MyDefVarargs('one', 'two'))
130  assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
131  call CheckDefFailure(['MyDefVarargs("one", 22)'], 'E1013: argument 2: type mismatch, expected string but got number')
132enddef
133
134let s:value = ''
135
136def FuncOneDefArg(opt = 'text')
137  s:value = opt
138enddef
139
140def FuncTwoDefArg(nr = 123, opt = 'text'): string
141  return nr .. opt
142enddef
143
144def FuncVarargs(...arg: list<string>): string
145  return join(arg, ',')
146enddef
147
148def Test_func_type_varargs()
149  let RefDefArg: func(?string)
150  RefDefArg = FuncOneDefArg
151  RefDefArg()
152  assert_equal('text', s:value)
153  RefDefArg('some')
154  assert_equal('some', s:value)
155
156  let RefDef2Arg: func(?number, ?string): string
157  RefDef2Arg = FuncTwoDefArg
158  assert_equal('123text', RefDef2Arg())
159  assert_equal('99text', RefDef2Arg(99))
160  assert_equal('77some', RefDef2Arg(77, 'some'))
161
162  call CheckDefFailure(['let RefWrong: func(string?)'], 'E1010:')
163  call CheckDefFailure(['let RefWrong: func(?string, string)'], 'E1007:')
164
165  let RefVarargs: func(...list<string>): string
166  RefVarargs = FuncVarargs
167  assert_equal('', RefVarargs())
168  assert_equal('one', RefVarargs('one'))
169  assert_equal('one,two', RefVarargs('one', 'two'))
170
171  call CheckDefFailure(['let RefWrong: func(...list<string>, string)'], 'E110:')
172  call CheckDefFailure(['let RefWrong: func(...list<string>, ?string)'], 'E110:')
173enddef
174
175" Only varargs
176def MyVarargsOnly(...args: list<string>): string
177  return join(args, ',')
178enddef
179
180def Test_call_varargs_only()
181  assert_equal('', MyVarargsOnly())
182  assert_equal('one', MyVarargsOnly('one'))
183  assert_equal('one,two', MyVarargsOnly('one', 'two'))
184  call CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: argument 1: type mismatch, expected string but got number')
185  call CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: argument 2: type mismatch, expected string but got number')
186enddef
187
188def Test_using_var_as_arg()
189  call writefile(['def Func(x: number)',  'let x = 234', 'enddef'], 'Xdef')
190  call assert_fails('so Xdef', 'E1006:')
191  call delete('Xdef')
192enddef
193
194def Test_call_func_defined_later()
195  call assert_equal('one', DefinedLater('one'))
196  call assert_fails('call NotDefined("one")', 'E117:')
197enddef
198
199func DefinedLater(arg)
200  return a:arg
201endfunc
202
203def FuncWithForwardCall()
204  return DefinedEvenLater("yes")
205enddef
206
207def DefinedEvenLater(arg: string): string
208  return arg
209enddef
210
211def Test_error_in_nested_function()
212  " Error in called function requires unwinding the call stack.
213  assert_fails('call FuncWithForwardCall()', 'E1029')
214enddef
215
216def Test_return_type_wrong()
217  CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
218  CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
219  CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string')
220  CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string')
221
222  CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
223
224  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
225  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
226  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
227enddef
228
229def Test_arg_type_wrong()
230  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
231  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
232enddef
233
234def Test_vim9script_call()
235  let lines =<< trim END
236    vim9script
237    let var = ''
238    def MyFunc(arg: string)
239       var = arg
240    enddef
241    MyFunc('foobar')
242    assert_equal('foobar', var)
243
244    let str = 'barfoo'
245    str->MyFunc()
246    assert_equal('barfoo', var)
247
248    let g:value = 'value'
249    g:value->MyFunc()
250    assert_equal('value', var)
251
252    let listvar = []
253    def ListFunc(arg: list<number>)
254       listvar = arg
255    enddef
256    [1, 2, 3]->ListFunc()
257    assert_equal([1, 2, 3], listvar)
258
259    let dictvar = {}
260    def DictFunc(arg: dict<number>)
261       dictvar = arg
262    enddef
263    {'a': 1, 'b': 2}->DictFunc()
264    assert_equal(#{a: 1, b: 2}, dictvar)
265    def CompiledDict()
266      {'a': 3, 'b': 4}->DictFunc()
267    enddef
268    CompiledDict()
269    assert_equal(#{a: 3, b: 4}, dictvar)
270
271    #{a: 3, b: 4}->DictFunc()
272    assert_equal(#{a: 3, b: 4}, dictvar)
273
274    ('text')->MyFunc()
275    assert_equal('text', var)
276    ("some")->MyFunc()
277    assert_equal('some', var)
278  END
279  writefile(lines, 'Xcall.vim')
280  source Xcall.vim
281  delete('Xcall.vim')
282enddef
283
284def Test_vim9script_call_fail_decl()
285  let lines =<< trim END
286    vim9script
287    let var = ''
288    def MyFunc(arg: string)
289       let var = 123
290    enddef
291  END
292  writefile(lines, 'Xcall_decl.vim')
293  assert_fails('source Xcall_decl.vim', 'E1054:')
294  delete('Xcall_decl.vim')
295enddef
296
297def Test_vim9script_call_fail_const()
298  let lines =<< trim END
299    vim9script
300    const var = ''
301    def MyFunc(arg: string)
302       var = 'asdf'
303    enddef
304  END
305  writefile(lines, 'Xcall_const.vim')
306  assert_fails('source Xcall_const.vim', 'E46:')
307  delete('Xcall_const.vim')
308enddef
309
310" Test that inside :function a Python function can be defined, :def is not
311" recognized.
312func Test_function_python()
313  CheckFeature python3
314  let py = 'python3'
315  execute py "<< EOF"
316def do_something():
317  return 1
318EOF
319endfunc
320
321def Test_delfunc()
322  let lines =<< trim END
323    vim9script
324    def GoneSoon()
325      echo 'hello'
326    enddef
327
328    def CallGoneSoon()
329      GoneSoon()
330    enddef
331
332    delfunc GoneSoon
333    CallGoneSoon()
334  END
335  writefile(lines, 'XToDelFunc')
336  assert_fails('so XToDelFunc', 'E933')
337  assert_fails('so XToDelFunc', 'E933')
338
339  delete('XToDelFunc')
340enddef
341
342def Test_redef_failure()
343  call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
344  so Xdef
345  call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
346  so Xdef
347  call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
348  call assert_fails('so Xdef', 'E1027:')
349  call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
350  so Xdef
351  call delete('Xdef')
352
353  call assert_equal(0, Func0())
354  call assert_equal('Func1', Func1())
355  call assert_equal('Func2', Func2())
356
357  delfunc! Func0
358  delfunc! Func1
359  delfunc! Func2
360enddef
361
362" Test for internal functions returning different types
363func Test_InternalFuncRetType()
364  let lines =<< trim END
365    def RetFloat(): float
366      return ceil(1.456)
367    enddef
368
369    def RetListAny(): list<any>
370      return items({'k' : 'v'})
371    enddef
372
373    def RetListString(): list<string>
374      return split('a:b:c', ':')
375    enddef
376
377    def RetListDictAny(): list<dict<any>>
378      return getbufinfo()
379    enddef
380
381    def RetDictNumber(): dict<number>
382      return wordcount()
383    enddef
384
385    def RetDictString(): dict<string>
386      return environ()
387    enddef
388  END
389  call writefile(lines, 'Xscript')
390  source Xscript
391
392  call assert_equal(2.0, RetFloat())
393  call assert_equal([['k', 'v']], RetListAny())
394  call assert_equal(['a', 'b', 'c'], RetListString())
395  call assert_notequal([], RetListDictAny())
396  call assert_notequal({}, RetDictNumber())
397  call assert_notequal({}, RetDictString())
398  call delete('Xscript')
399endfunc
400
401" Test for passing too many or too few arguments to internal functions
402func Test_internalfunc_arg_error()
403  let l =<< trim END
404    def! FArgErr(): float
405      return ceil(1.1, 2)
406    enddef
407  END
408  call writefile(l, 'Xinvalidarg')
409  call assert_fails('so Xinvalidarg', 'E118:')
410  let l =<< trim END
411    def! FArgErr(): float
412      return ceil()
413    enddef
414  END
415  call writefile(l, 'Xinvalidarg')
416  call assert_fails('so Xinvalidarg', 'E119:')
417  call delete('Xinvalidarg')
418endfunc
419
420let s:funcResult = 0
421
422def FuncNoArgNoRet()
423  funcResult = 11
424enddef
425
426def FuncNoArgRetNumber(): number
427  funcResult = 22
428  return 1234
429enddef
430
431def FuncNoArgRetString(): string
432  funcResult = 45
433  return 'text'
434enddef
435
436def FuncOneArgNoRet(arg: number)
437  funcResult = arg
438enddef
439
440def FuncOneArgRetNumber(arg: number): number
441  funcResult = arg
442  return arg
443enddef
444
445def FuncTwoArgNoRet(one: bool, two: number)
446  funcResult = two
447enddef
448
449def FuncOneArgRetString(arg: string): string
450  return arg
451enddef
452
453def FuncOneArgRetAny(arg: any): any
454  return arg
455enddef
456
457def Test_func_type()
458  let Ref1: func()
459  funcResult = 0
460  Ref1 = FuncNoArgNoRet
461  Ref1()
462  assert_equal(11, funcResult)
463
464  let Ref2: func
465  funcResult = 0
466  Ref2 = FuncNoArgNoRet
467  Ref2()
468  assert_equal(11, funcResult)
469
470  funcResult = 0
471  Ref2 = FuncOneArgNoRet
472  Ref2(12)
473  assert_equal(12, funcResult)
474
475  funcResult = 0
476  Ref2 = FuncNoArgRetNumber
477  assert_equal(1234, Ref2())
478  assert_equal(22, funcResult)
479
480  funcResult = 0
481  Ref2 = FuncOneArgRetNumber
482  assert_equal(13, Ref2(13))
483  assert_equal(13, funcResult)
484enddef
485
486def Test_func_type_part()
487  let RefVoid: func: void
488  RefVoid = FuncNoArgNoRet
489  RefVoid = FuncOneArgNoRet
490  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
491  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
492
493  let RefAny: func(): any
494  RefAny = FuncNoArgRetNumber
495  RefAny = FuncNoArgRetString
496  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
497  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
498
499  let RefNr: func: number
500  RefNr = FuncNoArgRetNumber
501  RefNr = FuncOneArgRetNumber
502  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
503  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
504
505  let RefStr: func: string
506  RefStr = FuncNoArgRetString
507  RefStr = FuncOneArgRetString
508  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
509  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
510enddef
511
512def Test_func_type_fails()
513  CheckDefFailure(['let ref1: func()'], 'E704:')
514
515  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
516  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)')
517  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number')
518  CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)')
519  CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)')
520  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)')
521
522  call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
523  call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
524  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:')
525  call CheckDefFailure(['let RefWrong: func(bool):string'], 'E1069:')
526enddef
527
528def Test_func_return_type()
529  let nr: number
530  nr = FuncNoArgRetNumber()
531  assert_equal(1234, nr)
532
533  nr = FuncOneArgRetAny(122)
534  assert_equal(122, nr)
535
536  let str: string
537  str = FuncOneArgRetAny('yes')
538  assert_equal('yes', str)
539
540  CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1013: type mismatch, expected string but got number')
541enddef
542
543" When using CheckScriptFailure() for the below test, E1010 is generated instead
544" of E1056.
545func Test_E1056_1059()
546  let caught_1056 = 0
547  try
548    def F():
549      return 1
550    enddef
551  catch /E1056:/
552    let caught_1056 = 1
553  endtry
554  call assert_equal(1, caught_1056)
555
556  let caught_1059 = 0
557  try
558    def F5(items : list)
559      echo 'a'
560    enddef
561  catch /E1059:/
562    let caught_1059 = 1
563  endtry
564  call assert_equal(1, caught_1059)
565endfunc
566
567" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
568