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