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