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