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&