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)
2258
2259  lines =<< trim END
2260      vim9script
2261      echo range(4)->mapnew((_, v) => {
2262        return range(v) ->mapnew((_, s) => {
2263          return string(s)
2264          })
2265        })
2266  END
2267  CheckScriptSuccess(lines)
2268
2269  lines =<< trim END
2270      vim9script
2271
2272      def s:func()
2273        range(10)
2274          ->mapnew((_, _) => ({
2275            key: range(10)->mapnew((_, _) => {
2276              return ' '
2277            }),
2278          }))
2279      enddef
2280
2281      defcomp
2282  END
2283  CheckScriptSuccess(lines)
2284enddef
2285
2286def Shadowed(): list<number>
2287  var FuncList: list<func: number> = [() => 42]
2288  return FuncList->mapnew((_, Shadowed) => Shadowed())
2289enddef
2290
2291def Test_lambda_arg_shadows_func()
2292  assert_equal([42], Shadowed())
2293enddef
2294
2295def Line_continuation_in_def(dir: string = ''): string
2296  var path: string = empty(dir)
2297          \ ? 'empty'
2298          \ : 'full'
2299  return path
2300enddef
2301
2302def Test_line_continuation_in_def()
2303  Line_continuation_in_def('.')->assert_equal('full')
2304enddef
2305
2306def Test_script_var_in_lambda()
2307  var lines =<< trim END
2308      vim9script
2309      var script = 'test'
2310      assert_equal(['test'], map(['one'], (_, _) => script))
2311  END
2312  CheckScriptSuccess(lines)
2313enddef
2314
2315def Line_continuation_in_lambda(): list<string>
2316  var x = range(97, 100)
2317      ->mapnew((_, v) => nr2char(v)
2318          ->toupper())
2319      ->reverse()
2320  return x
2321enddef
2322
2323def Test_line_continuation_in_lambda()
2324  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
2325
2326  var lines =<< trim END
2327      vim9script
2328      var res = [{n: 1, m: 2, s: 'xxx'}]
2329                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
2330                    v.n,
2331                    v.m,
2332                    substitute(v.s, '.*', 'yyy', '')
2333                    ))
2334      assert_equal(['1:2:yyy'], res)
2335  END
2336  CheckScriptSuccess(lines)
2337enddef
2338
2339def Test_list_lambda()
2340  timer_start(1000, (_) => 0)
2341  var body = execute(timer_info()[0].callback
2342         ->string()
2343         ->substitute("('", ' ', '')
2344         ->substitute("')", '', '')
2345         ->substitute('function\zs', ' ', ''))
2346  assert_match('def <lambda>\d\+(_: any): number\n1  return 0\n   enddef', body)
2347enddef
2348
2349def Test_legacy_lambda()
2350  legacy echo {x -> 'hello ' .. x}('foo')
2351
2352  var lines =<< trim END
2353      echo {x -> 'hello ' .. x}('foo')
2354  END
2355  CheckDefAndScriptFailure(lines, 'E720:')
2356
2357  lines =<< trim END
2358      vim9script
2359      def Func()
2360        echo (() => 'no error')()
2361      enddef
2362      legacy call s:Func()
2363  END
2364  CheckScriptSuccess(lines)
2365enddef
2366
2367def Test_legacy()
2368  var lines =<< trim END
2369      vim9script
2370      func g:LegacyFunction()
2371        let g:legacyvar = 1
2372      endfunc
2373      def Testit()
2374        legacy call g:LegacyFunction()
2375      enddef
2376      Testit()
2377      assert_equal(1, g:legacyvar)
2378      unlet g:legacyvar
2379      delfunc g:LegacyFunction
2380  END
2381  CheckScriptSuccess(lines)
2382enddef
2383
2384def Test_legacy_errors()
2385  for cmd in ['if', 'elseif', 'else', 'endif',
2386              'for', 'endfor', 'continue', 'break',
2387              'while', 'endwhile',
2388              'try', 'catch', 'finally', 'endtry']
2389    CheckDefFailure(['legacy ' .. cmd .. ' expr'], 'E1189:')
2390  endfor
2391enddef
2392
2393def DoFilterThis(a: string): list<string>
2394  # closure nested inside another closure using argument
2395  var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
2396  return ['x', 'y', 'a', 'x2', 'c']->Filter()
2397enddef
2398
2399def Test_nested_closure_using_argument()
2400  assert_equal(['x', 'x2'], DoFilterThis('x'))
2401enddef
2402
2403def Test_triple_nested_closure()
2404  var what = 'x'
2405  var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0
2406  var Filter = (l) => filter(l, (_, v) => Match(v, what))
2407  assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter())
2408enddef
2409
2410func Test_silent_echo()
2411  CheckScreendump
2412
2413  let lines =<< trim END
2414    vim9script
2415    def EchoNothing()
2416      silent echo ''
2417    enddef
2418    defcompile
2419  END
2420  call writefile(lines, 'XTest_silent_echo')
2421
2422  " Check that the balloon shows up after a mouse move
2423  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
2424  call term_sendkeys(buf, ":abc")
2425  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
2426
2427  " clean up
2428  call StopVimInTerminal(buf)
2429  call delete('XTest_silent_echo')
2430endfunc
2431
2432def SilentlyError()
2433  execute('silent! invalid')
2434  g:did_it = 'yes'
2435enddef
2436
2437func UserError()
2438  silent! invalid
2439endfunc
2440
2441def SilentlyUserError()
2442  UserError()
2443  g:did_it = 'yes'
2444enddef
2445
2446" This can't be a :def function, because the assert would not be reached.
2447func Test_ignore_silent_error()
2448  let g:did_it = 'no'
2449  call SilentlyError()
2450  call assert_equal('yes', g:did_it)
2451
2452  let g:did_it = 'no'
2453  call SilentlyUserError()
2454  call assert_equal('yes', g:did_it)
2455
2456  unlet g:did_it
2457endfunc
2458
2459def Test_ignore_silent_error_in_filter()
2460  var lines =<< trim END
2461      vim9script
2462      def Filter(winid: number, key: string): bool
2463          if key == 'o'
2464              silent! eval [][0]
2465              return true
2466          endif
2467          return popup_filter_menu(winid, key)
2468      enddef
2469
2470      popup_create('popup', {filter: Filter})
2471      feedkeys("o\r", 'xnt')
2472  END
2473  CheckScriptSuccess(lines)
2474enddef
2475
2476def Fibonacci(n: number): number
2477  if n < 2
2478    return n
2479  else
2480    return Fibonacci(n - 1) + Fibonacci(n - 2)
2481  endif
2482enddef
2483
2484def Test_recursive_call()
2485  Fibonacci(20)->assert_equal(6765)
2486enddef
2487
2488def TreeWalk(dir: string): list<any>
2489  return readdir(dir)->mapnew((_, val) =>
2490            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
2491               ? {[val]: TreeWalk(dir .. '/' .. val)}
2492               : val
2493             )
2494enddef
2495
2496def Test_closure_in_map()
2497  mkdir('XclosureDir/tdir', 'p')
2498  writefile(['111'], 'XclosureDir/file1')
2499  writefile(['222'], 'XclosureDir/file2')
2500  writefile(['333'], 'XclosureDir/tdir/file3')
2501
2502  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
2503
2504  delete('XclosureDir', 'rf')
2505enddef
2506
2507def Test_invalid_function_name()
2508  var lines =<< trim END
2509      vim9script
2510      def s: list<string>
2511  END
2512  CheckScriptFailure(lines, 'E129:')
2513
2514  lines =<< trim END
2515      vim9script
2516      def g: list<string>
2517  END
2518  CheckScriptFailure(lines, 'E129:')
2519
2520  lines =<< trim END
2521      vim9script
2522      def <SID>: list<string>
2523  END
2524  CheckScriptFailure(lines, 'E884:')
2525
2526  lines =<< trim END
2527      vim9script
2528      def F list<string>
2529  END
2530  CheckScriptFailure(lines, 'E488:')
2531enddef
2532
2533def Test_partial_call()
2534  var Xsetlist = function('setloclist', [0])
2535  Xsetlist([], ' ', {title: 'test'})
2536  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2537
2538  Xsetlist = function('setloclist', [0, [], ' '])
2539  Xsetlist({title: 'test'})
2540  getloclist(0, {title: 1})->assert_equal({title: 'test'})
2541
2542  Xsetlist = function('setqflist')
2543  Xsetlist([], ' ', {title: 'test'})
2544  getqflist({title: 1})->assert_equal({title: 'test'})
2545
2546  Xsetlist = function('setqflist', [[], ' '])
2547  Xsetlist({title: 'test'})
2548  getqflist({title: 1})->assert_equal({title: 'test'})
2549
2550  var Len: func: number = function('len', ['word'])
2551  assert_equal(4, Len())
2552enddef
2553
2554def Test_cmd_modifier()
2555  tab echo '0'
2556  CheckDefFailure(['5tab echo 3'], 'E16:')
2557enddef
2558
2559def Test_restore_modifiers()
2560  # check that when compiling a :def function command modifiers are not messed
2561  # up.
2562  var lines =<< trim END
2563      vim9script
2564      set eventignore=
2565      autocmd QuickFixCmdPost * copen
2566      def AutocmdsDisabled()
2567        eval 1 + 2
2568      enddef
2569      func Func()
2570        noautocmd call s:AutocmdsDisabled()
2571        let g:ei_after = &eventignore
2572      endfunc
2573      Func()
2574  END
2575  CheckScriptSuccess(lines)
2576  g:ei_after->assert_equal('')
2577enddef
2578
2579def StackTop()
2580  eval 1 + 2
2581  eval 2 + 3
2582  # call not on fourth line
2583  StackBot()
2584enddef
2585
2586def StackBot()
2587  # throw an error
2588  eval [][0]
2589enddef
2590
2591def Test_callstack_def()
2592  try
2593    StackTop()
2594  catch
2595    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2596  endtry
2597enddef
2598
2599" Re-using spot for variable used in block
2600def Test_block_scoped_var()
2601  var lines =<< trim END
2602      vim9script
2603      def Func()
2604        var x = ['a', 'b', 'c']
2605        if 1
2606          var y = 'x'
2607          map(x, (_, _) => y)
2608        endif
2609        var z = x
2610        assert_equal(['x', 'x', 'x'], z)
2611      enddef
2612      Func()
2613  END
2614  CheckScriptSuccess(lines)
2615enddef
2616
2617def Test_reset_did_emsg()
2618  var lines =<< trim END
2619      @s = 'blah'
2620      au BufWinLeave * #
2621      def Func()
2622        var winid = popup_create('popup', {})
2623        exe '*s'
2624        popup_close(winid)
2625      enddef
2626      Func()
2627  END
2628  CheckScriptFailure(lines, 'E492:', 8)
2629  delfunc! g:Func
2630enddef
2631
2632def Test_did_emsg_reset()
2633  # executing an autocommand resets did_emsg, this should not result in a
2634  # builtin function considered failing
2635  var lines =<< trim END
2636      vim9script
2637      au BufWinLeave * #
2638      def Func()
2639          popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()})
2640          eval [][0]
2641      enddef
2642      nno <F3> <cmd>call <sid>Func()<cr>
2643      feedkeys("\<F3>\e", 'xt')
2644  END
2645  writefile(lines, 'XemsgReset')
2646  assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
2647  delete('XemsgReset')
2648  nunmap <F3>
2649  au! BufWinLeave
2650enddef
2651
2652def Test_abort_with_silent_call()
2653  var lines =<< trim END
2654      vim9script
2655      g:result = 'none'
2656      def Func()
2657        g:result += 3
2658        g:result = 'yes'
2659      enddef
2660      # error is silenced, but function aborts on error
2661      silent! Func()
2662      assert_equal('none', g:result)
2663      unlet g:result
2664  END
2665  CheckScriptSuccess(lines)
2666enddef
2667
2668def Test_continues_with_silent_error()
2669  var lines =<< trim END
2670      vim9script
2671      g:result = 'none'
2672      def Func()
2673        silent!  g:result += 3
2674        g:result = 'yes'
2675      enddef
2676      # error is silenced, function does not abort
2677      Func()
2678      assert_equal('yes', g:result)
2679      unlet g:result
2680  END
2681  CheckScriptSuccess(lines)
2682enddef
2683
2684def Test_abort_even_with_silent()
2685  var lines =<< trim END
2686      vim9script
2687      g:result = 'none'
2688      def Func()
2689        eval {-> ''}() .. '' .. {}['X']
2690        g:result = 'yes'
2691      enddef
2692      silent! Func()
2693      assert_equal('none', g:result)
2694      unlet g:result
2695  END
2696  CheckScriptSuccess(lines)
2697enddef
2698
2699def Test_cmdmod_silent_restored()
2700  var lines =<< trim END
2701      vim9script
2702      def Func()
2703        g:result = 'none'
2704        silent! g:result += 3
2705        g:result = 'none'
2706        g:result += 3
2707      enddef
2708      Func()
2709  END
2710  # can't use CheckScriptFailure, it ignores the :silent!
2711  var fname = 'Xdefsilent'
2712  writefile(lines, fname)
2713  var caught = 'no'
2714  try
2715    exe 'source ' .. fname
2716  catch /E1030:/
2717    caught = 'yes'
2718    assert_match('Func, line 4', v:throwpoint)
2719  endtry
2720  assert_equal('yes', caught)
2721  delete(fname)
2722enddef
2723
2724def Test_cmdmod_silent_nested()
2725  var lines =<< trim END
2726      vim9script
2727      var result = ''
2728
2729      def Error()
2730          result ..= 'Eb'
2731          eval [][0]
2732          result ..= 'Ea'
2733      enddef
2734
2735      def Crash()
2736          result ..= 'Cb'
2737          sil! Error()
2738          result ..= 'Ca'
2739      enddef
2740
2741      Crash()
2742      assert_equal('CbEbEaCa', result)
2743  END
2744  CheckScriptSuccess(lines)
2745enddef
2746
2747def Test_dict_member_with_silent()
2748  var lines =<< trim END
2749      vim9script
2750      g:result = 'none'
2751      var d: dict<any>
2752      def Func()
2753        try
2754          g:result = map([], (_, v) => ({}[v]))->join() .. d['']
2755        catch
2756        endtry
2757      enddef
2758      silent! Func()
2759      assert_equal('0', g:result)
2760      unlet g:result
2761  END
2762  CheckScriptSuccess(lines)
2763enddef
2764
2765def Test_skip_cmds_with_silent()
2766  var lines =<< trim END
2767      vim9script
2768
2769      def Func(b: bool)
2770        Crash()
2771      enddef
2772
2773      def Crash()
2774        sil! :/not found/d _
2775        sil! :/not found/put _
2776      enddef
2777
2778      Func(true)
2779  END
2780  CheckScriptSuccess(lines)
2781enddef
2782
2783def Test_opfunc()
2784  nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
2785  def g:Opfunc(_: any): string
2786    setline(1, 'ASDF')
2787    return ''
2788  enddef
2789  new
2790  setline(1, 'asdf')
2791  feedkeys("\<F3>$", 'x')
2792  assert_equal('ASDF', getline(1))
2793
2794  bwipe!
2795  nunmap <F3>
2796enddef
2797
2798" this was crashing on exit
2799def Test_nested_lambda_in_closure()
2800  var lines =<< trim END
2801      vim9script
2802      command WriteDone writefile(['Done'], 'XnestedDone')
2803      def Outer()
2804          def g:Inner()
2805              echo map([1, 2, 3], {_, v -> v + 1})
2806          enddef
2807          g:Inner()
2808      enddef
2809      defcompile
2810      # not reached
2811  END
2812  if !RunVim([], lines, '--clean -c WriteDone -c quit')
2813    return
2814  endif
2815  assert_equal(['Done'], readfile('XnestedDone'))
2816  delete('XnestedDone')
2817enddef
2818
2819def Test_check_func_arg_types()
2820  var lines =<< trim END
2821      vim9script
2822      def F1(x: string): string
2823        return x
2824      enddef
2825
2826      def F2(x: number): number
2827        return x + 1
2828      enddef
2829
2830      def G(g: func): dict<func>
2831        return {f: g}
2832      enddef
2833
2834      def H(d: dict<func>): string
2835        return d.f('a')
2836      enddef
2837  END
2838
2839  CheckScriptSuccess(lines + ['echo H(G(F1))'])
2840  CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
2841enddef
2842
2843def Test_compile_error()
2844  var lines =<< trim END
2845    def g:Broken()
2846      echo 'a' + {}
2847    enddef
2848    call g:Broken()
2849  END
2850  # First call: compilation error
2851  CheckScriptFailure(lines, 'E1051: Wrong argument type for +')
2852
2853  # Second call won't try compiling again
2854  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2855  delfunc g:Broken
2856
2857  # No error when compiling with :silent!
2858  lines =<< trim END
2859    def g:Broken()
2860      echo 'a' + []
2861    enddef
2862    silent! defcompile
2863  END
2864  CheckScriptSuccess(lines)
2865
2866  # Calling the function won't try compiling again
2867  assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken')
2868  delfunc g:Broken
2869enddef
2870
2871def Test_ignored_argument()
2872  var lines =<< trim END
2873      vim9script
2874      def Ignore(_, _): string
2875        return 'yes'
2876      enddef
2877      assert_equal('yes', Ignore(1, 2))
2878
2879      func Ok(_)
2880        return a:_
2881      endfunc
2882      assert_equal('ok', Ok('ok'))
2883
2884      func Oktoo()
2885        let _ = 'too'
2886        return _
2887      endfunc
2888      assert_equal('too', Oktoo())
2889
2890      assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1)))
2891  END
2892  CheckScriptSuccess(lines)
2893
2894  lines =<< trim END
2895      def Ignore(_: string): string
2896        return _
2897      enddef
2898      defcompile
2899  END
2900  CheckScriptFailure(lines, 'E1181:', 1)
2901
2902  lines =<< trim END
2903      var _ = 1
2904  END
2905  CheckDefAndScriptFailure(lines, 'E1181:', 1)
2906
2907  lines =<< trim END
2908      var x = _
2909  END
2910  CheckDefAndScriptFailure(lines, 'E1181:', 1)
2911enddef
2912
2913def Test_too_many_arguments()
2914  var lines =<< trim END
2915    echo [0, 1, 2]->map(() => 123)
2916  END
2917  CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1)
2918
2919  lines =<< trim END
2920    echo [0, 1, 2]->map((_) => 123)
2921  END
2922  CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1)
2923enddef
2924
2925def Test_closing_brace_at_start_of_line()
2926  var lines =<< trim END
2927      def Func()
2928      enddef
2929      Func(
2930      )
2931  END
2932  call CheckDefAndScriptSuccess(lines)
2933enddef
2934
2935if has('python3')
2936  def Test_python3_heredoc()
2937    py3 << trim EOF
2938      import vim
2939      vim.vars['didit'] = 'yes'
2940    EOF
2941    assert_equal('yes', g:didit)
2942
2943    python3 << trim EOF
2944      import vim
2945      vim.vars['didit'] = 'again'
2946    EOF
2947    assert_equal('again', g:didit)
2948  enddef
2949endif
2950
2951" This messes up syntax highlight, keep near the end.
2952if has('lua')
2953  def Test_lua_heredoc()
2954    g:d = {}
2955    lua << trim EOF
2956        x = vim.eval('g:d')
2957        x['key'] = 'val'
2958    EOF
2959    assert_equal('val', g:d.key)
2960  enddef
2961endif
2962
2963
2964" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
2965