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