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 Test_nested_inline_lambda()
2106  # TODO: use the "text" argument
2107  var lines =<< trim END
2108      vim9script
2109      def F(text: string): func(string): func(string): string
2110        return (arg: string): func(string): string => ((sep: string): string => {
2111            return sep .. arg
2112          })
2113      enddef
2114      assert_equal('--there', F('unused')('there')('--'))
2115  END
2116  CheckScriptSuccess(lines)
2117enddef
2118
2119def Shadowed(): list<number>
2120  var FuncList: list<func: number> = [() => 42]
2121  return FuncList->mapnew((_, Shadowed) => Shadowed())
2122enddef
2123
2124def Test_lambda_arg_shadows_func()
2125  assert_equal([42], Shadowed())
2126enddef
2127
2128def Line_continuation_in_def(dir: string = ''): string
2129  var path: string = empty(dir)
2130          \ ? 'empty'
2131          \ : 'full'
2132  return path
2133enddef
2134
2135def Test_line_continuation_in_def()
2136  Line_continuation_in_def('.')->assert_equal('full')
2137enddef
2138
2139def Test_script_var_in_lambda()
2140  var lines =<< trim END
2141      vim9script
2142      var script = 'test'
2143      assert_equal(['test'], map(['one'], (_, _) => script))
2144  END
2145  CheckScriptSuccess(lines)
2146enddef
2147
2148def Line_continuation_in_lambda(): list<string>
2149  var x = range(97, 100)
2150      ->mapnew((_, v) => nr2char(v)
2151          ->toupper())
2152      ->reverse()
2153  return x
2154enddef
2155
2156def Test_line_continuation_in_lambda()
2157  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
2158
2159  var lines =<< trim END
2160      vim9script
2161      var res = [{n: 1, m: 2, s: 'xxx'}]
2162                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
2163                    v.n,
2164                    v.m,
2165                    substitute(v.s, '.*', 'yyy', '')
2166                    ))
2167      assert_equal(['1:2:yyy'], res)
2168  END
2169  CheckScriptSuccess(lines)
2170enddef
2171
2172def Test_list_lambda()
2173  timer_start(1000, (_) => 0)
2174  var body = execute(timer_info()[0].callback
2175         ->string()
2176         ->substitute("('", ' ', '')
2177         ->substitute("')", '', '')
2178         ->substitute('function\zs', ' ', ''))
2179  assert_match('def <lambda>\d\+(_: any): number\n1  return 0\n   enddef', body)
2180enddef
2181
2182def Test_legacy_lambda()
2183  legacy echo {x -> 'hello ' .. x}('foo')
2184
2185  var lines =<< trim END
2186      echo {x -> 'hello ' .. x}('foo')
2187  END
2188  CheckDefAndScriptFailure(lines, 'E720:')
2189
2190  lines =<< trim END
2191      vim9script
2192      def Func()
2193        echo (() => 'no error')()
2194      enddef
2195      legacy call s:Func()
2196  END
2197  CheckScriptSuccess(lines)
2198enddef
2199
2200def DoFilterThis(a: string): list<string>
2201  # closure nested inside another closure using argument
2202  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
2203  return ['x', 'y', 'a', 'x2', 'c']->Filter()
2204enddef
2205
2206def Test_nested_closure_using_argument()
2207  assert_equal(['x', 'x2'], DoFilterThis('x'))
2208enddef
2209
2210def Test_triple_nested_closure()
2211  var what = 'x'
2212  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
2213  var Filter = (l) => filter(l, (_, v) => Match(v, what))
2214  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
2215enddef
2216
2217func Test_silent_echo()
2218  CheckScreendump
2219
2220  let lines =<< trim END
2221    vim9script
2222    def EchoNothing()
2223      silent echo ''
2224    enddef
2225    defcompile
2226  END
2227  call writefile(lines, 'XTest_silent_echo')
2228
2229  " Check that the balloon shows up after a mouse move
2230  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
2231  call term_sendkeys(buf, ":abc")
2232  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
2233
2234  " clean up
2235  call StopVimInTerminal(buf)
2236  call delete('XTest_silent_echo')
2237endfunc
2238
2239def SilentlyError()
2240  execute('silent! invalid')
2241  g:did_it = 'yes'
2242enddef
2243
2244func UserError()
2245  silent! invalid
2246endfunc
2247
2248def SilentlyUserError()
2249  UserError()
2250  g:did_it = 'yes'
2251enddef
2252
2253" This can't be a :def function, because the assert would not be reached.
2254func Test_ignore_silent_error()
2255  let g:did_it = 'no'
2256  call SilentlyError()
2257  call assert_equal('yes', g:did_it)
2258
2259  let g:did_it = 'no'
2260  call SilentlyUserError()
2261  call assert_equal('yes', g:did_it)
2262
2263  unlet g:did_it
2264endfunc
2265
2266def Test_ignore_silent_error_in_filter()
2267  var lines =<< trim END
2268      vim9script
2269      def Filter(winid: number, key: string): bool
2270          if key == 'o'
2271              silent! eval [][0]
2272              return true
2273          endif
2274          return popup_filter_menu(winid, key)
2275      enddef
2276
2277      popup_create('popup', {filter: Filter})
2278      feedkeys("o\r", 'xnt')
2279  END
2280  CheckScriptSuccess(lines)
2281enddef
2282
2283def Fibonacci(n: number): number
2284  if n < 2
2285    return n
2286  else
2287    return Fibonacci(n - 1) + Fibonacci(n - 2)
2288  endif
2289enddef
2290
2291def Test_recursive_call()
2292  Fibonacci(20)->assert_equal(6765)
2293enddef
2294
2295def TreeWalk(dir: string): list<any>
2296  return readdir(dir)->mapnew((_, val) =>
2297            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2298               ? {[val]: TreeWalk(dir .. '/' .. val)}
2299               : val
2300             )
2301enddef
2302
2303def Test_closure_in_map()
2304  mkdir('XclosureDir/tdir', 'p')
2305  writefile(['111'], 'XclosureDir/file1')
2306  writefile(['222'], 'XclosureDir/file2')
2307  writefile(['333'], 'XclosureDir/tdir/file3')
2308
2309  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2310
2311  delete('XclosureDir', 'rf')
2312enddef
2313
2314def Test_invalid_function_name()
2315  var lines =<< trim END
2316      vim9script
2317      def s: list<string>
2318  END
2319  CheckScriptFailure(lines, 'E129:')
2320
2321  lines =<< trim END
2322      vim9script
2323      def g: list<string>
2324  END
2325  CheckScriptFailure(lines, 'E129:')
2326
2327  lines =<< trim END
2328      vim9script
2329      def <SID>: list<string>
2330  END
2331  CheckScriptFailure(lines, 'E884:')
2332
2333  lines =<< trim END
2334      vim9script
2335      def F list<string>
2336  END
2337  CheckScriptFailure(lines, 'E488:')
2338enddef
2339
2340def Test_partial_call()
2341  var Xsetlist = function('setloclist', [0])
2342  Xsetlist([], ' ', {title: 'test'})
2343  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2344
2345  Xsetlist = function('setloclist', [0, [], ' '])
2346  Xsetlist({title: 'test'})
2347  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2348
2349  Xsetlist = function('setqflist')
2350  Xsetlist([], ' ', {title: 'test'})
2351  getqflist({title: 1})->assert_equal({title: 'test'})
2352
2353  Xsetlist = function('setqflist', [[], ' '])
2354  Xsetlist({title: 'test'})
2355  getqflist({title: 1})->assert_equal({title: 'test'})
2356
2357  var Len: func: number = function('len', ['word'])
2358  assert_equal(4, Len())
2359enddef
2360
2361def Test_cmd_modifier()
2362  tab echo '0'
2363  CheckDefFailure(['5tab echo 3'], 'E16:')
2364enddef
2365
2366def Test_restore_modifiers()
2367  # check that when compiling a :def function command modifiers are not messed
2368  # up.
2369  var lines =<< trim END
2370      vim9script
2371      set eventignore=
2372      autocmd QuickFixCmdPost * copen
2373      def AutocmdsDisabled()
2374        eval 0
2375      enddef
2376      func Func()
2377        noautocmd call s:AutocmdsDisabled()
2378        let g:ei_after = &eventignore
2379      endfunc
2380      Func()
2381  END
2382  CheckScriptSuccess(lines)
2383  g:ei_after->assert_equal('')
2384enddef
2385
2386def StackTop()
2387  eval 1
2388  eval 2
2389  # call not on fourth line
2390  StackBot()
2391enddef
2392
2393def StackBot()
2394  # throw an error
2395  eval [][0]
2396enddef
2397
2398def Test_callstack_def()
2399  try
2400    StackTop()
2401  catch
2402    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2403  endtry
2404enddef
2405
2406" Re-using spot for variable used in block
2407def Test_block_scoped_var()
2408  var lines =<< trim END
2409      vim9script
2410      def Func()
2411        var x = ['a', 'b', 'c']
2412        if 1
2413          var y = 'x'
2414          map(x, (_, _) => y)
2415        endif
2416        var z = x
2417        assert_equal(['x', 'x', 'x'], z)
2418      enddef
2419      Func()
2420  END
2421  CheckScriptSuccess(lines)
2422enddef
2423
2424def Test_reset_did_emsg()
2425  var lines =<< trim END
2426      @s = 'blah'
2427      au BufWinLeave * #
2428      def Func()
2429        var winid = popup_create('popup', {})
2430        exe '*s'
2431        popup_close(winid)
2432      enddef
2433      Func()
2434  END
2435  CheckScriptFailure(lines, 'E492:', 8)
2436  delfunc! g:Func
2437enddef
2438
2439def Test_did_emsg_reset()
2440  # executing an autocommand resets did_emsg, this should not result in a
2441  # builtin function considered failing
2442  var lines =<< trim END
2443      vim9script
2444      au BufWinLeave * #
2445      def Func()
2446          popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()})
2447          eval [][0]
2448      enddef
2449      nno <F3> <cmd>call <sid>Func()<cr>
2450      feedkeys("\<F3>\e", 'xt')
2451  END
2452  writefile(lines, 'XemsgReset')
2453  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2454  delete('XemsgReset')
2455  nunmap <F3>
2456  au! BufWinLeave
2457enddef
2458
2459def Test_abort_with_silent_call()
2460  var lines =<< trim END
2461      vim9script
2462      g:result = 'none'
2463      def Func()
2464        g:result += 3
2465        g:result = 'yes'
2466      enddef
2467      # error is silenced, but function aborts on error
2468      silent! Func()
2469      assert_equal('none', g:result)
2470      unlet g:result
2471  END
2472  CheckScriptSuccess(lines)
2473enddef
2474
2475def Test_continues_with_silent_error()
2476  var lines =<< trim END
2477      vim9script
2478      g:result = 'none'
2479      def Func()
2480        silent!  g:result += 3
2481        g:result = 'yes'
2482      enddef
2483      # error is silenced, function does not abort
2484      Func()
2485      assert_equal('yes', g:result)
2486      unlet g:result
2487  END
2488  CheckScriptSuccess(lines)
2489enddef
2490
2491def Test_abort_even_with_silent()
2492  var lines =<< trim END
2493      vim9script
2494      g:result = 'none'
2495      def Func()
2496        eval {-> ''}() .. '' .. {}['X']
2497        g:result = 'yes'
2498      enddef
2499      silent! Func()
2500      assert_equal('none', g:result)
2501      unlet g:result
2502  END
2503  CheckScriptSuccess(lines)
2504enddef
2505
2506def Test_cmdmod_silent_restored()
2507  var lines =<< trim END
2508      vim9script
2509      def Func()
2510        g:result = 'none'
2511        silent! g:result += 3
2512        g:result = 'none'
2513        g:result += 3
2514      enddef
2515      Func()
2516  END
2517  # can't use CheckScriptFailure, it ignores the :silent!
2518  var fname = 'Xdefsilent'
2519  writefile(lines, fname)
2520  var caught = 'no'
2521  try
2522    exe 'source ' .. fname
2523  catch /E1030:/
2524    caught = 'yes'
2525    assert_match('Func, line 4', v:throwpoint)
2526  endtry
2527  assert_equal('yes', caught)
2528  delete(fname)
2529enddef
2530
2531def Test_cmdmod_silent_nested()
2532  var lines =<< trim END
2533      vim9script
2534      var result = ''
2535
2536      def Error()
2537          result ..= 'Eb'
2538          eval [][0]
2539          result ..= 'Ea'
2540      enddef
2541
2542      def Crash()
2543          result ..= 'Cb'
2544          sil! Error()
2545          result ..= 'Ca'
2546      enddef
2547
2548      Crash()
2549      assert_equal('CbEbEaCa', result)
2550  END
2551  CheckScriptSuccess(lines)
2552enddef
2553
2554def Test_dict_member_with_silent()
2555  var lines =<< trim END
2556      vim9script
2557      g:result = 'none'
2558      var d: dict<any>
2559      def Func()
2560        try
2561          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2562        catch
2563        endtry
2564      enddef
2565      silent! Func()
2566      assert_equal('0', g:result)
2567      unlet g:result
2568  END
2569  CheckScriptSuccess(lines)
2570enddef
2571
2572def Test_skip_cmds_with_silent()
2573  var lines =<< trim END
2574      vim9script
2575
2576      def Func(b: bool)
2577        Crash()
2578      enddef
2579
2580      def Crash()
2581        sil! :/not found/d _
2582        sil! :/not found/put _
2583      enddef
2584
2585      Func(true)
2586  END
2587  CheckScriptSuccess(lines)
2588enddef
2589
2590def Test_opfunc()
2591  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2592  def g:Opfunc(_: any): string
2593    setline(1, 'ASDF')
2594    return ''
2595  enddef
2596  new
2597  setline(1, 'asdf')
2598  feedkeys("\<F3>$", 'x')
2599  assert_equal('ASDF', getline(1))
2600
2601  bwipe!
2602  nunmap <F3>
2603enddef
2604
2605" this was crashing on exit
2606def Test_nested_lambda_in_closure()
2607  var lines =<< trim END
2608      vim9script
2609      command WriteDone writefile(['Done'], 'XnestedDone')
2610      def Outer()
2611          def g:Inner()
2612              echo map([1, 2, 3], {_, v -> v + 1})
2613          enddef
2614          g:Inner()
2615      enddef
2616      defcompile
2617      # not reached
2618  END
2619  if !RunVim([], lines, '--clean -c WriteDone -c quit')
2620    return
2621  endif
2622  assert_equal(['Done'], readfile('XnestedDone'))
2623  delete('XnestedDone')
2624enddef
2625
2626def Test_check_func_arg_types()
2627  var lines =<< trim END
2628      vim9script
2629      def F1(x: string): string
2630        return x
2631      enddef
2632
2633      def F2(x: number): number
2634        return x + 1
2635      enddef
2636
2637      def G(g: func): dict<func>
2638        return {f: g}
2639      enddef
2640
2641      def H(d: dict<func>): string
2642        return d.f('a')
2643      enddef
2644  END
2645
2646  CheckScriptSuccess(lines + ['echo H(G(F1))'])
2647  CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
2648enddef
2649
2650def Test_compile_error()
2651  var lines =<< trim END
2652    def g:Broken()
2653      echo 'a' + {}
2654    enddef
2655    call g:Broken()
2656  END
2657  # First call: compilation error
2658  CheckScriptFailure(lines, 'E1051: Wrong argument type for +')
2659
2660  # Second call won't try compiling again
2661  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2662  delfunc g:Broken
2663
2664  # No error when compiling with :silent!
2665  lines =<< trim END
2666    def g:Broken()
2667      echo 'a' + []
2668    enddef
2669    silent! defcompile
2670  END
2671  CheckScriptSuccess(lines)
2672
2673  # Calling the function won't try compiling again
2674  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2675  delfunc g:Broken
2676enddef
2677
2678def Test_ignored_argument()
2679  var lines =<< trim END
2680      vim9script
2681      def Ignore(_, _): string
2682        return 'yes'
2683      enddef
2684      assert_equal('yes', Ignore(1, 2))
2685
2686      func Ok(_)
2687        return a:_
2688      endfunc
2689      assert_equal('ok', Ok('ok'))
2690
2691      func Oktoo()
2692        let _ = 'too'
2693        return _
2694      endfunc
2695      assert_equal('too', Oktoo())
2696
2697      assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1)))
2698  END
2699  CheckScriptSuccess(lines)
2700
2701  lines =<< trim END
2702      def Ignore(_: string): string
2703        return _
2704      enddef
2705      defcompile
2706  END
2707  CheckScriptFailure(lines, 'E1181:', 1)
2708
2709  lines =<< trim END
2710      var _ = 1
2711  END
2712  CheckDefAndScriptFailure(lines, 'E1181:', 1)
2713enddef
2714
2715def Test_too_many_arguments()
2716  var lines =<< trim END
2717    echo [0, 1, 2]->map(() => 123)
2718  END
2719  CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1)
2720
2721  lines =<< trim END
2722    echo [0, 1, 2]->map((_) => 123)
2723  END
2724  CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1)
2725enddef
2726
2727def Test_closing_brace_at_start_of_line()
2728  var lines =<< trim END
2729      def Func()
2730      enddef
2731      Func(
2732      )
2733  END
2734  call CheckDefAndScriptSuccess(lines)
2735enddef
2736
2737
2738" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
2739