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 FuncOneArgRetString(arg: string): string
446  return arg
447enddef
448
449def FuncOneArgRetAny(arg: any): any
450  return arg
451enddef
452
453def Test_func_type()
454  let Ref1: func()
455  funcResult = 0
456  Ref1 = FuncNoArgNoRet
457  Ref1()
458  assert_equal(11, funcResult)
459
460  let Ref2: func
461  funcResult = 0
462  Ref2 = FuncNoArgNoRet
463  Ref2()
464  assert_equal(11, funcResult)
465
466  funcResult = 0
467  Ref2 = FuncOneArgNoRet
468  Ref2(12)
469  assert_equal(12, funcResult)
470
471  funcResult = 0
472  Ref2 = FuncNoArgRetNumber
473  assert_equal(1234, Ref2())
474  assert_equal(22, funcResult)
475
476  funcResult = 0
477  Ref2 = FuncOneArgRetNumber
478  assert_equal(13, Ref2(13))
479  assert_equal(13, funcResult)
480enddef
481
482def Test_func_type_part()
483  let RefVoid: func: void
484  RefVoid = FuncNoArgNoRet
485  RefVoid = FuncOneArgNoRet
486  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
487  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
488
489  let RefAny: func(): any
490  RefAny = FuncNoArgRetNumber
491  RefAny = FuncNoArgRetString
492  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
493  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
494
495  let RefNr: func: number
496  RefNr = FuncNoArgRetNumber
497  RefNr = FuncOneArgRetNumber
498  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
499  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
500
501  let RefStr: func: string
502  RefStr = FuncNoArgRetString
503  RefStr = FuncOneArgRetString
504  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
505  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
506enddef
507
508def Test_func_type_fails()
509  CheckDefFailure(['let ref1: func()'], 'E704:')
510
511  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
512  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)')
513  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number')
514enddef
515
516def Test_func_return_type()
517  let nr: number
518  nr = FuncNoArgRetNumber()
519  assert_equal(1234, nr)
520
521  nr = FuncOneArgRetAny(122)
522  assert_equal(122, nr)
523
524  let str: string
525  str = FuncOneArgRetAny('yes')
526  assert_equal('yes', str)
527
528  CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1013: type mismatch, expected string but got number')
529enddef
530
531" When using CheckScriptFailure() for the below test, E1010 is generated instead
532" of E1056.
533func Test_E1056_1059()
534  let caught_1056 = 0
535  try
536    def F():
537      return 1
538    enddef
539  catch /E1056:/
540    let caught_1056 = 1
541  endtry
542  call assert_equal(1, caught_1056)
543
544  let caught_1059 = 0
545  try
546    def F5(items : list)
547      echo 'a'
548    enddef
549  catch /E1059:/
550    let caught_1059 = 1
551  endtry
552  call assert_equal(1, caught_1059)
553endfunc
554
555" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
556