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 ...')
253  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
254enddef
255
256def Test_vim9script_call()
257  let lines =<< trim END
258    vim9script
259    let var = ''
260    def MyFunc(arg: string)
261       var = arg
262    enddef
263    MyFunc('foobar')
264    assert_equal('foobar', var)
265
266    let str = 'barfoo'
267    str->MyFunc()
268    assert_equal('barfoo', var)
269
270    let g:value = 'value'
271    g:value->MyFunc()
272    assert_equal('value', var)
273
274    let listvar = []
275    def ListFunc(arg: list<number>)
276       listvar = arg
277    enddef
278    [1, 2, 3]->ListFunc()
279    assert_equal([1, 2, 3], listvar)
280
281    let dictvar = {}
282    def DictFunc(arg: dict<number>)
283       dictvar = arg
284    enddef
285    {'a': 1, 'b': 2}->DictFunc()
286    assert_equal(#{a: 1, b: 2}, dictvar)
287    def CompiledDict()
288      {'a': 3, 'b': 4}->DictFunc()
289    enddef
290    CompiledDict()
291    assert_equal(#{a: 3, b: 4}, dictvar)
292
293    #{a: 3, b: 4}->DictFunc()
294    assert_equal(#{a: 3, b: 4}, dictvar)
295
296    ('text')->MyFunc()
297    assert_equal('text', var)
298    ("some")->MyFunc()
299    assert_equal('some', var)
300  END
301  writefile(lines, 'Xcall.vim')
302  source Xcall.vim
303  delete('Xcall.vim')
304enddef
305
306def Test_vim9script_call_fail_decl()
307  let lines =<< trim END
308    vim9script
309    let var = ''
310    def MyFunc(arg: string)
311       let var = 123
312    enddef
313  END
314  writefile(lines, 'Xcall_decl.vim')
315  assert_fails('source Xcall_decl.vim', 'E1054:')
316  delete('Xcall_decl.vim')
317enddef
318
319def Test_vim9script_call_fail_const()
320  let lines =<< trim END
321    vim9script
322    const var = ''
323    def MyFunc(arg: string)
324       var = 'asdf'
325    enddef
326  END
327  writefile(lines, 'Xcall_const.vim')
328  assert_fails('source Xcall_const.vim', 'E46:')
329  delete('Xcall_const.vim')
330enddef
331
332" Test that inside :function a Python function can be defined, :def is not
333" recognized.
334func Test_function_python()
335  CheckFeature python3
336  let py = 'python3'
337  execute py "<< EOF"
338def do_something():
339  return 1
340EOF
341endfunc
342
343def Test_delfunc()
344  let lines =<< trim END
345    vim9script
346    def GoneSoon()
347      echo 'hello'
348    enddef
349
350    def CallGoneSoon()
351      GoneSoon()
352    enddef
353
354    delfunc GoneSoon
355    CallGoneSoon()
356  END
357  writefile(lines, 'XToDelFunc')
358  assert_fails('so XToDelFunc', 'E933')
359  assert_fails('so XToDelFunc', 'E933')
360
361  delete('XToDelFunc')
362enddef
363
364def Test_redef_failure()
365  call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
366  so Xdef
367  call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
368  so Xdef
369  call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
370  call assert_fails('so Xdef', 'E1027:')
371  call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
372  so Xdef
373  call delete('Xdef')
374
375  call assert_equal(0, Func0())
376  call assert_equal('Func1', Func1())
377  call assert_equal('Func2', Func2())
378
379  delfunc! Func0
380  delfunc! Func1
381  delfunc! Func2
382enddef
383
384" Test for internal functions returning different types
385func Test_InternalFuncRetType()
386  let lines =<< trim END
387    def RetFloat(): float
388      return ceil(1.456)
389    enddef
390
391    def RetListAny(): list<any>
392      return items({'k' : 'v'})
393    enddef
394
395    def RetListString(): list<string>
396      return split('a:b:c', ':')
397    enddef
398
399    def RetListDictAny(): list<dict<any>>
400      return getbufinfo()
401    enddef
402
403    def RetDictNumber(): dict<number>
404      return wordcount()
405    enddef
406
407    def RetDictString(): dict<string>
408      return environ()
409    enddef
410  END
411  call writefile(lines, 'Xscript')
412  source Xscript
413
414  call assert_equal(2.0, RetFloat())
415  call assert_equal([['k', 'v']], RetListAny())
416  call assert_equal(['a', 'b', 'c'], RetListString())
417  call assert_notequal([], RetListDictAny())
418  call assert_notequal({}, RetDictNumber())
419  call assert_notequal({}, RetDictString())
420  call delete('Xscript')
421endfunc
422
423" Test for passing too many or too few arguments to internal functions
424func Test_internalfunc_arg_error()
425  let l =<< trim END
426    def! FArgErr(): float
427      return ceil(1.1, 2)
428    enddef
429  END
430  call writefile(l, 'Xinvalidarg')
431  call assert_fails('so Xinvalidarg', 'E118:')
432  let l =<< trim END
433    def! FArgErr(): float
434      return ceil()
435    enddef
436  END
437  call writefile(l, 'Xinvalidarg')
438  call assert_fails('so Xinvalidarg', 'E119:')
439  call delete('Xinvalidarg')
440endfunc
441
442let s:funcResult = 0
443
444def FuncNoArgNoRet()
445  funcResult = 11
446enddef
447
448def FuncNoArgRetNumber(): number
449  funcResult = 22
450  return 1234
451enddef
452
453def FuncNoArgRetString(): string
454  funcResult = 45
455  return 'text'
456enddef
457
458def FuncOneArgNoRet(arg: number)
459  funcResult = arg
460enddef
461
462def FuncOneArgRetNumber(arg: number): number
463  funcResult = arg
464  return arg
465enddef
466
467def FuncTwoArgNoRet(one: bool, two: number)
468  funcResult = two
469enddef
470
471def FuncOneArgRetString(arg: string): string
472  return arg
473enddef
474
475def FuncOneArgRetAny(arg: any): any
476  return arg
477enddef
478
479def Test_func_type()
480  let Ref1: func()
481  funcResult = 0
482  Ref1 = FuncNoArgNoRet
483  Ref1()
484  assert_equal(11, funcResult)
485
486  let Ref2: func
487  funcResult = 0
488  Ref2 = FuncNoArgNoRet
489  Ref2()
490  assert_equal(11, funcResult)
491
492  funcResult = 0
493  Ref2 = FuncOneArgNoRet
494  Ref2(12)
495  assert_equal(12, funcResult)
496
497  funcResult = 0
498  Ref2 = FuncNoArgRetNumber
499  assert_equal(1234, Ref2())
500  assert_equal(22, funcResult)
501
502  funcResult = 0
503  Ref2 = FuncOneArgRetNumber
504  assert_equal(13, Ref2(13))
505  assert_equal(13, funcResult)
506enddef
507
508def Test_func_type_part()
509  let RefVoid: func: void
510  RefVoid = FuncNoArgNoRet
511  RefVoid = FuncOneArgNoRet
512  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
513  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
514
515  let RefAny: func(): any
516  RefAny = FuncNoArgRetNumber
517  RefAny = FuncNoArgRetString
518  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
519  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
520
521  let RefNr: func: number
522  RefNr = FuncNoArgRetNumber
523  RefNr = FuncOneArgRetNumber
524  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
525  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
526
527  let RefStr: func: string
528  RefStr = FuncNoArgRetString
529  RefStr = FuncOneArgRetString
530  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
531  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
532enddef
533
534def Test_func_type_fails()
535  CheckDefFailure(['let ref1: func()'], 'E704:')
536
537  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
538  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)')
539  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): 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  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)')
543
544  call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
545  call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
546  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:')
547  call CheckDefFailure(['let RefWrong: func(bool):string'], 'E1069:')
548enddef
549
550def Test_func_return_type()
551  let nr: number
552  nr = FuncNoArgRetNumber()
553  assert_equal(1234, nr)
554
555  nr = FuncOneArgRetAny(122)
556  assert_equal(122, nr)
557
558  let str: string
559  str = FuncOneArgRetAny('yes')
560  assert_equal('yes', str)
561
562  CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1013: type mismatch, expected string but got number')
563enddef
564
565def MultiLine(
566    arg1: string,
567    arg2 = 1234,
568    ...rest: list<string>
569      ): string
570  return arg1 .. arg2 .. join(rest, '-')
571enddef
572
573def MultiLineComment(
574    arg1: string, # comment
575    arg2 = 1234, # comment
576    ...rest: list<string> # comment
577      ): string # comment
578  return arg1 .. arg2 .. join(rest, '-')
579enddef
580
581def Test_multiline()
582  assert_equal('text1234', MultiLine('text'))
583  assert_equal('text777', MultiLine('text', 777))
584  assert_equal('text777one', MultiLine('text', 777, 'one'))
585  assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
586enddef
587
588func Test_multiline_not_vim9()
589  call assert_equal('text1234', MultiLine('text'))
590  call assert_equal('text777', MultiLine('text', 777))
591  call assert_equal('text777one', MultiLine('text', 777, 'one'))
592  call assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
593endfunc
594
595
596" When using CheckScriptFailure() for the below test, E1010 is generated instead
597" of E1056.
598func Test_E1056_1059()
599  let caught_1056 = 0
600  try
601    def F():
602      return 1
603    enddef
604  catch /E1056:/
605    let caught_1056 = 1
606  endtry
607  call assert_equal(1, caught_1056)
608
609  let caught_1059 = 0
610  try
611    def F5(items : list)
612      echo 'a'
613    enddef
614  catch /E1059:/
615    let caught_1059 = 1
616  endtry
617  call assert_equal(1, caught_1059)
618endfunc
619
620" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
621