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