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