Mercurial > vim
comparison src/testdir/test_normal.vim @ 26518:13ba00ef7687 v8.2.3788
patch 8.2.3788: lambda for option that is a function may be freed
Commit: https://github.com/vim/vim/commit/6ae8fae8696623b527c7fb22567f6a3705b2f0dd
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sun Dec 12 16:26:44 2021 +0000
patch 8.2.3788: lambda for option that is a function may be freed
Problem: Lambda for option that is a function may be garbage collected.
Solution: Set a reference in the funcref. (Yegappan Lakshmanan,
closes #9330)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 12 Dec 2021 17:30:04 +0100 |
parents | 7eaf61a67d18 |
children | 33d680d372aa |
comparison
equal
deleted
inserted
replaced
26517:7dfc4c45f698 | 26518:13ba00ef7687 |
---|---|
446 new | 446 new |
447 func MyopFunc(val, type) | 447 func MyopFunc(val, type) |
448 let g:OpFuncArgs = [a:val, a:type] | 448 let g:OpFuncArgs = [a:val, a:type] |
449 endfunc | 449 endfunc |
450 | 450 |
451 " Test for using a function() | 451 let lines =<< trim END |
452 set opfunc=function('MyopFunc',\ [11]) | 452 #" Test for using a function() |
453 let g:OpFuncArgs = [] | 453 set opfunc=function('g:MyopFunc',\ [10]) |
454 normal! g@l | 454 LET g:OpFuncArgs = [] |
455 call assert_equal([11, 'char'], g:OpFuncArgs) | 455 normal! g@l |
456 | 456 call assert_equal([10, 'char'], g:OpFuncArgs) |
457 " Using a funcref variable to set 'operatorfunc' | 457 |
458 let Fn = function('MyopFunc', [12]) | 458 #" Using a funcref variable to set 'operatorfunc' |
459 let &opfunc = Fn | 459 VAR Fn = function('g:MyopFunc', [11]) |
460 let g:OpFuncArgs = [] | 460 LET &opfunc = Fn |
461 normal! g@l | 461 LET g:OpFuncArgs = [] |
462 call assert_equal([12, 'char'], g:OpFuncArgs) | 462 normal! g@l |
463 | 463 call assert_equal([11, 'char'], g:OpFuncArgs) |
464 " Using a string(funcref_variable) to set 'operatorfunc' | 464 |
465 let Fn = function('MyopFunc', [13]) | 465 #" Using a string(funcref_variable) to set 'operatorfunc' |
466 let &operatorfunc = string(Fn) | 466 LET Fn = function('g:MyopFunc', [12]) |
467 let g:OpFuncArgs = [] | 467 LET &operatorfunc = string(Fn) |
468 normal! g@l | 468 LET g:OpFuncArgs = [] |
469 call assert_equal([13, 'char'], g:OpFuncArgs) | 469 normal! g@l |
470 | 470 call assert_equal([12, 'char'], g:OpFuncArgs) |
471 " Test for using a funcref() | 471 |
472 set operatorfunc=funcref('MyopFunc',\ [14]) | 472 #" Test for using a funcref() |
473 let g:OpFuncArgs = [] | 473 set operatorfunc=funcref('g:MyopFunc',\ [13]) |
474 normal! g@l | 474 LET g:OpFuncArgs = [] |
475 call assert_equal([14, 'char'], g:OpFuncArgs) | 475 normal! g@l |
476 | 476 call assert_equal([13, 'char'], g:OpFuncArgs) |
477 " Using a funcref variable to set 'operatorfunc' | 477 |
478 let Fn = funcref('MyopFunc', [15]) | 478 #" Using a funcref variable to set 'operatorfunc' |
479 let &opfunc = Fn | 479 LET Fn = funcref('g:MyopFunc', [14]) |
480 let g:OpFuncArgs = [] | 480 LET &opfunc = Fn |
481 normal! g@l | 481 LET g:OpFuncArgs = [] |
482 call assert_equal([15, 'char'], g:OpFuncArgs) | 482 normal! g@l |
483 | 483 call assert_equal([14, 'char'], g:OpFuncArgs) |
484 " Using a string(funcref_variable) to set 'operatorfunc' | 484 |
485 let Fn = funcref('MyopFunc', [16]) | 485 #" Using a string(funcref_variable) to set 'operatorfunc' |
486 let &opfunc = string(Fn) | 486 LET Fn = funcref('g:MyopFunc', [15]) |
487 let g:OpFuncArgs = [] | 487 LET &opfunc = string(Fn) |
488 normal! g@l | 488 LET g:OpFuncArgs = [] |
489 call assert_equal([16, 'char'], g:OpFuncArgs) | 489 normal! g@l |
490 | 490 call assert_equal([15, 'char'], g:OpFuncArgs) |
491 " Test for using a lambda function using set | 491 |
492 set opfunc={a\ ->\ MyopFunc(17,\ a)} | 492 #" Test for using a lambda function using set |
493 let g:OpFuncArgs = [] | 493 VAR optval = "LSTART a LMIDDLE MyopFunc(16, a) LEND" |
494 normal! g@l | 494 LET optval = substitute(optval, ' ', '\\ ', 'g') |
495 call assert_equal([17, 'char'], g:OpFuncArgs) | 495 exe "set opfunc=" .. optval |
496 | 496 LET g:OpFuncArgs = [] |
497 " Test for using a lambda function using let | 497 normal! g@l |
498 let &opfunc = {a -> MyopFunc(18, a)} | 498 call assert_equal([16, 'char'], g:OpFuncArgs) |
499 let g:OpFuncArgs = [] | 499 |
500 normal! g@l | 500 #" Test for using a lambda function using LET |
501 call assert_equal([18, 'char'], g:OpFuncArgs) | 501 LET &opfunc = LSTART a LMIDDLE MyopFunc(17, a) LEND |
502 | 502 LET g:OpFuncArgs = [] |
503 " Set 'operatorfunc' to a string(lambda expression) | 503 normal! g@l |
504 let &opfunc = '{a -> MyopFunc(19, a)}' | 504 call assert_equal([17, 'char'], g:OpFuncArgs) |
505 let g:OpFuncArgs = [] | 505 |
506 normal! g@l | 506 #" Set 'operatorfunc' to a string(lambda expression) |
507 call assert_equal([19, 'char'], g:OpFuncArgs) | 507 LET &opfunc = 'LSTART a LMIDDLE MyopFunc(18, a) LEND' |
508 | 508 LET g:OpFuncArgs = [] |
509 " Set 'operatorfunc' to a variable with a lambda expression | 509 normal! g@l |
510 let Lambda = {a -> MyopFunc(20, a)} | 510 call assert_equal([18, 'char'], g:OpFuncArgs) |
511 let &opfunc = Lambda | 511 |
512 let g:OpFuncArgs = [] | 512 #" Set 'operatorfunc' to a variable with a lambda expression |
513 normal! g@l | 513 VAR Lambda = LSTART a LMIDDLE MyopFunc(19, a) LEND |
514 call assert_equal([20, 'char'], g:OpFuncArgs) | 514 LET &opfunc = Lambda |
515 | 515 LET g:OpFuncArgs = [] |
516 " Set 'operatorfunc' to a string(variable with a lambda expression) | 516 normal! g@l |
517 let Lambda = {a -> MyopFunc(21, a)} | 517 call assert_equal([19, 'char'], g:OpFuncArgs) |
518 let &opfunc = string(Lambda) | 518 |
519 let g:OpFuncArgs = [] | 519 #" Set 'operatorfunc' to a string(variable with a lambda expression) |
520 normal! g@l | 520 LET Lambda = LSTART a LMIDDLE MyopFunc(20, a) LEND |
521 call assert_equal([21, 'char'], g:OpFuncArgs) | 521 LET &opfunc = string(Lambda) |
522 | 522 LET g:OpFuncArgs = [] |
523 " Try to use 'operatorfunc' after the function is deleted | 523 normal! g@l |
524 func TmpOpFunc(type) | 524 call assert_equal([20, 'char'], g:OpFuncArgs) |
525 let g:OpFuncArgs = [22, a:type] | 525 |
526 endfunc | 526 #" Try to use 'operatorfunc' after the function is deleted |
527 let &opfunc = function('TmpOpFunc') | 527 func g:TmpOpFunc(type) |
528 delfunc TmpOpFunc | 528 LET g:OpFuncArgs = [21, a:type] |
529 call test_garbagecollect_now() | 529 endfunc |
530 let g:OpFuncArgs = [] | 530 LET &opfunc = function('g:TmpOpFunc') |
531 call assert_fails('normal! g@l', 'E117:') | 531 delfunc g:TmpOpFunc |
532 call assert_equal([], g:OpFuncArgs) | 532 call test_garbagecollect_now() |
533 | 533 LET g:OpFuncArgs = [] |
534 " Try to use a function with two arguments for 'operatorfunc' | 534 call assert_fails('normal! g@l', 'E117:') |
535 func! MyopFunc2(x, y) | 535 call assert_equal([], g:OpFuncArgs) |
536 let g:OpFuncArgs = [a:x, a:y] | 536 |
537 endfunc | 537 #" Try to use a function with two arguments for 'operatorfunc' |
538 set opfunc=MyopFunc2 | 538 func MyopFunc2(x, y) |
539 let g:OpFuncArgs = [] | 539 LET g:OpFuncArgs = [a:x, a:y] |
540 call assert_fails('normal! g@l', 'E119:') | 540 endfunc |
541 call assert_equal([], g:OpFuncArgs) | 541 set opfunc=MyopFunc2 |
542 | 542 LET g:OpFuncArgs = [] |
543 " Try to use a lambda function with two arguments for 'operatorfunc' | 543 call assert_fails('normal! g@l', 'E119:') |
544 let &opfunc = {a, b -> MyopFunc(23, b)} | 544 call assert_equal([], g:OpFuncArgs) |
545 let g:OpFuncArgs = [] | 545 |
546 call assert_fails('normal! g@l', 'E119:') | 546 #" Try to use a lambda function with two arguments for 'operatorfunc' |
547 call assert_equal([], g:OpFuncArgs) | 547 LET &opfunc = LSTART a, b LMIDDLE MyopFunc(22, b) LEND |
548 | 548 LET g:OpFuncArgs = [] |
549 " Test for clearing the 'operatorfunc' option | 549 call assert_fails('normal! g@l', 'E119:') |
550 set opfunc='' | 550 call assert_equal([], g:OpFuncArgs) |
551 set opfunc& | 551 |
552 | 552 #" Test for clearing the 'operatorfunc' option |
553 call assert_fails("set opfunc=function('abc')", "E700:") | 553 set opfunc='' |
554 call assert_fails("set opfunc=funcref('abc')", "E700:") | 554 set opfunc& |
555 call assert_fails("set opfunc=function('abc')", "E700:") | |
556 call assert_fails("set opfunc=funcref('abc')", "E700:") | |
557 | |
558 #" set 'operatorfunc' to a non-existing function | |
559 LET &opfunc = function('g:MyopFunc', [23]) | |
560 call assert_fails("set opfunc=function('NonExistingFunc')", 'E700:') | |
561 call assert_fails("LET &opfunc = function('NonExistingFunc')", 'E700:') | |
562 LET g:OpFuncArgs = [] | |
563 normal! g@l | |
564 call assert_equal([23, 'char'], g:OpFuncArgs) | |
565 END | |
566 call CheckTransLegacySuccess(lines) | |
555 | 567 |
556 " Using Vim9 lambda expression in legacy context should fail | 568 " Using Vim9 lambda expression in legacy context should fail |
557 set opfunc=(a)\ =>\ MyopFunc(24,\ a) | 569 set opfunc=(a)\ =>\ MyopFunc(24,\ a) |
558 let g:OpFuncArgs = [] | 570 let g:OpFuncArgs = [] |
559 call assert_fails('normal! g@l', 'E117:') | 571 call assert_fails('normal! g@l', 'E117:') |
560 call assert_equal([], g:OpFuncArgs) | 572 call assert_equal([], g:OpFuncArgs) |
561 | 573 |
562 " set 'operatorfunc' to a non-existing function | 574 " set 'operatorfunc' to a partial with dict. This used to cause a crash. |
563 let &opfunc = function('MyopFunc', [25]) | 575 func SetOpFunc() |
564 call assert_fails("set opfunc=function('NonExistingFunc')", 'E700:') | 576 let operator = {'execute': function('OperatorExecute')} |
565 call assert_fails("let &opfunc = function('NonExistingFunc')", 'E700:') | 577 let &opfunc = operator.execute |
566 let g:OpFuncArgs = [] | 578 endfunc |
567 normal! g@l | 579 func OperatorExecute(_) dict |
568 call assert_equal([25, 'char'], g:OpFuncArgs) | 580 endfunc |
581 call SetOpFunc() | |
582 call test_garbagecollect_now() | |
583 set operatorfunc= | |
584 delfunc SetOpFunc | |
585 delfunc OperatorExecute | |
569 | 586 |
570 " Vim9 tests | 587 " Vim9 tests |
571 let lines =<< trim END | 588 let lines =<< trim END |
572 vim9script | 589 vim9script |
573 | 590 |
574 # Test for using function() | 591 # Test for using a def function with opfunc |
575 def g:Vim9opFunc(val: number, type: string): void | 592 def g:Vim9opFunc(val: number, type: string): void |
576 g:OpFuncArgs = [val, type] | 593 g:OpFuncArgs = [val, type] |
577 enddef | 594 enddef |
578 set opfunc=function('g:Vim9opFunc',\ [60]) | 595 set opfunc=function('g:Vim9opFunc',\ [60]) |
579 g:OpFuncArgs = [] | 596 g:OpFuncArgs = [] |
580 normal! g@l | 597 normal! g@l |
581 assert_equal([60, 'char'], g:OpFuncArgs) | 598 assert_equal([60, 'char'], g:OpFuncArgs) |
582 | |
583 # Test for using a lambda | |
584 &opfunc = (a) => Vim9opFunc(61, a) | |
585 g:OpFuncArgs = [] | |
586 normal! g@l | |
587 assert_equal([61, 'char'], g:OpFuncArgs) | |
588 | |
589 # Test for using a string(lambda) | |
590 &opfunc = '(a) => Vim9opFunc(62, a)' | |
591 g:OpFuncArgs = [] | |
592 normal! g@l | |
593 assert_equal([62, 'char'], g:OpFuncArgs) | |
594 | |
595 # Test for using a variable with a lambda expression | |
596 var Fn: func = (a) => Vim9opFunc(63, a) | |
597 &opfunc = Fn | |
598 g:OpFuncArgs = [] | |
599 normal! g@l | |
600 assert_equal([63, 'char'], g:OpFuncArgs) | |
601 | |
602 # Test for using a string(variable with a lambda expression) | |
603 Fn = (a) => Vim9opFunc(64, a) | |
604 &opfunc = string(Fn) | |
605 g:OpFuncArgs = [] | |
606 normal! g@l | |
607 assert_equal([64, 'char'], g:OpFuncArgs) | |
608 bw! | |
609 END | 599 END |
610 call CheckScriptSuccess(lines) | 600 call CheckScriptSuccess(lines) |
611 | 601 |
612 " cleanup | 602 " cleanup |
613 set opfunc& | 603 set opfunc& |