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', DefinedLater('one'))
197  call assert_fails('call NotDefined("one")', 'E117:')
198enddef
199
200def CombineFuncrefTypes()
201  " same arguments, different return type
202  let Ref1: func(bool): string
203  let Ref2: func(bool): number
204  let Ref3: func(bool): any
205  Ref3 = g:cond ? Ref1 : Ref2
206
207  " different number of arguments
208  let Refa1: func(bool): number
209  let Refa2: func(bool, number): number
210  let Refa3: func: number
211  Refa3 = g:cond ? Refa1 : Refa2
212
213  " different argument types
214  let Refb1: func(bool, string): number
215  let Refb2: func(string, number): number
216  let Refb3: func(any, any): number
217  Refb3 = g:cond ? Refb1 : Refb2
218enddef
219
220func DefinedLater(arg)
221  return a:arg
222endfunc
223
224def FuncWithForwardCall()
225  return DefinedEvenLater("yes")
226enddef
227
228def DefinedEvenLater(arg: string): string
229  return arg
230enddef
231
232def Test_error_in_nested_function()
233  " Error in called function requires unwinding the call stack.
234  assert_fails('call FuncWithForwardCall()', 'E1029')
235enddef
236
237def Test_return_type_wrong()
238  CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
239  CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
240  CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string')
241  CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string')
242
243  CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
244
245  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
246  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
247  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
248enddef
249
250def Test_arg_type_wrong()
251  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
252  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
253enddef
254
255def Test_vim9script_call()
256  let lines =<< trim END
257    vim9script
258    let var = ''
259    def MyFunc(arg: string)
260       var = arg
261    enddef
262    MyFunc('foobar')
263    assert_equal('foobar', var)
264
265    let str = 'barfoo'
266    str->MyFunc()
267    assert_equal('barfoo', var)
268
269    let g:value = 'value'
270    g:value->MyFunc()
271    assert_equal('value', var)
272
273    let listvar = []
274    def ListFunc(arg: list<number>)
275       listvar = arg
276    enddef
277    [1, 2, 3]->ListFunc()
278    assert_equal([1, 2, 3], listvar)
279
280    let dictvar = {}
281    def DictFunc(arg: dict<number>)
282       dictvar = arg
283    enddef
284    {'a': 1, 'b': 2}->DictFunc()
285    assert_equal(#{a: 1, b: 2}, dictvar)
286    def CompiledDict()
287      {'a': 3, 'b': 4}->DictFunc()
288    enddef
289    CompiledDict()
290    assert_equal(#{a: 3, b: 4}, dictvar)
291
292    #{a: 3, b: 4}->DictFunc()
293    assert_equal(#{a: 3, b: 4}, dictvar)
294
295    ('text')->MyFunc()
296    assert_equal('text', var)
297    ("some")->MyFunc()
298    assert_equal('some', var)
299  END
300  writefile(lines, 'Xcall.vim')
301  source Xcall.vim
302  delete('Xcall.vim')
303enddef
304
305def Test_vim9script_call_fail_decl()
306  let lines =<< trim END
307    vim9script
308    let var = ''
309    def MyFunc(arg: string)
310       let var = 123
311    enddef
312  END
313  writefile(lines, 'Xcall_decl.vim')
314  assert_fails('source Xcall_decl.vim', 'E1054:')
315  delete('Xcall_decl.vim')
316enddef
317
318def Test_vim9script_call_fail_const()
319  let lines =<< trim END
320    vim9script
321    const var = ''
322    def MyFunc(arg: string)
323       var = 'asdf'
324    enddef
325  END
326  writefile(lines, 'Xcall_const.vim')
327  assert_fails('source Xcall_const.vim', 'E46:')
328  delete('Xcall_const.vim')
329enddef
330
331" Test that inside :function a Python function can be defined, :def is not
332" recognized.
333func Test_function_python()
334  CheckFeature python3
335  let py = 'python3'
336  execute py "<< EOF"
337def do_something():
338  return 1
339EOF
340endfunc
341
342def Test_delfunc()
343  let lines =<< trim END
344    vim9script
345    def GoneSoon()
346      echo 'hello'
347    enddef
348
349    def CallGoneSoon()
350      GoneSoon()
351    enddef
352
353    delfunc GoneSoon
354    CallGoneSoon()
355  END
356  writefile(lines, 'XToDelFunc')
357  assert_fails('so XToDelFunc', 'E933')
358  assert_fails('so XToDelFunc', 'E933')
359
360  delete('XToDelFunc')
361enddef
362
363def Test_redef_failure()
364  call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
365  so Xdef
366  call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
367  so Xdef
368  call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
369  call assert_fails('so Xdef', 'E1027:')
370  call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
371  so Xdef
372  call delete('Xdef')
373
374  call assert_equal(0, Func0())
375  call assert_equal('Func1', Func1())
376  call assert_equal('Func2', Func2())
377
378  delfunc! Func0
379  delfunc! Func1
380  delfunc! Func2
381enddef
382
383" Test for internal functions returning different types
384func Test_InternalFuncRetType()
385  let lines =<< trim END
386    def RetFloat(): float
387      return ceil(1.456)
388    enddef
389
390    def RetListAny(): list<any>
391      return items({'k' : 'v'})
392    enddef
393
394    def RetListString(): list<string>
395      return split('a:b:c', ':')
396    enddef
397
398    def RetListDictAny(): list<dict<any>>
399      return getbufinfo()
400    enddef
401
402    def RetDictNumber(): dict<number>
403      return wordcount()
404    enddef
405
406    def RetDictString(): dict<string>
407      return environ()
408    enddef
409  END
410  call writefile(lines, 'Xscript')
411  source Xscript
412
413  call assert_equal(2.0, RetFloat())
414  call assert_equal([['k', 'v']], RetListAny())
415  call assert_equal(['a', 'b', 'c'], RetListString())
416  call assert_notequal([], RetListDictAny())
417  call assert_notequal({}, RetDictNumber())
418  call assert_notequal({}, RetDictString())
419  call delete('Xscript')
420endfunc
421
422" Test for passing too many or too few arguments to internal functions
423func Test_internalfunc_arg_error()
424  let l =<< trim END
425    def! FArgErr(): float
426      return ceil(1.1, 2)
427    enddef
428  END
429  call writefile(l, 'Xinvalidarg')
430  call assert_fails('so Xinvalidarg', 'E118:')
431  let l =<< trim END
432    def! FArgErr(): float
433      return ceil()
434    enddef
435  END
436  call writefile(l, 'Xinvalidarg')
437  call assert_fails('so Xinvalidarg', 'E119:')
438  call delete('Xinvalidarg')
439endfunc
440
441let s:funcResult = 0
442
443def FuncNoArgNoRet()
444  funcResult = 11
445enddef
446
447def FuncNoArgRetNumber(): number
448  funcResult = 22
449  return 1234
450enddef
451
452def FuncNoArgRetString(): string
453  funcResult = 45
454  return 'text'
455enddef
456
457def FuncOneArgNoRet(arg: number)
458  funcResult = arg
459enddef
460
461def FuncOneArgRetNumber(arg: number): number
462  funcResult = arg
463  return arg
464enddef
465
466def FuncTwoArgNoRet(one: bool, two: number)
467  funcResult = two
468enddef
469
470def FuncOneArgRetString(arg: string): string
471  return arg
472enddef
473
474def FuncOneArgRetAny(arg: any): any
475  return arg
476enddef
477
478def Test_func_type()
479  let Ref1: func()
480  funcResult = 0
481  Ref1 = FuncNoArgNoRet
482  Ref1()
483  assert_equal(11, funcResult)
484
485  let Ref2: func
486  funcResult = 0
487  Ref2 = FuncNoArgNoRet
488  Ref2()
489  assert_equal(11, funcResult)
490
491  funcResult = 0
492  Ref2 = FuncOneArgNoRet
493  Ref2(12)
494  assert_equal(12, funcResult)
495
496  funcResult = 0
497  Ref2 = FuncNoArgRetNumber
498  assert_equal(1234, Ref2())
499  assert_equal(22, funcResult)
500
501  funcResult = 0
502  Ref2 = FuncOneArgRetNumber
503  assert_equal(13, Ref2(13))
504  assert_equal(13, funcResult)
505enddef
506
507def Test_func_type_part()
508  let RefVoid: func: void
509  RefVoid = FuncNoArgNoRet
510  RefVoid = FuncOneArgNoRet
511  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
512  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
513
514  let RefAny: func(): any
515  RefAny = FuncNoArgRetNumber
516  RefAny = FuncNoArgRetString
517  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
518  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
519
520  let RefNr: func: number
521  RefNr = FuncNoArgRetNumber
522  RefNr = FuncOneArgRetNumber
523  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
524  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
525
526  let RefStr: func: string
527  RefStr = FuncNoArgRetString
528  RefStr = FuncOneArgRetString
529  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
530  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
531enddef
532
533def Test_func_type_fails()
534  CheckDefFailure(['let ref1: func()'], 'E704:')
535
536  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
537  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)')
538  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number')
539  CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)')
540  CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)')
541  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)')
542
543  call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
544  call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
545  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:')
546  call CheckDefFailure(['let RefWrong: func(bool):string'], 'E1069:')
547enddef
548
549def Test_func_return_type()
550  let nr: number
551  nr = FuncNoArgRetNumber()
552  assert_equal(1234, nr)
553
554  nr = FuncOneArgRetAny(122)
555  assert_equal(122, nr)
556
557  let str: string
558  str = FuncOneArgRetAny('yes')
559  assert_equal('yes', str)
560
561  CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1013: type mismatch, expected string but got number')
562enddef
563
564" When using CheckScriptFailure() for the below test, E1010 is generated instead
565" of E1056.
566func Test_E1056_1059()
567  let caught_1056 = 0
568  try
569    def F():
570      return 1
571    enddef
572  catch /E1056:/
573    let caught_1056 = 1
574  endtry
575  call assert_equal(1, caught_1056)
576
577  let caught_1059 = 0
578  try
579    def F5(items : list)
580      echo 'a'
581    enddef
582  catch /E1059:/
583    let caught_1059 = 1
584  endtry
585  call assert_equal(1, caught_1059)
586endfunc
587
588" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
589