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