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