1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source view_util.vim
5source vim9.vim
6source screendump.vim
7
8func Test_def_basic()
9  def SomeFunc(): string
10    return 'yes'
11  enddef
12  call assert_equal('yes', SomeFunc())
13endfunc
14
15def ReturnString(): string
16  return 'string'
17enddef
18
19def ReturnNumber(): number
20  return 123
21enddef
22
23let g:notNumber = 'string'
24
25def ReturnGlobal(): number
26  return g:notNumber
27enddef
28
29def Test_return_something()
30  assert_equal('string', ReturnString())
31  assert_equal(123, ReturnNumber())
32  assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
33enddef
34
35def Test_missing_return()
36  CheckDefFailure(['def Missing(): number',
37                   '  if g:cond',
38                   '    echo "no return"',
39                   '  else',
40                   '    return 0',
41                   '  endif'
42                   'enddef'], 'E1027:')
43  CheckDefFailure(['def Missing(): number',
44                   '  if g:cond',
45                   '    return 1',
46                   '  else',
47                   '    echo "no return"',
48                   '  endif'
49                   'enddef'], 'E1027:')
50  CheckDefFailure(['def Missing(): number',
51                   '  if g:cond',
52                   '    return 1',
53                   '  else',
54                   '    return 2',
55                   '  endif'
56                   '  return 3'
57                   'enddef'], 'E1095:')
58enddef
59
60let s:nothing = 0
61def ReturnNothing()
62  s:nothing = 1
63  if true
64    return
65  endif
66  s:nothing = 2
67enddef
68
69def Test_return_nothing()
70  ReturnNothing()
71  assert_equal(1, s:nothing)
72enddef
73
74func Increment()
75  let g:counter += 1
76endfunc
77
78def Test_call_ufunc_count()
79  g:counter = 1
80  Increment()
81  Increment()
82  Increment()
83  # works with and without :call
84  assert_equal(4, g:counter)
85  call assert_equal(4, g:counter)
86  unlet g:counter
87enddef
88
89def MyVarargs(arg: string, ...rest: list<string>): string
90  let res = arg
91  for s in rest
92    res ..= ',' .. s
93  endfor
94  return res
95enddef
96
97def Test_call_varargs()
98  assert_equal('one', MyVarargs('one'))
99  assert_equal('one,two', MyVarargs('one', 'two'))
100  assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
101enddef
102
103def MyDefaultArgs(name = 'string'): string
104  return name
105enddef
106
107def MyDefaultSecond(name: string, second: bool  = true): string
108  return second ? name : 'none'
109enddef
110
111def Test_call_default_args()
112  assert_equal('string', MyDefaultArgs())
113  assert_equal('one', MyDefaultArgs('one'))
114  assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
115
116  assert_equal('test', MyDefaultSecond('test'))
117  assert_equal('test', MyDefaultSecond('test', true))
118  assert_equal('none', MyDefaultSecond('test', false))
119
120  CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:')
121  CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: argument 1: type mismatch, expected number but got string')
122enddef
123
124def Test_nested_function()
125  def Nested(arg: string): string
126    return 'nested ' .. arg
127  enddef
128  assert_equal('nested function', Nested('function'))
129
130  CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
131  CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
132
133  CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
134  CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
135  CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
136enddef
137
138func Test_call_default_args_from_func()
139  call assert_equal('string', MyDefaultArgs())
140  call assert_equal('one', MyDefaultArgs('one'))
141  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
142endfunc
143
144def Test_nested_global_function()
145  let lines =<< trim END
146      vim9script
147      def Outer()
148          def g:Inner(): string
149              return 'inner'
150          enddef
151      enddef
152      defcompile
153      Outer()
154      assert_equal('inner', g:Inner())
155      delfunc g:Inner
156      Outer()
157      assert_equal('inner', g:Inner())
158      delfunc g:Inner
159      Outer()
160      assert_equal('inner', g:Inner())
161      delfunc g:Inner
162  END
163  CheckScriptSuccess(lines)
164
165  lines =<< trim END
166      vim9script
167      def Outer()
168          def g:Inner(): string
169              return 'inner'
170          enddef
171      enddef
172      defcompile
173      Outer()
174      Outer()
175  END
176  CheckScriptFailure(lines, "E122:")
177
178  lines =<< trim END
179      vim9script
180      def Func()
181        echo 'script'
182      enddef
183      def Outer()
184        def Func()
185          echo 'inner'
186        enddef
187      enddef
188      defcompile
189  END
190  CheckScriptFailure(lines, "E1073:")
191enddef
192
193def Test_global_local_function()
194  let lines =<< trim END
195      vim9script
196      def g:Func(): string
197          return 'global'
198      enddef
199      def Func(): string
200          return 'local'
201      enddef
202      assert_equal('global', g:Func())
203      assert_equal('local', Func())
204  END
205  CheckScriptSuccess(lines)
206
207  lines =<< trim END
208      vim9script
209      def g:Funcy()
210        echo 'funcy'
211      enddef
212      s:Funcy()
213  END
214  CheckScriptFailure(lines, 'E117:')
215enddef
216
217func TakesOneArg(arg)
218  echo a:arg
219endfunc
220
221def Test_call_wrong_args()
222  call CheckDefFailure(['TakesOneArg()'], 'E119:')
223  call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
224  call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
225  call CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:')
226
227  let lines =<< trim END
228    vim9script
229    def Func(s: string)
230      echo s
231    enddef
232    Func([])
233  END
234  call CheckScriptFailure(lines, 'E1012: type mismatch, expected string but got list<unknown>', 5)
235enddef
236
237" Default arg and varargs
238def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
239  let res = one .. ',' .. two
240  for s in rest
241    res ..= ',' .. s
242  endfor
243  return res
244enddef
245
246def Test_call_def_varargs()
247  call assert_fails('call MyDefVarargs()', 'E119:')
248  assert_equal('one,foo', MyDefVarargs('one'))
249  assert_equal('one,two', MyDefVarargs('one', 'two'))
250  assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
251  CheckDefFailure(['MyDefVarargs("one", 22)'],
252      'E1013: argument 2: type mismatch, expected string but got number')
253  CheckDefFailure(['MyDefVarargs("one", "two", 123)'],
254      'E1013: argument 3: type mismatch, expected string but got number')
255
256  let lines =<< trim END
257      vim9script
258      def Func(...l: list<string>)
259        echo l
260      enddef
261      Func('a', 'b', 'c')
262  END
263  CheckScriptSuccess(lines)
264
265  lines =<< trim END
266      vim9script
267      def Func(...l: list<string>)
268        echo l
269      enddef
270      Func()
271  END
272  CheckScriptSuccess(lines)
273
274  lines =<< trim END
275      vim9script
276      def Func(...l: list<string>)
277        echo l
278      enddef
279      Func(1, 2, 3)
280  END
281  CheckScriptFailure(lines, 'E1012:')
282
283  lines =<< trim END
284      vim9script
285      def Func(...l: list<string>)
286        echo l
287      enddef
288      Func('a', 9)
289  END
290  CheckScriptFailure(lines, 'E1012:')
291
292  lines =<< trim END
293      vim9script
294      def Func(...l: list<string>)
295        echo l
296      enddef
297      Func(1, 'a')
298  END
299  CheckScriptFailure(lines, 'E1012:')
300enddef
301
302def Test_call_call()
303  let l = [3, 2, 1]
304  call('reverse', [l])
305  assert_equal([1, 2, 3], l)
306enddef
307
308let s:value = ''
309
310def FuncOneDefArg(opt = 'text')
311  s:value = opt
312enddef
313
314def FuncTwoDefArg(nr = 123, opt = 'text'): string
315  return nr .. opt
316enddef
317
318def FuncVarargs(...arg: list<string>): string
319  return join(arg, ',')
320enddef
321
322def Test_func_type_varargs()
323  let RefDefArg: func(?string)
324  RefDefArg = FuncOneDefArg
325  RefDefArg()
326  assert_equal('text', s:value)
327  RefDefArg('some')
328  assert_equal('some', s:value)
329
330  let RefDef2Arg: func(?number, ?string): string
331  RefDef2Arg = FuncTwoDefArg
332  assert_equal('123text', RefDef2Arg())
333  assert_equal('99text', RefDef2Arg(99))
334  assert_equal('77some', RefDef2Arg(77, 'some'))
335
336  call CheckDefFailure(['let RefWrong: func(string?)'], 'E1010:')
337  call CheckDefFailure(['let RefWrong: func(?string, string)'], 'E1007:')
338
339  let RefVarargs: func(...list<string>): string
340  RefVarargs = FuncVarargs
341  assert_equal('', RefVarargs())
342  assert_equal('one', RefVarargs('one'))
343  assert_equal('one,two', RefVarargs('one', 'two'))
344
345  call CheckDefFailure(['let RefWrong: func(...list<string>, string)'], 'E110:')
346  call CheckDefFailure(['let RefWrong: func(...list<string>, ?string)'], 'E110:')
347enddef
348
349" Only varargs
350def MyVarargsOnly(...args: list<string>): string
351  return join(args, ',')
352enddef
353
354def Test_call_varargs_only()
355  assert_equal('', MyVarargsOnly())
356  assert_equal('one', MyVarargsOnly('one'))
357  assert_equal('one,two', MyVarargsOnly('one', 'two'))
358  call CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: argument 1: type mismatch, expected string but got number')
359  call CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: argument 2: type mismatch, expected string but got number')
360enddef
361
362def Test_using_var_as_arg()
363  call writefile(['def Func(x: number)',  'let x = 234', 'enddef', 'defcompile'], 'Xdef')
364  call assert_fails('so Xdef', 'E1006:')
365  call delete('Xdef')
366enddef
367
368def DictArg(arg: dict<string>)
369  arg['key'] = 'value'
370enddef
371
372def ListArg(arg: list<string>)
373  arg[0] = 'value'
374enddef
375
376def Test_assign_to_argument()
377  # works for dict and list
378  let d: dict<string> = {}
379  DictArg(d)
380  assert_equal('value', d['key'])
381  let l: list<string> = []
382  ListArg(l)
383  assert_equal('value', l[0])
384
385  call CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:')
386enddef
387
388def Test_call_func_defined_later()
389  call assert_equal('one', g:DefinedLater('one'))
390  call assert_fails('call NotDefined("one")', 'E117:')
391enddef
392
393func DefinedLater(arg)
394  return a:arg
395endfunc
396
397def Test_call_funcref()
398  assert_equal(3, g:SomeFunc('abc'))
399  assert_fails('NotAFunc()', 'E117:') # comment after call
400  assert_fails('g:NotAFunc()', 'E117:')
401
402  let lines =<< trim END
403    vim9script
404    def RetNumber(): number
405      return 123
406    enddef
407    let Funcref: func: number = function('RetNumber')
408    assert_equal(123, Funcref())
409  END
410  CheckScriptSuccess(lines)
411
412  lines =<< trim END
413    vim9script
414    def RetNumber(): number
415      return 123
416    enddef
417    def Bar(F: func: number): number
418      return F()
419    enddef
420    let Funcref = function('RetNumber')
421    assert_equal(123, Bar(Funcref))
422  END
423  CheckScriptSuccess(lines)
424
425  lines =<< trim END
426    vim9script
427    def UseNumber(nr: number)
428      echo nr
429    enddef
430    let Funcref: func(number) = function('UseNumber')
431    Funcref(123)
432  END
433  CheckScriptSuccess(lines)
434
435  lines =<< trim END
436    vim9script
437    def UseNumber(nr: number)
438      echo nr
439    enddef
440    let Funcref: func(string) = function('UseNumber')
441  END
442  CheckScriptFailure(lines, 'E1012: type mismatch, expected func(string) but got func(number)')
443
444  lines =<< trim END
445    vim9script
446    def EchoNr(nr = 34)
447      g:echo = nr
448    enddef
449    let Funcref: func(?number) = function('EchoNr')
450    Funcref()
451    assert_equal(34, g:echo)
452    Funcref(123)
453    assert_equal(123, g:echo)
454  END
455  CheckScriptSuccess(lines)
456
457  lines =<< trim END
458    vim9script
459    def EchoList(...l: list<number>)
460      g:echo = l
461    enddef
462    let Funcref: func(...list<number>) = function('EchoList')
463    Funcref()
464    assert_equal([], g:echo)
465    Funcref(1, 2, 3)
466    assert_equal([1, 2, 3], g:echo)
467  END
468  CheckScriptSuccess(lines)
469
470  lines =<< trim END
471    vim9script
472    def OptAndVar(nr: number, opt = 12, ...l: list<number>): number
473      g:optarg = opt
474      g:listarg = l
475      return nr
476    enddef
477    let Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar')
478    assert_equal(10, Funcref(10))
479    assert_equal(12, g:optarg)
480    assert_equal([], g:listarg)
481
482    assert_equal(11, Funcref(11, 22))
483    assert_equal(22, g:optarg)
484    assert_equal([], g:listarg)
485
486    assert_equal(17, Funcref(17, 18, 1, 2, 3))
487    assert_equal(18, g:optarg)
488    assert_equal([1, 2, 3], g:listarg)
489  END
490  CheckScriptSuccess(lines)
491enddef
492
493let SomeFunc = function('len')
494let NotAFunc = 'text'
495
496def CombineFuncrefTypes()
497  # same arguments, different return type
498  let Ref1: func(bool): string
499  let Ref2: func(bool): number
500  let Ref3: func(bool): any
501  Ref3 = g:cond ? Ref1 : Ref2
502
503  # different number of arguments
504  let Refa1: func(bool): number
505  let Refa2: func(bool, number): number
506  let Refa3: func: number
507  Refa3 = g:cond ? Refa1 : Refa2
508
509  # different argument types
510  let Refb1: func(bool, string): number
511  let Refb2: func(string, number): number
512  let Refb3: func(any, any): number
513  Refb3 = g:cond ? Refb1 : Refb2
514enddef
515
516def FuncWithForwardCall()
517  return g:DefinedEvenLater("yes")
518enddef
519
520def DefinedEvenLater(arg: string): string
521  return arg
522enddef
523
524def Test_error_in_nested_function()
525  # Error in called function requires unwinding the call stack.
526  assert_fails('call FuncWithForwardCall()', 'E1096')
527enddef
528
529def Test_return_type_wrong()
530  CheckScriptFailure([
531        'def Func(): number',
532        'return "a"',
533        'enddef',
534        'defcompile'], 'expected number but got string')
535  CheckScriptFailure([
536        'def Func(): string',
537        'return 1',
538        'enddef',
539        'defcompile'], 'expected string but got number')
540  CheckScriptFailure([
541        'def Func(): void',
542        'return "a"',
543        'enddef',
544        'defcompile'],
545        'E1096: Returning a value in a function without a return type')
546  CheckScriptFailure([
547        'def Func()',
548        'return "a"',
549        'enddef',
550        'defcompile'],
551        'E1096: Returning a value in a function without a return type')
552
553  CheckScriptFailure([
554        'def Func(): number',
555        'return',
556        'enddef',
557        'defcompile'], 'E1003:')
558
559  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
560  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
561  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
562
563  CheckScriptFailure([
564        'vim9script',
565        'def FuncB()',
566        '  return 123',
567        'enddef',
568        'def FuncA()',
569        '   FuncB()',
570        'enddef',
571        'defcompile'], 'E1096:')
572enddef
573
574def Test_arg_type_wrong()
575  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
576  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
577  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
578  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
579enddef
580
581def Test_vim9script_call()
582  let lines =<< trim END
583    vim9script
584    let var = ''
585    def MyFunc(arg: string)
586       var = arg
587    enddef
588    MyFunc('foobar')
589    assert_equal('foobar', var)
590
591    let str = 'barfoo'
592    str->MyFunc()
593    assert_equal('barfoo', var)
594
595    g:value = 'value'
596    g:value->MyFunc()
597    assert_equal('value', var)
598
599    let listvar = []
600    def ListFunc(arg: list<number>)
601       listvar = arg
602    enddef
603    [1, 2, 3]->ListFunc()
604    assert_equal([1, 2, 3], listvar)
605
606    let dictvar = {}
607    def DictFunc(arg: dict<number>)
608       dictvar = arg
609    enddef
610    {'a': 1, 'b': 2}->DictFunc()
611    assert_equal(#{a: 1, b: 2}, dictvar)
612    def CompiledDict()
613      {'a': 3, 'b': 4}->DictFunc()
614    enddef
615    CompiledDict()
616    assert_equal(#{a: 3, b: 4}, dictvar)
617
618    #{a: 3, b: 4}->DictFunc()
619    assert_equal(#{a: 3, b: 4}, dictvar)
620
621    ('text')->MyFunc()
622    assert_equal('text', var)
623    ("some")->MyFunc()
624    assert_equal('some', var)
625
626    # line starting with single quote is not a mark
627    # line starting with double quote can be a method call
628    'asdfasdf'->MyFunc()
629    assert_equal('asdfasdf', var)
630    "xyz"->MyFunc()
631    assert_equal('xyz', var)
632
633    def UseString()
634      'xyork'->MyFunc()
635    enddef
636    UseString()
637    assert_equal('xyork', var)
638
639    def UseString2()
640      "knife"->MyFunc()
641    enddef
642    UseString2()
643    assert_equal('knife', var)
644
645    # prepending a colon makes it a mark
646    new
647    setline(1, ['aaa', 'bbb', 'ccc'])
648    normal! 3Gmt1G
649    :'t
650    assert_equal(3, getcurpos()[1])
651    bwipe!
652
653    MyFunc(
654        'continued'
655        )
656    assert_equal('continued',
657            var
658            )
659
660    call MyFunc(
661        'more'
662          ..
663          'lines'
664        )
665    assert_equal(
666        'morelines',
667        var)
668  END
669  writefile(lines, 'Xcall.vim')
670  source Xcall.vim
671  delete('Xcall.vim')
672enddef
673
674def Test_vim9script_call_fail_decl()
675  let lines =<< trim END
676    vim9script
677    let var = ''
678    def MyFunc(arg: string)
679       let var = 123
680    enddef
681    defcompile
682  END
683  CheckScriptFailure(lines, 'E1054:')
684enddef
685
686def Test_vim9script_call_fail_type()
687  let lines =<< trim END
688    vim9script
689    def MyFunc(arg: string)
690      echo arg
691    enddef
692    MyFunc(1234)
693  END
694  CheckScriptFailure(lines, 'E1012: type mismatch, expected string but got number')
695enddef
696
697def Test_vim9script_call_fail_const()
698  let lines =<< trim END
699    vim9script
700    const var = ''
701    def MyFunc(arg: string)
702       var = 'asdf'
703    enddef
704    defcompile
705  END
706  writefile(lines, 'Xcall_const.vim')
707  assert_fails('source Xcall_const.vim', 'E46:')
708  delete('Xcall_const.vim')
709enddef
710
711" Test that inside :function a Python function can be defined, :def is not
712" recognized.
713func Test_function_python()
714  CheckFeature python3
715  let py = 'python3'
716  execute py "<< EOF"
717def do_something():
718  return 1
719EOF
720endfunc
721
722def Test_delfunc()
723  let lines =<< trim END
724    vim9script
725    def g:GoneSoon()
726      echo 'hello'
727    enddef
728
729    def CallGoneSoon()
730      GoneSoon()
731    enddef
732    defcompile
733
734    delfunc g:GoneSoon
735    CallGoneSoon()
736  END
737  writefile(lines, 'XToDelFunc')
738  assert_fails('so XToDelFunc', 'E933')
739  assert_fails('so XToDelFunc', 'E933')
740
741  delete('XToDelFunc')
742enddef
743
744def Test_redef_failure()
745  call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
746  so Xdef
747  call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
748  so Xdef
749  call writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
750  call assert_fails('so Xdef', 'E1027:')
751  call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
752  so Xdef
753  call delete('Xdef')
754
755  call assert_equal(0, g:Func0())
756  call assert_equal('Func1', g:Func1())
757  call assert_equal('Func2', g:Func2())
758
759  delfunc! Func0
760  delfunc! Func1
761  delfunc! Func2
762enddef
763
764def Test_vim9script_func()
765  let lines =<< trim END
766    vim9script
767    func Func(arg)
768      echo a:arg
769    endfunc
770    Func('text')
771  END
772  writefile(lines, 'XVim9Func')
773  so XVim9Func
774
775  delete('XVim9Func')
776enddef
777
778" Test for internal functions returning different types
779func Test_InternalFuncRetType()
780  let lines =<< trim END
781    def RetFloat(): float
782      return ceil(1.456)
783    enddef
784
785    def RetListAny(): list<any>
786      return items({'k': 'v'})
787    enddef
788
789    def RetListString(): list<string>
790      return split('a:b:c', ':')
791    enddef
792
793    def RetListDictAny(): list<dict<any>>
794      return getbufinfo()
795    enddef
796
797    def RetDictNumber(): dict<number>
798      return wordcount()
799    enddef
800
801    def RetDictString(): dict<string>
802      return environ()
803    enddef
804  END
805  call writefile(lines, 'Xscript')
806  source Xscript
807
808  call assert_equal(2.0, RetFloat())
809  call assert_equal([['k', 'v']], RetListAny())
810  call assert_equal(['a', 'b', 'c'], RetListString())
811  call assert_notequal([], RetListDictAny())
812  call assert_notequal({}, RetDictNumber())
813  call assert_notequal({}, RetDictString())
814  call delete('Xscript')
815endfunc
816
817" Test for passing too many or too few arguments to internal functions
818func Test_internalfunc_arg_error()
819  let l =<< trim END
820    def! FArgErr(): float
821      return ceil(1.1, 2)
822    enddef
823    defcompile
824  END
825  call writefile(l, 'Xinvalidarg')
826  call assert_fails('so Xinvalidarg', 'E118:')
827  let l =<< trim END
828    def! FArgErr(): float
829      return ceil()
830    enddef
831    defcompile
832  END
833  call writefile(l, 'Xinvalidarg')
834  call assert_fails('so Xinvalidarg', 'E119:')
835  call delete('Xinvalidarg')
836endfunc
837
838let s:funcResult = 0
839
840def FuncNoArgNoRet()
841  s:funcResult = 11
842enddef
843
844def FuncNoArgRetNumber(): number
845  s:funcResult = 22
846  return 1234
847enddef
848
849def FuncNoArgRetString(): string
850  s:funcResult = 45
851  return 'text'
852enddef
853
854def FuncOneArgNoRet(arg: number)
855  s:funcResult = arg
856enddef
857
858def FuncOneArgRetNumber(arg: number): number
859  s:funcResult = arg
860  return arg
861enddef
862
863def FuncTwoArgNoRet(one: bool, two: number)
864  s:funcResult = two
865enddef
866
867def FuncOneArgRetString(arg: string): string
868  return arg
869enddef
870
871def FuncOneArgRetAny(arg: any): any
872  return arg
873enddef
874
875def Test_func_type()
876  let Ref1: func()
877  s:funcResult = 0
878  Ref1 = FuncNoArgNoRet
879  Ref1()
880  assert_equal(11, s:funcResult)
881
882  let Ref2: func
883  s:funcResult = 0
884  Ref2 = FuncNoArgNoRet
885  Ref2()
886  assert_equal(11, s:funcResult)
887
888  s:funcResult = 0
889  Ref2 = FuncOneArgNoRet
890  Ref2(12)
891  assert_equal(12, s:funcResult)
892
893  s:funcResult = 0
894  Ref2 = FuncNoArgRetNumber
895  assert_equal(1234, Ref2())
896  assert_equal(22, s:funcResult)
897
898  s:funcResult = 0
899  Ref2 = FuncOneArgRetNumber
900  assert_equal(13, Ref2(13))
901  assert_equal(13, s:funcResult)
902enddef
903
904def Test_repeat_return_type()
905  let res = 0
906  for n in repeat([1], 3)
907    res += n
908  endfor
909  assert_equal(3, res)
910
911  res = 0
912  for n in add([1, 2], 3)
913    res += n
914  endfor
915  assert_equal(6, res)
916enddef
917
918def Test_argv_return_type()
919  next fileone filetwo
920  let res = ''
921  for name in argv()
922    res ..= name
923  endfor
924  assert_equal('fileonefiletwo', res)
925enddef
926
927def Test_func_type_part()
928  let RefVoid: func: void
929  RefVoid = FuncNoArgNoRet
930  RefVoid = FuncOneArgNoRet
931  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: type mismatch, expected func() but got func(): number')
932  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: type mismatch, expected func() but got func(): string')
933
934  let RefAny: func(): any
935  RefAny = FuncNoArgRetNumber
936  RefAny = FuncNoArgRetString
937  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: type mismatch, expected func(): any but got func()')
938  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: type mismatch, expected func(): any but got func(number)')
939
940  let RefNr: func: number
941  RefNr = FuncNoArgRetNumber
942  RefNr = FuncOneArgRetNumber
943  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: type mismatch, expected func(): number but got func()')
944  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: type mismatch, expected func(): number but got func(): string')
945
946  let RefStr: func: string
947  RefStr = FuncNoArgRetString
948  RefStr = FuncOneArgRetString
949  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: type mismatch, expected func(): string but got func()')
950  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: type mismatch, expected func(): string but got func(): number')
951enddef
952
953def Test_func_type_fails()
954  CheckDefFailure(['let ref1: func()'], 'E704:')
955
956  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: type mismatch, expected func() but got func(): number')
957  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: type mismatch, expected func() but got func(number)')
958  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: type mismatch, expected func() but got func(number): number')
959  CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(bool) but got func(bool, number)')
960  CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(?bool) but got func(bool, number)')
961  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(...bool) but got func(bool, number)')
962
963  call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
964  call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
965  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)'], 'E1005:')
966  call CheckDefFailure(['let RefWrong: func(bool):string'], 'E1069:')
967enddef
968
969def Test_func_return_type()
970  let nr: number
971  nr = FuncNoArgRetNumber()
972  assert_equal(1234, nr)
973
974  nr = FuncOneArgRetAny(122)
975  assert_equal(122, nr)
976
977  let str: string
978  str = FuncOneArgRetAny('yes')
979  assert_equal('yes', str)
980
981  CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1012: type mismatch, expected string but got number')
982enddef
983
984def MultiLine(
985    arg1: string,
986    arg2 = 1234,
987    ...rest: list<string>
988      ): string
989  return arg1 .. arg2 .. join(rest, '-')
990enddef
991
992def MultiLineComment(
993    arg1: string, # comment
994    arg2 = 1234, # comment
995    ...rest: list<string> # comment
996      ): string # comment
997  return arg1 .. arg2 .. join(rest, '-')
998enddef
999
1000def Test_multiline()
1001  assert_equal('text1234', MultiLine('text'))
1002  assert_equal('text777', MultiLine('text', 777))
1003  assert_equal('text777one', MultiLine('text', 777, 'one'))
1004  assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
1005enddef
1006
1007func Test_multiline_not_vim9()
1008  call assert_equal('text1234', MultiLine('text'))
1009  call assert_equal('text777', MultiLine('text', 777))
1010  call assert_equal('text777one', MultiLine('text', 777, 'one'))
1011  call assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two'))
1012endfunc
1013
1014
1015" When using CheckScriptFailure() for the below test, E1010 is generated instead
1016" of E1056.
1017func Test_E1056_1059()
1018  let caught_1056 = 0
1019  try
1020    def F():
1021      return 1
1022    enddef
1023  catch /E1056:/
1024    let caught_1056 = 1
1025  endtry
1026  call assert_equal(1, caught_1056)
1027
1028  let caught_1059 = 0
1029  try
1030    def F5(items : list)
1031      echo 'a'
1032    enddef
1033  catch /E1059:/
1034    let caught_1059 = 1
1035  endtry
1036  call assert_equal(1, caught_1059)
1037endfunc
1038
1039func DelMe()
1040  echo 'DelMe'
1041endfunc
1042
1043def Test_error_reporting()
1044  # comment lines at the start of the function
1045  let lines =<< trim END
1046    " comment
1047    def Func()
1048      # comment
1049      # comment
1050      invalid
1051    enddef
1052    defcompile
1053  END
1054  call writefile(lines, 'Xdef')
1055  try
1056    source Xdef
1057    assert_report('should have failed')
1058  catch /E476:/
1059    assert_match('Invalid command: invalid', v:exception)
1060    assert_match(', line 3$', v:throwpoint)
1061  endtry
1062
1063  # comment lines after the start of the function
1064  lines =<< trim END
1065    " comment
1066    def Func()
1067      let x = 1234
1068      # comment
1069      # comment
1070      invalid
1071    enddef
1072    defcompile
1073  END
1074  call writefile(lines, 'Xdef')
1075  try
1076    source Xdef
1077    assert_report('should have failed')
1078  catch /E476:/
1079    assert_match('Invalid command: invalid', v:exception)
1080    assert_match(', line 4$', v:throwpoint)
1081  endtry
1082
1083  lines =<< trim END
1084    vim9script
1085    def Func()
1086      let db = #{foo: 1, bar: 2}
1087      # comment
1088      let x = db.asdf
1089    enddef
1090    defcompile
1091    Func()
1092  END
1093  call writefile(lines, 'Xdef')
1094  try
1095    source Xdef
1096    assert_report('should have failed')
1097  catch /E716:/
1098    assert_match('_Func, line 3$', v:throwpoint)
1099  endtry
1100
1101  call delete('Xdef')
1102enddef
1103
1104def Test_deleted_function()
1105  CheckDefExecFailure([
1106      'let RefMe: func = function("g:DelMe")',
1107      'delfunc g:DelMe',
1108      'echo RefMe()'], 'E117:')
1109enddef
1110
1111def Test_unknown_function()
1112  CheckDefExecFailure([
1113      'let Ref: func = function("NotExist")',
1114      'delfunc g:NotExist'], 'E700:')
1115enddef
1116
1117def RefFunc(Ref: func(string): string): string
1118  return Ref('more')
1119enddef
1120
1121def Test_closure_simple()
1122  let local = 'some '
1123  assert_equal('some more', RefFunc({s -> local .. s}))
1124enddef
1125
1126def MakeRef()
1127  let local = 'some '
1128  g:Ref = {s -> local .. s}
1129enddef
1130
1131def Test_closure_ref_after_return()
1132  MakeRef()
1133  assert_equal('some thing', g:Ref('thing'))
1134  unlet g:Ref
1135enddef
1136
1137def MakeTwoRefs()
1138  let local = ['some']
1139  g:Extend = {s -> local->add(s)}
1140  g:Read = {-> local}
1141enddef
1142
1143def Test_closure_two_refs()
1144  MakeTwoRefs()
1145  assert_equal('some', join(g:Read(), ' '))
1146  g:Extend('more')
1147  assert_equal('some more', join(g:Read(), ' '))
1148  g:Extend('even')
1149  assert_equal('some more even', join(g:Read(), ' '))
1150
1151  unlet g:Extend
1152  unlet g:Read
1153enddef
1154
1155def ReadRef(Ref: func(): list<string>): string
1156  return join(Ref(), ' ')
1157enddef
1158
1159def ExtendRef(Ref: func(string), add: string)
1160  Ref(add)
1161enddef
1162
1163def Test_closure_two_indirect_refs()
1164  MakeTwoRefs()
1165  assert_equal('some', ReadRef(g:Read))
1166  ExtendRef(g:Extend, 'more')
1167  assert_equal('some more', ReadRef(g:Read))
1168  ExtendRef(g:Extend, 'even')
1169  assert_equal('some more even', ReadRef(g:Read))
1170
1171  unlet g:Extend
1172  unlet g:Read
1173enddef
1174
1175def MakeArgRefs(theArg: string)
1176  let local = 'loc_val'
1177  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
1178enddef
1179
1180def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1181  let local = 'the_loc'
1182  g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)}
1183enddef
1184
1185def Test_closure_using_argument()
1186  MakeArgRefs('arg_val')
1187  assert_equal('arg_val/loc_val/call_val', g:UseArg('call_val'))
1188
1189  MakeArgRefsVarargs('arg_val', 'one', 'two')
1190  assert_equal('arg_val/the_loc/call_val/one two', g:UseVararg('call_val'))
1191
1192  unlet g:UseArg
1193  unlet g:UseVararg
1194enddef
1195
1196def MakeGetAndAppendRefs()
1197  let local = 'a'
1198
1199  def Append(arg: string)
1200    local ..= arg
1201  enddef
1202  g:Append = Append
1203
1204  def Get(): string
1205    return local
1206  enddef
1207  g:Get = Get
1208enddef
1209
1210def Test_closure_append_get()
1211  MakeGetAndAppendRefs()
1212  assert_equal('a', g:Get())
1213  g:Append('-b')
1214  assert_equal('a-b', g:Get())
1215  g:Append('-c')
1216  assert_equal('a-b-c', g:Get())
1217
1218  unlet g:Append
1219  unlet g:Get
1220enddef
1221
1222def Test_nested_closure()
1223  let local = 'text'
1224  def Closure(arg: string): string
1225    return local .. arg
1226  enddef
1227  assert_equal('text!!!', Closure('!!!'))
1228enddef
1229
1230func GetResult(Ref)
1231  return a:Ref('some')
1232endfunc
1233
1234def Test_call_closure_not_compiled()
1235  let text = 'text'
1236  g:Ref = {s ->  s .. text}
1237  assert_equal('sometext', GetResult(g:Ref))
1238enddef
1239
1240def Test_sort_return_type()
1241  let res: list<number>
1242  res = [1, 2, 3]->sort()
1243enddef
1244
1245def Test_getqflist_return_type()
1246  let l = getqflist()
1247  assert_equal([], l)
1248
1249  let d = getqflist(#{items: 0})
1250  assert_equal(#{items: []}, d)
1251enddef
1252
1253def Test_getloclist_return_type()
1254  let l = getloclist(1)
1255  assert_equal([], l)
1256
1257  let d = getloclist(1, #{items: 0})
1258  assert_equal(#{items: []}, d)
1259enddef
1260
1261def Test_copy_return_type()
1262  let l = copy([1, 2, 3])
1263  let res = 0
1264  for n in l
1265    res += n
1266  endfor
1267  assert_equal(6, res)
1268
1269  let dl = deepcopy([1, 2, 3])
1270  res = 0
1271  for n in dl
1272    res += n
1273  endfor
1274  assert_equal(6, res)
1275enddef
1276
1277def Test_extend_return_type()
1278  let l = extend([1, 2], [3])
1279  let res = 0
1280  for n in l
1281    res += n
1282  endfor
1283  assert_equal(6, res)
1284enddef
1285
1286def Test_insert_return_type()
1287  let l = insert([2, 1], 3)
1288  let res = 0
1289  for n in l
1290    res += n
1291  endfor
1292  assert_equal(6, res)
1293enddef
1294
1295def Test_keys_return_type()
1296  const var: list<string> = #{a: 1, b: 2}->keys()
1297  assert_equal(['a', 'b'], var)
1298enddef
1299
1300def Test_reverse_return_type()
1301  let l = reverse([1, 2, 3])
1302  let res = 0
1303  for n in l
1304    res += n
1305  endfor
1306  assert_equal(6, res)
1307enddef
1308
1309def Test_remove_return_type()
1310  let l = remove(#{one: [1, 2], two: [3, 4]}, 'one')
1311  let res = 0
1312  for n in l
1313    res += n
1314  endfor
1315  assert_equal(3, res)
1316enddef
1317
1318def Test_filter_return_type()
1319  let l = filter([1, 2, 3], {-> 1})
1320  let res = 0
1321  for n in l
1322    res += n
1323  endfor
1324  assert_equal(6, res)
1325enddef
1326
1327def Test_bufnr()
1328  let buf = bufnr()
1329  assert_equal(buf, bufnr('%'))
1330enddef
1331
1332def Test_col()
1333  new
1334  setline(1, 'asdf')
1335  assert_equal(5, col([1, '$']))
1336enddef
1337
1338def Test_getreg_return_type()
1339  let s1: string = getreg('"')
1340  let s2: string = getreg('"', 1)
1341  let s3: list<string> = getreg('"', 1, 1)
1342enddef
1343
1344def Wrong_dict_key_type(items: list<number>): list<number>
1345  return filter(items, {_, val -> get({val: 1}, 'x')})
1346enddef
1347
1348def Test_wrong_dict_key_type()
1349  assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1029:')
1350enddef
1351
1352def Line_continuation_in_def(dir: string = ''): string
1353    let path: string = empty(dir)
1354            \ ? 'empty'
1355            \ : 'full'
1356    return path
1357enddef
1358
1359def Test_line_continuation_in_def()
1360  assert_equal('full', Line_continuation_in_def('.'))
1361enddef
1362
1363def Line_continuation_in_lambda(): list<number>
1364  let x = range(97, 100)
1365      ->map({_, v -> nr2char(v)
1366          ->toupper()})
1367      ->reverse()
1368  return x
1369enddef
1370
1371def Test_line_continuation_in_lambda()
1372  assert_equal(['D', 'C', 'B', 'A'], Line_continuation_in_lambda())
1373enddef
1374
1375func Test_silent_echo()
1376  CheckScreendump
1377
1378  let lines =<< trim END
1379    vim9script
1380    def EchoNothing()
1381      silent echo ''
1382    enddef
1383    defcompile
1384  END
1385  call writefile(lines, 'XTest_silent_echo')
1386
1387  " Check that the balloon shows up after a mouse move
1388  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1389  call term_sendkeys(buf, ":abc")
1390  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1391
1392  " clean up
1393  call StopVimInTerminal(buf)
1394  call delete('XTest_silent_echo')
1395endfunc
1396
1397def Test_search()
1398  new
1399  setline(1, ['foo', 'bar'])
1400  let val = 0
1401  # skip expr returns boolean
1402  assert_equal(2, search('bar', 'W', 0, 0, {-> val == 1}))
1403  :1
1404  assert_equal(0, search('bar', 'W', 0, 0, {-> val == 0}))
1405  # skip expr returns number, only 0 and 1 are accepted
1406  :1
1407  assert_equal(2, search('bar', 'W', 0, 0, {-> 0}))
1408  :1
1409  assert_equal(0, search('bar', 'W', 0, 0, {-> 1}))
1410  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1411  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1412enddef
1413
1414def Test_readdir()
1415   eval expand('sautest')->readdir({e -> e[0] !=# '.'})
1416   eval expand('sautest')->readdirex({e -> e.name[0] !=# '.'})
1417enddef
1418
1419def Test_setbufvar()
1420   setbufvar(bufnr('%'), '&syntax', 'vim')
1421   assert_equal('vim', &syntax)
1422   setbufvar(bufnr('%'), '&ts', 16)
1423   assert_equal(16, &ts)
1424   settabwinvar(1, 1, '&syntax', 'vam')
1425   assert_equal('vam', &syntax)
1426   settabwinvar(1, 1, '&ts', 15)
1427   assert_equal(15, &ts)
1428   setlocal ts=8
1429enddef
1430
1431def Test_setreg()
1432  setreg('a', ['aaa', 'bbb', 'ccc'])
1433  let reginfo = getreginfo('a')
1434  setreg('a', reginfo)
1435  assert_equal(reginfo, getreginfo('a'))
1436enddef
1437
1438def Fibonacci(n: number): number
1439  if n < 2
1440    return n
1441  else
1442    return Fibonacci(n - 1) + Fibonacci(n - 2)
1443  endif
1444enddef
1445
1446def Test_recursive_call()
1447  assert_equal(6765, Fibonacci(20))
1448enddef
1449
1450def TreeWalk(dir: string): list<any>
1451  return readdir(dir)->map({_, val ->
1452            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
1453               ? {val: TreeWalk(dir .. '/' .. val)}
1454               : val
1455             })
1456enddef
1457
1458def Test_closure_in_map()
1459  mkdir('XclosureDir/tdir', 'p')
1460  writefile(['111'], 'XclosureDir/file1')
1461  writefile(['222'], 'XclosureDir/file2')
1462  writefile(['333'], 'XclosureDir/tdir/file3')
1463
1464  assert_equal(['file1', 'file2', {'tdir': ['file3']}], TreeWalk('XclosureDir'))
1465
1466  delete('XclosureDir', 'rf')
1467enddef
1468
1469def Test_partial_call()
1470  let Xsetlist = function('setloclist', [0])
1471  Xsetlist([], ' ', {'title': 'test'})
1472  assert_equal({'title': 'test'}, getloclist(0, {'title': 1}))
1473
1474  Xsetlist = function('setloclist', [0, [], ' '])
1475  Xsetlist({'title': 'test'})
1476  assert_equal({'title': 'test'}, getloclist(0, {'title': 1}))
1477
1478  Xsetlist = function('setqflist')
1479  Xsetlist([], ' ', {'title': 'test'})
1480  assert_equal({'title': 'test'}, getqflist({'title': 1}))
1481
1482  Xsetlist = function('setqflist', [[], ' '])
1483  Xsetlist({'title': 'test'})
1484  assert_equal({'title': 'test'}, getqflist({'title': 1}))
1485enddef
1486
1487def Test_cmd_modifier()
1488  tab echo '0'
1489  call CheckDefFailure(['5tab echo 3'], 'E16:')
1490enddef
1491
1492def Test_restore_modifiers()
1493  # check that when compiling a :def function command modifiers are not messed
1494  # up.
1495  let lines =<< trim END
1496      vim9script
1497      set eventignore=
1498      autocmd QuickFixCmdPost * copen
1499      def AutocmdsDisabled()
1500          eval 0
1501      enddef
1502      func Func()
1503        noautocmd call s:AutocmdsDisabled()
1504        let g:ei_after = &eventignore
1505      endfunc
1506      Func()
1507  END
1508  CheckScriptSuccess(lines)
1509  assert_equal('', g:ei_after)
1510enddef
1511
1512
1513" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
1514