1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source term_util.vim
5source view_util.vim
6source vim9.vim
7source screendump.vim
8
9func Test_def_basic()
10  def SomeFunc(): string
11    return 'yes'
12  enddef
13  call SomeFunc()->assert_equal('yes')
14endfunc
15
16func Test_compiling_error()
17  " use a terminal to see the whole error message
18  CheckRunVimInTerminal
19
20  call TestCompilingError()
21endfunc
22
23def TestCompilingError()
24  var lines =<< trim END
25    vim9script
26    def Fails()
27      echo nothing
28    enddef
29    defcompile
30  END
31  call writefile(lines, 'XTest_compile_error')
32  var buf = RunVimInTerminal('-S XTest_compile_error',
33              {rows: 10, wait_for_ruler: 0})
34  call WaitForAssert(() => assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing',
35                     Term_getlines(buf, range(1, 9))))
36
37  # clean up
38  call StopVimInTerminal(buf)
39  call delete('XTest_compile_error')
40enddef
41
42def CallRecursive(n: number): number
43  return CallRecursive(n + 1)
44enddef
45
46def CallMapRecursive(l: list<number>): number
47  return map(l, (_, v) => CallMapRecursive([v]))[0]
48enddef
49
50def Test_funcdepth_error()
51  set maxfuncdepth=10
52
53  var caught = false
54  try
55    CallRecursive(1)
56  catch /E132:/
57    caught = true
58  endtry
59  assert_true(caught)
60
61  caught = false
62  try
63    CallMapRecursive([1])
64  catch /E132:/
65    caught = true
66  endtry
67  assert_true(caught)
68
69  set maxfuncdepth&
70enddef
71
72def Test_endfunc_enddef()
73  var lines =<< trim END
74    def Test()
75      echo 'test'
76      endfunc
77    enddef
78  END
79  CheckScriptFailure(lines, 'E1151:', 3)
80
81  lines =<< trim END
82    def Test()
83      func Nested()
84        echo 'test'
85      enddef
86    enddef
87  END
88  CheckScriptFailure(lines, 'E1152:', 4)
89enddef
90
91def Test_missing_endfunc_enddef()
92  var lines =<< trim END
93    vim9script
94    def Test()
95      echo 'test'
96    endef
97  END
98  CheckScriptFailure(lines, 'E1057:', 2)
99
100  lines =<< trim END
101    vim9script
102    func Some()
103      echo 'test'
104    enfffunc
105  END
106  CheckScriptFailure(lines, 'E126:', 2)
107enddef
108
109def Test_white_space_before_paren()
110  var lines =<< trim END
111    vim9script
112    def Test ()
113      echo 'test'
114    enddef
115  END
116  CheckScriptFailure(lines, 'E1068:', 2)
117
118  lines =<< trim END
119    vim9script
120    func Test ()
121      echo 'test'
122    endfunc
123  END
124  CheckScriptFailure(lines, 'E1068:', 2)
125
126  lines =<< trim END
127    def Test ()
128      echo 'test'
129    enddef
130  END
131  CheckScriptFailure(lines, 'E1068:', 1)
132
133  lines =<< trim END
134    func Test ()
135      echo 'test'
136    endfunc
137  END
138  CheckScriptSuccess(lines)
139enddef
140
141def Test_enddef_dict_key()
142  var d = {
143    enddef: 'x',
144    endfunc: 'y',
145  }
146  assert_equal({enddef: 'x', endfunc: 'y'}, d)
147enddef
148
149def ReturnString(): string
150  return 'string'
151enddef
152
153def ReturnNumber(): number
154  return 123
155enddef
156
157let g:notNumber = 'string'
158
159def ReturnGlobal(): number
160  return g:notNumber
161enddef
162
163def Test_return_something()
164  ReturnString()->assert_equal('string')
165  ReturnNumber()->assert_equal(123)
166  assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal')
167enddef
168
169def Test_check_argument_type()
170  var lines =<< trim END
171      vim9script
172      def Val(a: number, b: number): number
173        return 0
174      enddef
175      def Func()
176        var x: any = true
177        Val(0, x)
178      enddef
179      disass Func
180      Func()
181  END
182  CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got bool', 2)
183enddef
184
185def Test_missing_return()
186  CheckDefFailure(['def Missing(): number',
187                   '  if g:cond',
188                   '    echo "no return"',
189                   '  else',
190                   '    return 0',
191                   '  endif'
192                   'enddef'], 'E1027:')
193  CheckDefFailure(['def Missing(): number',
194                   '  if g:cond',
195                   '    return 1',
196                   '  else',
197                   '    echo "no return"',
198                   '  endif'
199                   'enddef'], 'E1027:')
200  CheckDefFailure(['def Missing(): number',
201                   '  if g:cond',
202                   '    return 1',
203                   '  else',
204                   '    return 2',
205                   '  endif'
206                   '  return 3'
207                   'enddef'], 'E1095:')
208enddef
209
210def Test_return_bool()
211  var lines =<< trim END
212      vim9script
213      def MenuFilter(id: number, key: string): bool
214        return popup_filter_menu(id, key)
215      enddef
216      def YesnoFilter(id: number, key: string): bool
217        return popup_filter_yesno(id, key)
218      enddef
219      defcompile
220  END
221  CheckScriptSuccess(lines)
222enddef
223
224let s:nothing = 0
225def ReturnNothing()
226  s:nothing = 1
227  if true
228    return
229  endif
230  s:nothing = 2
231enddef
232
233def Test_return_nothing()
234  ReturnNothing()
235  s:nothing->assert_equal(1)
236enddef
237
238def Test_return_invalid()
239  var lines =<< trim END
240    vim9script
241    def Func(): invalid
242      return xxx
243    enddef
244    defcompile
245  END
246  CheckScriptFailure(lines, 'E1010:', 2)
247
248  lines =<< trim END
249      vim9script
250      def Test(Fun: func(number): number): list<number>
251          return map([1, 2, 3], (_, i) => Fun(i))
252      enddef
253      defcompile
254      def Inc(nr: number): nr
255        return nr + 2
256      enddef
257      echo Test(Inc)
258  END
259  # doing this twice was leaking memory
260  CheckScriptFailure(lines, 'E1010:')
261  CheckScriptFailure(lines, 'E1010:')
262enddef
263
264func Increment()
265  let g:counter += 1
266endfunc
267
268def Test_call_ufunc_count()
269  g:counter = 1
270  Increment()
271  Increment()
272  Increment()
273  # works with and without :call
274  g:counter->assert_equal(4)
275  eval g:counter->assert_equal(4)
276  unlet g:counter
277enddef
278
279def MyVarargs(arg: string, ...rest: list<string>): string
280  var res = arg
281  for s in rest
282    res ..= ',' .. s
283  endfor
284  return res
285enddef
286
287def Test_call_varargs()
288  MyVarargs('one')->assert_equal('one')
289  MyVarargs('one', 'two')->assert_equal('one,two')
290  MyVarargs('one', 'two', 'three')->assert_equal('one,two,three')
291enddef
292
293def MyDefaultArgs(name = 'string'): string
294  return name
295enddef
296
297def MyDefaultSecond(name: string, second: bool  = true): string
298  return second ? name : 'none'
299enddef
300
301def Test_call_default_args()
302  MyDefaultArgs()->assert_equal('string')
303  MyDefaultArgs('one')->assert_equal('one')
304  assert_fails('MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args')
305
306  MyDefaultSecond('test')->assert_equal('test')
307  MyDefaultSecond('test', true)->assert_equal('test')
308  MyDefaultSecond('test', false)->assert_equal('none')
309
310  CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:')
311  delfunc g:Func
312  CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: Argument 1: type mismatch, expected number but got string')
313  delfunc g:Func
314
315  var lines =<< trim END
316      vim9script
317      def Func(a = b == 0 ? 1 : 2, b = 0)
318      enddef
319      defcompile
320  END
321  CheckScriptFailure(lines, 'E1001: Variable not found: b')
322enddef
323
324def FuncWithComment(  # comment
325  a: number, #comment
326  b: bool, # comment
327  c: string) #comment
328  assert_equal(4, a)
329  assert_equal(true, b)
330  assert_equal('yes', c)
331enddef
332
333def Test_func_with_comments()
334  FuncWithComment(4, true, 'yes')
335
336  var lines =<< trim END
337      def Func(# comment
338        arg: string)
339      enddef
340  END
341  CheckScriptFailure(lines, 'E125:', 1)
342
343  lines =<< trim END
344      def Func(
345        arg: string# comment
346        )
347      enddef
348  END
349  CheckScriptFailure(lines, 'E475:', 2)
350
351  lines =<< trim END
352      def Func(
353        arg: string
354        )# comment
355      enddef
356  END
357  CheckScriptFailure(lines, 'E488:', 3)
358enddef
359
360def Test_nested_function()
361  def Nested(arg: string): string
362    return 'nested ' .. arg
363  enddef
364  Nested('function')->assert_equal('nested function')
365
366  CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
367  CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
368
369  CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
370  CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
371  CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
372
373  var lines =<< trim END
374      def Outer()
375        def Inner()
376          # comment
377        enddef
378        def Inner()
379        enddef
380      enddef
381  END
382  CheckDefFailure(lines, 'E1073:')
383
384  lines =<< trim END
385      def Outer()
386        def Inner()
387          # comment
388        enddef
389        def! Inner()
390        enddef
391      enddef
392  END
393  CheckDefFailure(lines, 'E1117:')
394
395  # nested function inside conditional
396  # TODO: should it work when "thecount" is inside the "if"?
397  lines =<< trim END
398      vim9script
399      var thecount = 0
400      if true
401        def Test(): number
402          def TheFunc(): number
403            thecount += 1
404            return thecount
405          enddef
406          return TheFunc()
407        enddef
408      endif
409      defcompile
410      assert_equal(1, Test())
411      assert_equal(2, Test())
412  END
413  CheckScriptSuccess(lines)
414enddef
415
416def Test_not_nested_function()
417  echo printf('%d',
418      function('len')('xxx'))
419enddef
420
421func Test_call_default_args_from_func()
422  call MyDefaultArgs()->assert_equal('string')
423  call MyDefaultArgs('one')->assert_equal('one')
424  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args_from_func')
425endfunc
426
427def Test_nested_global_function()
428  var lines =<< trim END
429      vim9script
430      def Outer()
431          def g:Inner(): string
432              return 'inner'
433          enddef
434      enddef
435      defcompile
436      Outer()
437      g:Inner()->assert_equal('inner')
438      delfunc g:Inner
439      Outer()
440      g:Inner()->assert_equal('inner')
441      delfunc g:Inner
442      Outer()
443      g:Inner()->assert_equal('inner')
444      delfunc g:Inner
445  END
446  CheckScriptSuccess(lines)
447
448  lines =<< trim END
449      vim9script
450      def Outer()
451          def g:Inner(): string
452              return 'inner'
453          enddef
454      enddef
455      defcompile
456      Outer()
457      Outer()
458  END
459  CheckScriptFailure(lines, "E122:")
460  delfunc g:Inner
461
462  lines =<< trim END
463      vim9script
464      def Outer()
465        def g:Inner()
466          echo map([1, 2, 3], (_, v) => v + 1)
467        enddef
468        g:Inner()
469      enddef
470      Outer()
471  END
472  CheckScriptSuccess(lines)
473  delfunc g:Inner
474
475  lines =<< trim END
476      vim9script
477      def Func()
478        echo 'script'
479      enddef
480      def Outer()
481        def Func()
482          echo 'inner'
483        enddef
484      enddef
485      defcompile
486  END
487  CheckScriptFailure(lines, "E1073:")
488enddef
489
490def DefListAll()
491  def
492enddef
493
494def DefListOne()
495  def DefListOne
496enddef
497
498def DefListMatches()
499  def /DefList
500enddef
501
502def Test_nested_def_list()
503  var funcs = split(execute('call DefListAll()'), "\n")
504  assert_true(len(funcs) > 10)
505  assert_true(funcs->index('def DefListAll()') >= 0)
506
507  funcs = split(execute('call DefListOne()'), "\n")
508  assert_equal(['   def DefListOne()', '1    def DefListOne', '   enddef'], funcs)
509
510  funcs = split(execute('call DefListMatches()'), "\n")
511  assert_true(len(funcs) >= 3)
512  assert_true(funcs->index('def DefListAll()') >= 0)
513  assert_true(funcs->index('def DefListOne()') >= 0)
514  assert_true(funcs->index('def DefListMatches()') >= 0)
515
516  var lines =<< trim END
517    vim9script
518    def Func()
519      def +Func+
520    enddef
521    defcompile
522  END
523  CheckScriptFailure(lines, 'E476:', 1)
524enddef
525
526def Test_global_local_function()
527  var lines =<< trim END
528      vim9script
529      def g:Func(): string
530          return 'global'
531      enddef
532      def Func(): string
533          return 'local'
534      enddef
535      g:Func()->assert_equal('global')
536      Func()->assert_equal('local')
537      delfunc g:Func
538  END
539  CheckScriptSuccess(lines)
540
541  lines =<< trim END
542      vim9script
543      def g:Funcy()
544        echo 'funcy'
545      enddef
546      s:Funcy()
547  END
548  CheckScriptFailure(lines, 'E117:')
549enddef
550
551def Test_local_function_shadows_global()
552  var lines =<< trim END
553      vim9script
554      def g:Gfunc(): string
555        return 'global'
556      enddef
557      def AnotherFunc(): number
558        var Gfunc = function('len')
559        return Gfunc('testing')
560      enddef
561      g:Gfunc()->assert_equal('global')
562      AnotherFunc()->assert_equal(7)
563      delfunc g:Gfunc
564  END
565  CheckScriptSuccess(lines)
566
567  lines =<< trim END
568      vim9script
569      def g:Func(): string
570        return 'global'
571      enddef
572      def AnotherFunc()
573        g:Func = function('len')
574      enddef
575      AnotherFunc()
576  END
577  CheckScriptFailure(lines, 'E705:')
578  delfunc g:Func
579enddef
580
581func TakesOneArg(arg)
582  echo a:arg
583endfunc
584
585def Test_call_wrong_args()
586  CheckDefFailure(['TakesOneArg()'], 'E119:')
587  CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
588  CheckDefFailure(['bufnr(xxx)'], 'E1001:')
589  CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:')
590
591  var lines =<< trim END
592    vim9script
593    def Func(s: string)
594      echo s
595    enddef
596    Func([])
597  END
598  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 5)
599
600  lines =<< trim END
601    vim9script
602    var name = 'piet'
603    def FuncOne(name: string)
604      echo nr
605    enddef
606  END
607  CheckScriptFailure(lines, 'E1168:')
608
609  lines =<< trim END
610    vim9script
611    def FuncOne(nr: number)
612      echo nr
613    enddef
614    def FuncTwo()
615      FuncOne()
616    enddef
617    defcompile
618  END
619  writefile(lines, 'Xscript')
620  var didCatch = false
621  try
622    source Xscript
623  catch
624    assert_match('E119: Not enough arguments for function: <SNR>\d\+_FuncOne', v:exception)
625    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
626    didCatch = true
627  endtry
628  assert_true(didCatch)
629
630  lines =<< trim END
631    vim9script
632    def FuncOne(nr: number)
633      echo nr
634    enddef
635    def FuncTwo()
636      FuncOne(1, 2)
637    enddef
638    defcompile
639  END
640  writefile(lines, 'Xscript')
641  didCatch = false
642  try
643    source Xscript
644  catch
645    assert_match('E118: Too many arguments for function: <SNR>\d\+_FuncOne', v:exception)
646    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
647    didCatch = true
648  endtry
649  assert_true(didCatch)
650
651  delete('Xscript')
652enddef
653
654def Test_call_funcref_wrong_args()
655  var head =<< trim END
656      vim9script
657      def Func3(a1: string, a2: number, a3: list<number>)
658        echo a1 .. a2 .. a3[0]
659      enddef
660      def Testme()
661        var funcMap: dict<func> = {func: Func3}
662  END
663  var tail =<< trim END
664      enddef
665      Testme()
666  END
667  CheckScriptSuccess(head + ["funcMap['func']('str', 123, [1, 2, 3])"] + tail)
668
669  CheckScriptFailure(head + ["funcMap['func']('str', 123)"] + tail, 'E119:')
670  CheckScriptFailure(head + ["funcMap['func']('str', 123, [1], 4)"] + tail, 'E118:')
671
672  var lines =<< trim END
673      vim9script
674      var Ref: func(number): any
675      Ref = (j) => !j
676      echo Ref(false)
677  END
678  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4)
679
680  lines =<< trim END
681      vim9script
682      var Ref: func(number): any
683      Ref = (j) => !j
684      call Ref(false)
685  END
686  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4)
687enddef
688
689def Test_call_lambda_args()
690  CheckDefFailure(['echo ((i) => 0)()'],
691                  'E119: Not enough arguments for function: ((i) => 0)()')
692
693  var lines =<< trim END
694      var Ref = (x: number, y: number) => x + y
695      echo Ref(1, 'x')
696  END
697  CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string')
698
699  lines =<< trim END
700    var Ref: func(job, string, number)
701    Ref = (x, y) => 0
702  END
703  CheckDefAndScriptFailure(lines, 'E1012:')
704
705  lines =<< trim END
706    var Ref: func(job, string)
707    Ref = (x, y, z) => 0
708  END
709  CheckDefAndScriptFailure(lines, 'E1012:')
710
711  lines =<< trim END
712      var one = 1
713      var l = [1, 2, 3]
714      echo map(l, (one) => one)
715  END
716  CheckDefFailure(lines, 'E1167:')
717  CheckScriptFailure(['vim9script'] + lines, 'E1168:')
718
719  lines =<< trim END
720      def ShadowLocal()
721        var one = 1
722        var l = [1, 2, 3]
723        echo map(l, (one) => one)
724      enddef
725  END
726  CheckDefFailure(lines, 'E1167:')
727
728  lines =<< trim END
729      def Shadowarg(one: number)
730        var l = [1, 2, 3]
731        echo map(l, (one) => one)
732      enddef
733  END
734  CheckDefFailure(lines, 'E1167:')
735enddef
736
737def Test_lambda_return_type()
738  var lines =<< trim END
739    var Ref = (): => 123
740  END
741  CheckDefAndScriptFailure(lines, 'E1157:', 1)
742enddef
743
744def Test_lambda_uses_assigned_var()
745  CheckDefSuccess([
746        'var x: any = "aaa"'
747        'x = filter(["bbb"], (_, v) => v =~ x)'])
748enddef
749
750def Test_pass_legacy_lambda_to_def_func()
751  var lines =<< trim END
752      vim9script
753      func Foo()
754        eval s:Bar({x -> 0})
755      endfunc
756      def Bar(y: any)
757      enddef
758      Foo()
759  END
760  CheckScriptSuccess(lines)
761enddef
762
763" Default arg and varargs
764def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
765  var res = one .. ',' .. two
766  for s in rest
767    res ..= ',' .. s
768  endfor
769  return res
770enddef
771
772def Test_call_def_varargs()
773  assert_fails('MyDefVarargs()', 'E119:', '', 1, 'Test_call_def_varargs')
774  MyDefVarargs('one')->assert_equal('one,foo')
775  MyDefVarargs('one', 'two')->assert_equal('one,two')
776  MyDefVarargs('one', 'two', 'three')->assert_equal('one,two,three')
777  CheckDefFailure(['MyDefVarargs("one", 22)'],
778      'E1013: Argument 2: type mismatch, expected string but got number')
779  CheckDefFailure(['MyDefVarargs("one", "two", 123)'],
780      'E1013: Argument 3: type mismatch, expected string but got number')
781
782  var lines =<< trim END
783      vim9script
784      def Func(...l: list<string>)
785        echo l
786      enddef
787      Func('a', 'b', 'c')
788  END
789  CheckScriptSuccess(lines)
790
791  lines =<< trim END
792      vim9script
793      def Func(...l: list<string>)
794        echo l
795      enddef
796      Func()
797  END
798  CheckScriptSuccess(lines)
799
800  lines =<< trim END
801      vim9script
802      def Func(...l: any)
803        echo l
804      enddef
805      Func(0)
806  END
807  CheckScriptSuccess(lines)
808
809  lines =<< trim END
810      vim9script
811      def Func(..._l: list<string>)
812        echo _l
813      enddef
814      Func('a', 'b', 'c')
815  END
816  CheckScriptSuccess(lines)
817
818  lines =<< trim END
819      vim9script
820      def Func(...l: list<string>)
821        echo l
822      enddef
823      Func(1, 2, 3)
824  END
825  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
826
827  lines =<< trim END
828      vim9script
829      def Func(...l: list<string>)
830        echo l
831      enddef
832      Func('a', 9)
833  END
834  CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch')
835
836  lines =<< trim END
837      vim9script
838      def Func(...l: list<string>)
839        echo l
840      enddef
841      Func(1, 'a')
842  END
843  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
844
845  lines =<< trim END
846      vim9script
847      def Func(  # some comment
848                ...l = []
849                )
850        echo l
851      enddef
852  END
853  CheckScriptFailure(lines, 'E1160:')
854enddef
855
856let s:value = ''
857
858def FuncOneDefArg(opt = 'text')
859  s:value = opt
860enddef
861
862def FuncTwoDefArg(nr = 123, opt = 'text'): string
863  return nr .. opt
864enddef
865
866def FuncVarargs(...arg: list<string>): string
867  return join(arg, ',')
868enddef
869
870def Test_func_type_varargs()
871  var RefDefArg: func(?string)
872  RefDefArg = FuncOneDefArg
873  RefDefArg()
874  s:value->assert_equal('text')
875  RefDefArg('some')
876  s:value->assert_equal('some')
877
878  var RefDef2Arg: func(?number, ?string): string
879  RefDef2Arg = FuncTwoDefArg
880  RefDef2Arg()->assert_equal('123text')
881  RefDef2Arg(99)->assert_equal('99text')
882  RefDef2Arg(77, 'some')->assert_equal('77some')
883
884  CheckDefFailure(['var RefWrong: func(string?)'], 'E1010:')
885  CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:')
886
887  var RefVarargs: func(...list<string>): string
888  RefVarargs = FuncVarargs
889  RefVarargs()->assert_equal('')
890  RefVarargs('one')->assert_equal('one')
891  RefVarargs('one', 'two')->assert_equal('one,two')
892
893  CheckDefFailure(['var RefWrong: func(...list<string>, string)'], 'E110:')
894  CheckDefFailure(['var RefWrong: func(...list<string>, ?string)'], 'E110:')
895enddef
896
897" Only varargs
898def MyVarargsOnly(...args: list<string>): string
899  return join(args, ',')
900enddef
901
902def Test_call_varargs_only()
903  MyVarargsOnly()->assert_equal('')
904  MyVarargsOnly('one')->assert_equal('one')
905  MyVarargsOnly('one', 'two')->assert_equal('one,two')
906  CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: Argument 1: type mismatch, expected string but got number')
907  CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number')
908enddef
909
910def Test_using_var_as_arg()
911  writefile(['def Func(x: number)',  'var x = 234', 'enddef', 'defcompile'], 'Xdef')
912  assert_fails('so Xdef', 'E1006:', '', 1, 'Func')
913  delete('Xdef')
914enddef
915
916def DictArg(arg: dict<string>)
917  arg['key'] = 'value'
918enddef
919
920def ListArg(arg: list<string>)
921  arg[0] = 'value'
922enddef
923
924def Test_assign_to_argument()
925  # works for dict and list
926  var d: dict<string> = {}
927  DictArg(d)
928  d['key']->assert_equal('value')
929  var l: list<string> = []
930  ListArg(l)
931  l[0]->assert_equal('value')
932
933  CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:')
934  delfunc! g:Func
935enddef
936
937" These argument names are reserved in legacy functions.
938def WithReservedNames(firstline: string, lastline: string): string
939  return firstline .. lastline
940enddef
941
942def Test_argument_names()
943  assert_equal('OK', WithReservedNames('O', 'K'))
944enddef
945
946def Test_call_func_defined_later()
947  g:DefinedLater('one')->assert_equal('one')
948  assert_fails('NotDefined("one")', 'E117:', '', 2, 'Test_call_func_defined_later')
949enddef
950
951func DefinedLater(arg)
952  return a:arg
953endfunc
954
955def Test_call_funcref()
956  g:SomeFunc('abc')->assert_equal(3)
957  assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call
958  assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref')
959
960  var lines =<< trim END
961    vim9script
962    def RetNumber(): number
963      return 123
964    enddef
965    var Funcref: func: number = function('RetNumber')
966    Funcref()->assert_equal(123)
967  END
968  CheckScriptSuccess(lines)
969
970  lines =<< trim END
971    vim9script
972    def RetNumber(): number
973      return 123
974    enddef
975    def Bar(F: func: number): number
976      return F()
977    enddef
978    var Funcref = function('RetNumber')
979    Bar(Funcref)->assert_equal(123)
980  END
981  CheckScriptSuccess(lines)
982
983  lines =<< trim END
984    vim9script
985    def UseNumber(nr: number)
986      echo nr
987    enddef
988    var Funcref: func(number) = function('UseNumber')
989    Funcref(123)
990  END
991  CheckScriptSuccess(lines)
992
993  lines =<< trim END
994    vim9script
995    def UseNumber(nr: number)
996      echo nr
997    enddef
998    var Funcref: func(string) = function('UseNumber')
999  END
1000  CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)')
1001
1002  lines =<< trim END
1003    vim9script
1004    def EchoNr(nr = 34)
1005      g:echo = nr
1006    enddef
1007    var Funcref: func(?number) = function('EchoNr')
1008    Funcref()
1009    g:echo->assert_equal(34)
1010    Funcref(123)
1011    g:echo->assert_equal(123)
1012  END
1013  CheckScriptSuccess(lines)
1014
1015  lines =<< trim END
1016    vim9script
1017    def EchoList(...l: list<number>)
1018      g:echo = l
1019    enddef
1020    var Funcref: func(...list<number>) = function('EchoList')
1021    Funcref()
1022    g:echo->assert_equal([])
1023    Funcref(1, 2, 3)
1024    g:echo->assert_equal([1, 2, 3])
1025  END
1026  CheckScriptSuccess(lines)
1027
1028  lines =<< trim END
1029    vim9script
1030    def OptAndVar(nr: number, opt = 12, ...l: list<number>): number
1031      g:optarg = opt
1032      g:listarg = l
1033      return nr
1034    enddef
1035    var Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar')
1036    Funcref(10)->assert_equal(10)
1037    g:optarg->assert_equal(12)
1038    g:listarg->assert_equal([])
1039
1040    Funcref(11, 22)->assert_equal(11)
1041    g:optarg->assert_equal(22)
1042    g:listarg->assert_equal([])
1043
1044    Funcref(17, 18, 1, 2, 3)->assert_equal(17)
1045    g:optarg->assert_equal(18)
1046    g:listarg->assert_equal([1, 2, 3])
1047  END
1048  CheckScriptSuccess(lines)
1049enddef
1050
1051let SomeFunc = function('len')
1052let NotAFunc = 'text'
1053
1054def CombineFuncrefTypes()
1055  # same arguments, different return type
1056  var Ref1: func(bool): string
1057  var Ref2: func(bool): number
1058  var Ref3: func(bool): any
1059  Ref3 = g:cond ? Ref1 : Ref2
1060
1061  # different number of arguments
1062  var Refa1: func(bool): number
1063  var Refa2: func(bool, number): number
1064  var Refa3: func: number
1065  Refa3 = g:cond ? Refa1 : Refa2
1066
1067  # different argument types
1068  var Refb1: func(bool, string): number
1069  var Refb2: func(string, number): number
1070  var Refb3: func(any, any): number
1071  Refb3 = g:cond ? Refb1 : Refb2
1072enddef
1073
1074def FuncWithForwardCall()
1075  return g:DefinedEvenLater("yes")
1076enddef
1077
1078def DefinedEvenLater(arg: string): string
1079  return arg
1080enddef
1081
1082def Test_error_in_nested_function()
1083  # Error in called function requires unwinding the call stack.
1084  assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall')
1085enddef
1086
1087def Test_return_type_wrong()
1088  CheckScriptFailure([
1089        'def Func(): number',
1090        'return "a"',
1091        'enddef',
1092        'defcompile'], 'expected number but got string')
1093  delfunc! g:Func
1094  CheckScriptFailure([
1095        'def Func(): string',
1096        'return 1',
1097        'enddef',
1098        'defcompile'], 'expected string but got number')
1099  delfunc! g:Func
1100  CheckScriptFailure([
1101        'def Func(): void',
1102        'return "a"',
1103        'enddef',
1104        'defcompile'],
1105        'E1096: Returning a value in a function without a return type')
1106  delfunc! g:Func
1107  CheckScriptFailure([
1108        'def Func()',
1109        'return "a"',
1110        'enddef',
1111        'defcompile'],
1112        'E1096: Returning a value in a function without a return type')
1113  delfunc! g:Func
1114
1115  CheckScriptFailure([
1116        'def Func(): number',
1117        'return',
1118        'enddef',
1119        'defcompile'], 'E1003:')
1120  delfunc! g:Func
1121
1122  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
1123  delfunc! g:Func
1124  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
1125  delfunc! g:Func
1126  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
1127  delfunc! g:Func
1128
1129  CheckScriptFailure([
1130        'vim9script',
1131        'def FuncB()',
1132        '  return 123',
1133        'enddef',
1134        'def FuncA()',
1135        '   FuncB()',
1136        'enddef',
1137        'defcompile'], 'E1096:')
1138enddef
1139
1140def Test_arg_type_wrong()
1141  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
1142  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
1143  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
1144  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
1145enddef
1146
1147def Test_white_space_after_comma()
1148  var lines =<< trim END
1149    vim9script
1150    def Func(a: number,b: number)
1151    enddef
1152  END
1153  CheckScriptFailure(lines, 'E1069:')
1154
1155  # OK in legacy function
1156  lines =<< trim END
1157    vim9script
1158    func Func(a,b)
1159    endfunc
1160  END
1161  CheckScriptSuccess(lines)
1162enddef
1163
1164def Test_vim9script_call()
1165  var lines =<< trim END
1166    vim9script
1167    var name = ''
1168    def MyFunc(arg: string)
1169       name = arg
1170    enddef
1171    MyFunc('foobar')
1172    name->assert_equal('foobar')
1173
1174    var str = 'barfoo'
1175    str->MyFunc()
1176    name->assert_equal('barfoo')
1177
1178    g:value = 'value'
1179    g:value->MyFunc()
1180    name->assert_equal('value')
1181
1182    var listvar = []
1183    def ListFunc(arg: list<number>)
1184       listvar = arg
1185    enddef
1186    [1, 2, 3]->ListFunc()
1187    listvar->assert_equal([1, 2, 3])
1188
1189    var dictvar = {}
1190    def DictFunc(arg: dict<number>)
1191       dictvar = arg
1192    enddef
1193    {a: 1, b: 2}->DictFunc()
1194    dictvar->assert_equal({a: 1, b: 2})
1195    def CompiledDict()
1196      {a: 3, b: 4}->DictFunc()
1197    enddef
1198    CompiledDict()
1199    dictvar->assert_equal({a: 3, b: 4})
1200
1201    {a: 3, b: 4}->DictFunc()
1202    dictvar->assert_equal({a: 3, b: 4})
1203
1204    ('text')->MyFunc()
1205    name->assert_equal('text')
1206    ("some")->MyFunc()
1207    name->assert_equal('some')
1208
1209    # line starting with single quote is not a mark
1210    # line starting with double quote can be a method call
1211    'asdfasdf'->MyFunc()
1212    name->assert_equal('asdfasdf')
1213    "xyz"->MyFunc()
1214    name->assert_equal('xyz')
1215
1216    def UseString()
1217      'xyork'->MyFunc()
1218    enddef
1219    UseString()
1220    name->assert_equal('xyork')
1221
1222    def UseString2()
1223      "knife"->MyFunc()
1224    enddef
1225    UseString2()
1226    name->assert_equal('knife')
1227
1228    # prepending a colon makes it a mark
1229    new
1230    setline(1, ['aaa', 'bbb', 'ccc'])
1231    normal! 3Gmt1G
1232    :'t
1233    getcurpos()[1]->assert_equal(3)
1234    bwipe!
1235
1236    MyFunc(
1237        'continued'
1238        )
1239    assert_equal('continued',
1240            name
1241            )
1242
1243    call MyFunc(
1244        'more'
1245          ..
1246          'lines'
1247        )
1248    assert_equal(
1249        'morelines',
1250        name)
1251  END
1252  writefile(lines, 'Xcall.vim')
1253  source Xcall.vim
1254  delete('Xcall.vim')
1255enddef
1256
1257def Test_vim9script_call_fail_decl()
1258  var lines =<< trim END
1259    vim9script
1260    var name = ''
1261    def MyFunc(arg: string)
1262       var name = 123
1263    enddef
1264    defcompile
1265  END
1266  CheckScriptFailure(lines, 'E1054:')
1267enddef
1268
1269def Test_vim9script_call_fail_type()
1270  var lines =<< trim END
1271    vim9script
1272    def MyFunc(arg: string)
1273      echo arg
1274    enddef
1275    MyFunc(1234)
1276  END
1277  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
1278enddef
1279
1280def Test_vim9script_call_fail_const()
1281  var lines =<< trim END
1282    vim9script
1283    const var = ''
1284    def MyFunc(arg: string)
1285       var = 'asdf'
1286    enddef
1287    defcompile
1288  END
1289  writefile(lines, 'Xcall_const.vim')
1290  assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
1291  delete('Xcall_const.vim')
1292
1293  lines =<< trim END
1294      const g:Aconst = 77
1295      def Change()
1296        # comment
1297        g:Aconst = 99
1298      enddef
1299      call Change()
1300      unlet g:Aconst
1301  END
1302  CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2)
1303enddef
1304
1305" Test that inside :function a Python function can be defined, :def is not
1306" recognized.
1307func Test_function_python()
1308  CheckFeature python3
1309  let py = 'python3'
1310  execute py "<< EOF"
1311def do_something():
1312  return 1
1313EOF
1314endfunc
1315
1316def Test_delfunc()
1317  var lines =<< trim END
1318    vim9script
1319    def g:GoneSoon()
1320      echo 'hello'
1321    enddef
1322
1323    def CallGoneSoon()
1324      GoneSoon()
1325    enddef
1326    defcompile
1327
1328    delfunc g:GoneSoon
1329    CallGoneSoon()
1330  END
1331  writefile(lines, 'XToDelFunc')
1332  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1333  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
1334
1335  delete('XToDelFunc')
1336enddef
1337
1338def Test_redef_failure()
1339  writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
1340  so Xdef
1341  writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
1342  so Xdef
1343  writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
1344  assert_fails('so Xdef', 'E1027:', '', 1, 'Func0')
1345  writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
1346  so Xdef
1347  delete('Xdef')
1348
1349  g:Func0()->assert_equal(0)
1350  g:Func1()->assert_equal('Func1')
1351  g:Func2()->assert_equal('Func2')
1352
1353  delfunc! Func0
1354  delfunc! Func1
1355  delfunc! Func2
1356enddef
1357
1358def Test_vim9script_func()
1359  var lines =<< trim END
1360    vim9script
1361    func Func(arg)
1362      echo a:arg
1363    endfunc
1364    Func('text')
1365  END
1366  writefile(lines, 'XVim9Func')
1367  so XVim9Func
1368
1369  delete('XVim9Func')
1370enddef
1371
1372let s:funcResult = 0
1373
1374def FuncNoArgNoRet()
1375  s:funcResult = 11
1376enddef
1377
1378def FuncNoArgRetNumber(): number
1379  s:funcResult = 22
1380  return 1234
1381enddef
1382
1383def FuncNoArgRetString(): string
1384  s:funcResult = 45
1385  return 'text'
1386enddef
1387
1388def FuncOneArgNoRet(arg: number)
1389  s:funcResult = arg
1390enddef
1391
1392def FuncOneArgRetNumber(arg: number): number
1393  s:funcResult = arg
1394  return arg
1395enddef
1396
1397def FuncTwoArgNoRet(one: bool, two: number)
1398  s:funcResult = two
1399enddef
1400
1401def FuncOneArgRetString(arg: string): string
1402  return arg
1403enddef
1404
1405def FuncOneArgRetAny(arg: any): any
1406  return arg
1407enddef
1408
1409def Test_func_type()
1410  var Ref1: func()
1411  s:funcResult = 0
1412  Ref1 = FuncNoArgNoRet
1413  Ref1()
1414  s:funcResult->assert_equal(11)
1415
1416  var Ref2: func
1417  s:funcResult = 0
1418  Ref2 = FuncNoArgNoRet
1419  Ref2()
1420  s:funcResult->assert_equal(11)
1421
1422  s:funcResult = 0
1423  Ref2 = FuncOneArgNoRet
1424  Ref2(12)
1425  s:funcResult->assert_equal(12)
1426
1427  s:funcResult = 0
1428  Ref2 = FuncNoArgRetNumber
1429  Ref2()->assert_equal(1234)
1430  s:funcResult->assert_equal(22)
1431
1432  s:funcResult = 0
1433  Ref2 = FuncOneArgRetNumber
1434  Ref2(13)->assert_equal(13)
1435  s:funcResult->assert_equal(13)
1436enddef
1437
1438def Test_repeat_return_type()
1439  var res = 0
1440  for n in repeat([1], 3)
1441    res += n
1442  endfor
1443  res->assert_equal(3)
1444
1445  res = 0
1446  for n in add([1, 2], 3)
1447    res += n
1448  endfor
1449  res->assert_equal(6)
1450enddef
1451
1452def Test_argv_return_type()
1453  next fileone filetwo
1454  var res = ''
1455  for name in argv()
1456    res ..= name
1457  endfor
1458  res->assert_equal('fileonefiletwo')
1459enddef
1460
1461def Test_func_type_part()
1462  var RefVoid: func: void
1463  RefVoid = FuncNoArgNoRet
1464  RefVoid = FuncOneArgNoRet
1465  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
1466  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
1467
1468  var RefAny: func(): any
1469  RefAny = FuncNoArgRetNumber
1470  RefAny = FuncNoArgRetString
1471  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
1472  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
1473
1474  var RefAnyNoArgs: func: any = RefAny
1475
1476  var RefNr: func: number
1477  RefNr = FuncNoArgRetNumber
1478  RefNr = FuncOneArgRetNumber
1479  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1480  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1481
1482  var RefStr: func: string
1483  RefStr = FuncNoArgRetString
1484  RefStr = FuncOneArgRetString
1485  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1486  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1487enddef
1488
1489def Test_func_type_fails()
1490  CheckDefFailure(['var ref1: func()'], 'E704:')
1491
1492  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1493  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1494  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1495  CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1496  CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1497  CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1498
1499  CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
1500  CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
1501  CheckDefFailure(['var RefWrong: func(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)'], 'E1005:')
1502  CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:')
1503enddef
1504
1505def Test_func_return_type()
1506  var nr: number
1507  nr = FuncNoArgRetNumber()
1508  nr->assert_equal(1234)
1509
1510  nr = FuncOneArgRetAny(122)
1511  nr->assert_equal(122)
1512
1513  var str: string
1514  str = FuncOneArgRetAny('yes')
1515  str->assert_equal('yes')
1516
1517  CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
1518enddef
1519
1520def Test_func_common_type()
1521  def FuncOne(n: number): number
1522    return n
1523  enddef
1524  def FuncTwo(s: string): number
1525    return len(s)
1526  enddef
1527  def FuncThree(n: number, s: string): number
1528    return n + len(s)
1529  enddef
1530  var list = [FuncOne, FuncTwo, FuncThree]
1531  assert_equal(8, list[0](8))
1532  assert_equal(4, list[1]('word'))
1533  assert_equal(7, list[2](3, 'word'))
1534enddef
1535
1536def MultiLine(
1537    arg1: string,
1538    arg2 = 1234,
1539    ...rest: list<string>
1540      ): string
1541  return arg1 .. arg2 .. join(rest, '-')
1542enddef
1543
1544def MultiLineComment(
1545    arg1: string, # comment
1546    arg2 = 1234, # comment
1547    ...rest: list<string> # comment
1548      ): string # comment
1549  return arg1 .. arg2 .. join(rest, '-')
1550enddef
1551
1552def Test_multiline()
1553  MultiLine('text')->assert_equal('text1234')
1554  MultiLine('text', 777)->assert_equal('text777')
1555  MultiLine('text', 777, 'one')->assert_equal('text777one')
1556  MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1557enddef
1558
1559func Test_multiline_not_vim9()
1560  call MultiLine('text')->assert_equal('text1234')
1561  call MultiLine('text', 777)->assert_equal('text777')
1562  call MultiLine('text', 777, 'one')->assert_equal('text777one')
1563  call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1564endfunc
1565
1566
1567" When using CheckScriptFailure() for the below test, E1010 is generated instead
1568" of E1056.
1569func Test_E1056_1059()
1570  let caught_1056 = 0
1571  try
1572    def F():
1573      return 1
1574    enddef
1575  catch /E1056:/
1576    let caught_1056 = 1
1577  endtry
1578  eval caught_1056->assert_equal(1)
1579
1580  let caught_1059 = 0
1581  try
1582    def F5(items : list)
1583      echo 'a'
1584    enddef
1585  catch /E1059:/
1586    let caught_1059 = 1
1587  endtry
1588  eval caught_1059->assert_equal(1)
1589endfunc
1590
1591func DelMe()
1592  echo 'DelMe'
1593endfunc
1594
1595def Test_error_reporting()
1596  # comment lines at the start of the function
1597  var lines =<< trim END
1598    " comment
1599    def Func()
1600      # comment
1601      # comment
1602      invalid
1603    enddef
1604    defcompile
1605  END
1606  writefile(lines, 'Xdef')
1607  try
1608    source Xdef
1609    assert_report('should have failed')
1610  catch /E476:/
1611    v:exception->assert_match('Invalid command: invalid')
1612    v:throwpoint->assert_match(', line 3$')
1613  endtry
1614  delfunc! g:Func
1615
1616  # comment lines after the start of the function
1617  lines =<< trim END
1618    " comment
1619    def Func()
1620      var x = 1234
1621      # comment
1622      # comment
1623      invalid
1624    enddef
1625    defcompile
1626  END
1627  writefile(lines, 'Xdef')
1628  try
1629    source Xdef
1630    assert_report('should have failed')
1631  catch /E476:/
1632    v:exception->assert_match('Invalid command: invalid')
1633    v:throwpoint->assert_match(', line 4$')
1634  endtry
1635  delfunc! g:Func
1636
1637  lines =<< trim END
1638    vim9script
1639    def Func()
1640      var db = {foo: 1, bar: 2}
1641      # comment
1642      var x = db.asdf
1643    enddef
1644    defcompile
1645    Func()
1646  END
1647  writefile(lines, 'Xdef')
1648  try
1649    source Xdef
1650    assert_report('should have failed')
1651  catch /E716:/
1652    v:throwpoint->assert_match('_Func, line 3$')
1653  endtry
1654  delfunc! g:Func
1655
1656  delete('Xdef')
1657enddef
1658
1659def Test_deleted_function()
1660  CheckDefExecFailure([
1661      'var RefMe: func = function("g:DelMe")',
1662      'delfunc g:DelMe',
1663      'echo RefMe()'], 'E117:')
1664enddef
1665
1666def Test_unknown_function()
1667  CheckDefExecFailure([
1668      'var Ref: func = function("NotExist")',
1669      'delfunc g:NotExist'], 'E700:')
1670enddef
1671
1672def RefFunc(Ref: func(any): any): string
1673  return Ref('more')
1674enddef
1675
1676def Test_closure_simple()
1677  var local = 'some '
1678  RefFunc((s) => local .. s)->assert_equal('some more')
1679enddef
1680
1681def MakeRef()
1682  var local = 'some '
1683  g:Ref = (s) => local .. s
1684enddef
1685
1686def Test_closure_ref_after_return()
1687  MakeRef()
1688  g:Ref('thing')->assert_equal('some thing')
1689  unlet g:Ref
1690enddef
1691
1692def MakeTwoRefs()
1693  var local = ['some']
1694  g:Extend = (s) => local->add(s)
1695  g:Read = () => local
1696enddef
1697
1698def Test_closure_two_refs()
1699  MakeTwoRefs()
1700  join(g:Read(), ' ')->assert_equal('some')
1701  g:Extend('more')
1702  join(g:Read(), ' ')->assert_equal('some more')
1703  g:Extend('even')
1704  join(g:Read(), ' ')->assert_equal('some more even')
1705
1706  unlet g:Extend
1707  unlet g:Read
1708enddef
1709
1710def ReadRef(Ref: func(): list<string>): string
1711  return join(Ref(), ' ')
1712enddef
1713
1714def ExtendRef(Ref: func(string): list<string>, add: string)
1715  Ref(add)
1716enddef
1717
1718def Test_closure_two_indirect_refs()
1719  MakeTwoRefs()
1720  ReadRef(g:Read)->assert_equal('some')
1721  ExtendRef(g:Extend, 'more')
1722  ReadRef(g:Read)->assert_equal('some more')
1723  ExtendRef(g:Extend, 'even')
1724  ReadRef(g:Read)->assert_equal('some more even')
1725
1726  unlet g:Extend
1727  unlet g:Read
1728enddef
1729
1730def MakeArgRefs(theArg: string)
1731  var local = 'loc_val'
1732  g:UseArg = (s) => theArg .. '/' .. local .. '/' .. s
1733enddef
1734
1735def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1736  var local = 'the_loc'
1737  g:UseVararg = (s) => theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)
1738enddef
1739
1740def Test_closure_using_argument()
1741  MakeArgRefs('arg_val')
1742  g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val')
1743
1744  MakeArgRefsVarargs('arg_val', 'one', 'two')
1745  g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two')
1746
1747  unlet g:UseArg
1748  unlet g:UseVararg
1749
1750  var lines =<< trim END
1751      vim9script
1752      def Test(Fun: func(number): number): list<number>
1753        return map([1, 2, 3], (_, i) => Fun(i))
1754      enddef
1755      def Inc(nr: number): number
1756        return nr + 2
1757      enddef
1758      assert_equal([3, 4, 5], Test(Inc))
1759  END
1760  CheckScriptSuccess(lines)
1761enddef
1762
1763def MakeGetAndAppendRefs()
1764  var local = 'a'
1765
1766  def Append(arg: string)
1767    local ..= arg
1768  enddef
1769  g:Append = Append
1770
1771  def Get(): string
1772    return local
1773  enddef
1774  g:Get = Get
1775enddef
1776
1777def Test_closure_append_get()
1778  MakeGetAndAppendRefs()
1779  g:Get()->assert_equal('a')
1780  g:Append('-b')
1781  g:Get()->assert_equal('a-b')
1782  g:Append('-c')
1783  g:Get()->assert_equal('a-b-c')
1784
1785  unlet g:Append
1786  unlet g:Get
1787enddef
1788
1789def Test_nested_closure()
1790  var local = 'text'
1791  def Closure(arg: string): string
1792    return local .. arg
1793  enddef
1794  Closure('!!!')->assert_equal('text!!!')
1795enddef
1796
1797func GetResult(Ref)
1798  return a:Ref('some')
1799endfunc
1800
1801def Test_call_closure_not_compiled()
1802  var text = 'text'
1803  g:Ref = (s) =>  s .. text
1804  GetResult(g:Ref)->assert_equal('sometext')
1805enddef
1806
1807def Test_double_closure_fails()
1808  var lines =<< trim END
1809    vim9script
1810    def Func()
1811      var name = 0
1812      for i in range(2)
1813          timer_start(0, () => name)
1814      endfor
1815    enddef
1816    Func()
1817  END
1818  CheckScriptSuccess(lines)
1819enddef
1820
1821def Test_nested_closure_used()
1822  var lines =<< trim END
1823      vim9script
1824      def Func()
1825        var x = 'hello'
1826        var Closure = () => x
1827        g:Myclosure = () => Closure()
1828      enddef
1829      Func()
1830      assert_equal('hello', g:Myclosure())
1831  END
1832  CheckScriptSuccess(lines)
1833enddef
1834
1835def Test_nested_closure_fails()
1836  var lines =<< trim END
1837    vim9script
1838    def FuncA()
1839      FuncB(0)
1840    enddef
1841    def FuncB(n: number): list<string>
1842      return map([0], (_, v) => n)
1843    enddef
1844    FuncA()
1845  END
1846  CheckScriptFailure(lines, 'E1012:')
1847enddef
1848
1849def Test_global_closure()
1850  var lines =<< trim END
1851      vim9script
1852      def ReverseEveryNLines(n: number, line1: number, line2: number)
1853        var mods = 'sil keepj keepp lockm '
1854        var range = ':' .. line1 .. ',' .. line2
1855        def g:Offset(): number
1856            var offset = (line('.') - line1 + 1) % n
1857            return offset != 0 ? offset : n
1858        enddef
1859        exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()'
1860      enddef
1861
1862      new
1863      repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1)
1864      ReverseEveryNLines(3, 1, 9)
1865  END
1866  CheckScriptSuccess(lines)
1867  var expected = repeat(['ccc', 'bbb', 'aaa'], 3)
1868  assert_equal(expected, getline(1, 9))
1869  bwipe!
1870enddef
1871
1872def Test_global_closure_called_directly()
1873  var lines =<< trim END
1874      vim9script
1875      def Outer()
1876        var x = 1
1877        def g:Inner()
1878          var y = x
1879          x += 1
1880          assert_equal(1, y)
1881        enddef
1882        g:Inner()
1883        assert_equal(2, x)
1884      enddef
1885      Outer()
1886  END
1887  CheckScriptSuccess(lines)
1888  delfunc g:Inner
1889enddef
1890
1891def Test_failure_in_called_function()
1892  # this was using the frame index as the return value
1893  var lines =<< trim END
1894      vim9script
1895      au TerminalWinOpen * eval [][0]
1896      def PopupTerm(a: any)
1897        # make sure typvals on stack are string
1898        ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join()
1899        FireEvent()
1900      enddef
1901      def FireEvent()
1902          do TerminalWinOpen
1903      enddef
1904      # use try/catch to make eval fail
1905      try
1906          call PopupTerm(0)
1907      catch
1908      endtry
1909      au! TerminalWinOpen
1910  END
1911  CheckScriptSuccess(lines)
1912enddef
1913
1914def Test_nested_lambda()
1915  var lines =<< trim END
1916    vim9script
1917    def Func()
1918      var x = 4
1919      var Lambda1 = () => 7
1920      var Lambda2 = () => [Lambda1(), x]
1921      var res = Lambda2()
1922      assert_equal([7, 4], res)
1923    enddef
1924    Func()
1925  END
1926  CheckScriptSuccess(lines)
1927enddef
1928
1929def Shadowed(): list<number>
1930  var FuncList: list<func: number> = [() => 42]
1931  return FuncList->mapnew((_, Shadowed) => Shadowed())
1932enddef
1933
1934def Test_lambda_arg_shadows_func()
1935  assert_equal([42], Shadowed())
1936enddef
1937
1938def Line_continuation_in_def(dir: string = ''): string
1939  var path: string = empty(dir)
1940          \ ? 'empty'
1941          \ : 'full'
1942  return path
1943enddef
1944
1945def Test_line_continuation_in_def()
1946  Line_continuation_in_def('.')->assert_equal('full')
1947enddef
1948
1949def Test_script_var_in_lambda()
1950  var lines =<< trim END
1951      vim9script
1952      var script = 'test'
1953      assert_equal(['test'], map(['one'], () => script))
1954  END
1955  CheckScriptSuccess(lines)
1956enddef
1957
1958def Line_continuation_in_lambda(): list<string>
1959  var x = range(97, 100)
1960      ->mapnew((_, v) => nr2char(v)
1961          ->toupper())
1962      ->reverse()
1963  return x
1964enddef
1965
1966def Test_line_continuation_in_lambda()
1967  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
1968
1969  var lines =<< trim END
1970      vim9script
1971      var res = [{n: 1, m: 2, s: 'xxx'}]
1972                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
1973                    v.n,
1974                    v.m,
1975                    substitute(v.s, '.*', 'yyy', '')
1976                    ))
1977      assert_equal(['1:2:yyy'], res)
1978  END
1979  CheckScriptSuccess(lines)
1980enddef
1981
1982def Test_list_lambda()
1983  timer_start(1000, (_) => 0)
1984  var body = execute(timer_info()[0].callback
1985         ->string()
1986         ->substitute("('", ' ', '')
1987         ->substitute("')", '', '')
1988         ->substitute('function\zs', ' ', ''))
1989  assert_match('def <lambda>\d\+(_: any, ...): number\n1  return 0\n   enddef', body)
1990enddef
1991
1992def DoFilterThis(a: string): list<string>
1993  # closure nested inside another closure using argument
1994  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
1995  return ['x', 'y', 'a', 'x2', 'c']->Filter()
1996enddef
1997
1998def Test_nested_closure_using_argument()
1999  assert_equal(['x', 'x2'], DoFilterThis('x'))
2000enddef
2001
2002def Test_triple_nested_closure()
2003  var what = 'x'
2004  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
2005  var Filter = (l) => filter(l, (_, v) => Match(v, what))
2006  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
2007enddef
2008
2009func Test_silent_echo()
2010  CheckScreendump
2011
2012  let lines =<< trim END
2013    vim9script
2014    def EchoNothing()
2015      silent echo ''
2016    enddef
2017    defcompile
2018  END
2019  call writefile(lines, 'XTest_silent_echo')
2020
2021  " Check that the balloon shows up after a mouse move
2022  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
2023  call term_sendkeys(buf, ":abc")
2024  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
2025
2026  " clean up
2027  call StopVimInTerminal(buf)
2028  call delete('XTest_silent_echo')
2029endfunc
2030
2031def SilentlyError()
2032  execute('silent! invalid')
2033  g:did_it = 'yes'
2034enddef
2035
2036func UserError()
2037  silent! invalid
2038endfunc
2039
2040def SilentlyUserError()
2041  UserError()
2042  g:did_it = 'yes'
2043enddef
2044
2045" This can't be a :def function, because the assert would not be reached.
2046func Test_ignore_silent_error()
2047  let g:did_it = 'no'
2048  call SilentlyError()
2049  call assert_equal('yes', g:did_it)
2050
2051  let g:did_it = 'no'
2052  call SilentlyUserError()
2053  call assert_equal('yes', g:did_it)
2054
2055  unlet g:did_it
2056endfunc
2057
2058def Test_ignore_silent_error_in_filter()
2059  var lines =<< trim END
2060      vim9script
2061      def Filter(winid: number, key: string): bool
2062          if key == 'o'
2063              silent! eval [][0]
2064              return true
2065          endif
2066          return popup_filter_menu(winid, key)
2067      enddef
2068
2069      popup_create('popup', {filter: Filter})
2070      feedkeys("o\r", 'xnt')
2071  END
2072  CheckScriptSuccess(lines)
2073enddef
2074
2075def Fibonacci(n: number): number
2076  if n < 2
2077    return n
2078  else
2079    return Fibonacci(n - 1) + Fibonacci(n - 2)
2080  endif
2081enddef
2082
2083def Test_recursive_call()
2084  Fibonacci(20)->assert_equal(6765)
2085enddef
2086
2087def TreeWalk(dir: string): list<any>
2088  return readdir(dir)->mapnew((_, val) =>
2089            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2090               ? {[val]: TreeWalk(dir .. '/' .. val)}
2091               : val
2092             )
2093enddef
2094
2095def Test_closure_in_map()
2096  mkdir('XclosureDir/tdir', 'p')
2097  writefile(['111'], 'XclosureDir/file1')
2098  writefile(['222'], 'XclosureDir/file2')
2099  writefile(['333'], 'XclosureDir/tdir/file3')
2100
2101  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2102
2103  delete('XclosureDir', 'rf')
2104enddef
2105
2106def Test_invalid_function_name()
2107  var lines =<< trim END
2108      vim9script
2109      def s: list<string>
2110  END
2111  CheckScriptFailure(lines, 'E129:')
2112
2113  lines =<< trim END
2114      vim9script
2115      def g: list<string>
2116  END
2117  CheckScriptFailure(lines, 'E129:')
2118
2119  lines =<< trim END
2120      vim9script
2121      def <SID>: list<string>
2122  END
2123  CheckScriptFailure(lines, 'E884:')
2124
2125  lines =<< trim END
2126      vim9script
2127      def F list<string>
2128  END
2129  CheckScriptFailure(lines, 'E488:')
2130enddef
2131
2132def Test_partial_call()
2133  var Xsetlist = function('setloclist', [0])
2134  Xsetlist([], ' ', {title: 'test'})
2135  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2136
2137  Xsetlist = function('setloclist', [0, [], ' '])
2138  Xsetlist({title: 'test'})
2139  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2140
2141  Xsetlist = function('setqflist')
2142  Xsetlist([], ' ', {title: 'test'})
2143  getqflist({title: 1})->assert_equal({title: 'test'})
2144
2145  Xsetlist = function('setqflist', [[], ' '])
2146  Xsetlist({title: 'test'})
2147  getqflist({title: 1})->assert_equal({title: 'test'})
2148
2149  var Len: func: number = function('len', ['word'])
2150  assert_equal(4, Len())
2151enddef
2152
2153def Test_cmd_modifier()
2154  tab echo '0'
2155  CheckDefFailure(['5tab echo 3'], 'E16:')
2156enddef
2157
2158def Test_restore_modifiers()
2159  # check that when compiling a :def function command modifiers are not messed
2160  # up.
2161  var lines =<< trim END
2162      vim9script
2163      set eventignore=
2164      autocmd QuickFixCmdPost * copen
2165      def AutocmdsDisabled()
2166        eval 0
2167      enddef
2168      func Func()
2169        noautocmd call s:AutocmdsDisabled()
2170        let g:ei_after = &eventignore
2171      endfunc
2172      Func()
2173  END
2174  CheckScriptSuccess(lines)
2175  g:ei_after->assert_equal('')
2176enddef
2177
2178def StackTop()
2179  eval 1
2180  eval 2
2181  # call not on fourth line
2182  StackBot()
2183enddef
2184
2185def StackBot()
2186  # throw an error
2187  eval [][0]
2188enddef
2189
2190def Test_callstack_def()
2191  try
2192    StackTop()
2193  catch
2194    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2195  endtry
2196enddef
2197
2198" Re-using spot for variable used in block
2199def Test_block_scoped_var()
2200  var lines =<< trim END
2201      vim9script
2202      def Func()
2203        var x = ['a', 'b', 'c']
2204        if 1
2205          var y = 'x'
2206          map(x, () => y)
2207        endif
2208        var z = x
2209        assert_equal(['x', 'x', 'x'], z)
2210      enddef
2211      Func()
2212  END
2213  CheckScriptSuccess(lines)
2214enddef
2215
2216def Test_reset_did_emsg()
2217  var lines =<< trim END
2218      @s = 'blah'
2219      au BufWinLeave * #
2220      def Func()
2221        var winid = popup_create('popup', {})
2222        exe '*s'
2223        popup_close(winid)
2224      enddef
2225      Func()
2226  END
2227  CheckScriptFailure(lines, 'E492:', 8)
2228  delfunc! g:Func
2229enddef
2230
2231def Test_did_emsg_reset()
2232  # executing an autocommand resets did_emsg, this should not result in a
2233  # builtin function considered failing
2234  var lines =<< trim END
2235      vim9script
2236      au BufWinLeave * #
2237      def Func()
2238          popup_menu('', {callback: () => popup_create('', {})->popup_close()})
2239          eval [][0]
2240      enddef
2241      nno <F3> <cmd>call <sid>Func()<cr>
2242      feedkeys("\<F3>\e", 'xt')
2243  END
2244  writefile(lines, 'XemsgReset')
2245  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2246  delete('XemsgReset')
2247  nunmap <F3>
2248  au! BufWinLeave
2249enddef
2250
2251def Test_abort_with_silent_call()
2252  var lines =<< trim END
2253      vim9script
2254      g:result = 'none'
2255      def Func()
2256        g:result += 3
2257        g:result = 'yes'
2258      enddef
2259      # error is silenced, but function aborts on error
2260      silent! Func()
2261      assert_equal('none', g:result)
2262      unlet g:result
2263  END
2264  CheckScriptSuccess(lines)
2265enddef
2266
2267def Test_continues_with_silent_error()
2268  var lines =<< trim END
2269      vim9script
2270      g:result = 'none'
2271      def Func()
2272        silent!  g:result += 3
2273        g:result = 'yes'
2274      enddef
2275      # error is silenced, function does not abort
2276      Func()
2277      assert_equal('yes', g:result)
2278      unlet g:result
2279  END
2280  CheckScriptSuccess(lines)
2281enddef
2282
2283def Test_abort_even_with_silent()
2284  var lines =<< trim END
2285      vim9script
2286      g:result = 'none'
2287      def Func()
2288        eval {-> ''}() .. '' .. {}['X']
2289        g:result = 'yes'
2290      enddef
2291      silent! Func()
2292      assert_equal('none', g:result)
2293      unlet g:result
2294  END
2295  CheckScriptSuccess(lines)
2296enddef
2297
2298def Test_cmdmod_silent_restored()
2299  var lines =<< trim END
2300      vim9script
2301      def Func()
2302        g:result = 'none'
2303        silent! g:result += 3
2304        g:result = 'none'
2305        g:result += 3
2306      enddef
2307      Func()
2308  END
2309  # can't use CheckScriptFailure, it ignores the :silent!
2310  var fname = 'Xdefsilent'
2311  writefile(lines, fname)
2312  var caught = 'no'
2313  try
2314    exe 'source ' .. fname
2315  catch /E1030:/
2316    caught = 'yes'
2317    assert_match('Func, line 4', v:throwpoint)
2318  endtry
2319  assert_equal('yes', caught)
2320  delete(fname)
2321enddef
2322
2323def Test_dict_member_with_silent()
2324  var lines =<< trim END
2325      vim9script
2326      g:result = 'none'
2327      var d: dict<any>
2328      def Func()
2329        try
2330          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2331        catch
2332        endtry
2333      enddef
2334      silent! Func()
2335      assert_equal('0', g:result)
2336      unlet g:result
2337  END
2338  CheckScriptSuccess(lines)
2339enddef
2340
2341def Test_skip_cmds_with_silent()
2342  var lines =<< trim END
2343      vim9script
2344
2345      def Func(b: bool)
2346        Crash()
2347      enddef
2348
2349      def Crash()
2350        sil! :/not found/d _
2351        sil! :/not found/put _
2352      enddef
2353
2354      Func(true)
2355  END
2356  CheckScriptSuccess(lines)
2357enddef
2358
2359def Test_opfunc()
2360  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2361  def g:Opfunc(_: any): string
2362    setline(1, 'ASDF')
2363    return ''
2364  enddef
2365  new
2366  setline(1, 'asdf')
2367  feedkeys("\<F3>$", 'x')
2368  assert_equal('ASDF', getline(1))
2369
2370  bwipe!
2371  nunmap <F3>
2372enddef
2373
2374" this was crashing on exit
2375def Test_nested_lambda_in_closure()
2376  var lines =<< trim END
2377      vim9script
2378      def Outer()
2379          def g:Inner()
2380              echo map([1, 2, 3], {_, v -> v + 1})
2381          enddef
2382          g:Inner()
2383      enddef
2384      defcompile
2385      writefile(['Done'], 'XnestedDone')
2386      quit
2387  END
2388  if !RunVim([], lines, '--clean')
2389    return
2390  endif
2391  assert_equal(['Done'], readfile('XnestedDone'))
2392  delete('XnestedDone')
2393enddef
2394
2395def Test_check_func_arg_types()
2396  var lines =<< trim END
2397      vim9script
2398      def F1(x: string): string
2399        return x
2400      enddef
2401
2402      def F2(x: number): number
2403        return x + 1
2404      enddef
2405
2406      def G(g: func): dict<func>
2407        return {f: g}
2408      enddef
2409
2410      def H(d: dict<func>): string
2411        return d.f('a')
2412      enddef
2413  END
2414
2415  CheckScriptSuccess(lines + ['echo H(G(F1))'])
2416  CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
2417enddef
2418
2419
2420
2421" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
2422