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