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