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