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