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