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