comparison src/testdir/test_vim9_class.vim @ 33393:016d8f863230 v9.0.1955

patch 9.0.1955: Vim9: lockvar issues with objects/classes Commit: https://github.com/vim/vim/commit/ee865f37acab6cac2cee6a171d60e1b365f852b0 Author: Ernie Rael <errael@raelity.com> Date: Fri Sep 29 19:53:55 2023 +0200 patch 9.0.1955: Vim9: lockvar issues with objects/classes Problem: Vim9: lockvar issues with objects/classes Solution: fix `get_lhs()` object/class access and avoid `SEGV`, make error messages more accurate. - `get_lval()` detects/returns object/class access - `compile_lock_unlock()` generate code for bare static and obj_arg access - `do_lock_var()` check lval for `ll_object`/`ll_class` and fail if so. Details: - Add `ll_object`/`ll_class`/`ll_oi` to `lval_T`. - Add `lockunlock_T` to `isn_T` for `is_arg` to specify handling of `lval_root` in `get_lval()`. - In `get_lval()`, fill in `ll_object`/`ll_class`/`ll_oi` as needed; when no `[idx] or .key`, check lval_root on the way out. - In `do_lock_var()` check for `ll_object`/`ll_class`; also bullet proof ll_dict case and give `Dictionay required` if problem. (not needed to avoid lockvar crash anymore) - In `compile_lock_unlock()` compile for the class variable and func arg cases. closes: #13174 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Ernie Rael <errael@raelity.com>
author Christian Brabandt <cb@256bit.org>
date Fri, 29 Sep 2023 20:00:07 +0200
parents b5ad84fdc702
children bb99820510ef
comparison
equal deleted inserted replaced
33392:3d3d0492824e 33393:016d8f863230
3478 v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected bool but got string', 0) 3478 v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected bool but got string', 0)
3479 enddef 3479 enddef
3480 3480
3481 " Test for locking a variable referring to an object and reassigning to another 3481 " Test for locking a variable referring to an object and reassigning to another
3482 " object. 3482 " object.
3483 def Test_object_lockvar() 3483 def Test_lockvar_object()
3484 var lines =<< trim END 3484 var lines =<< trim END
3485 vim9script 3485 vim9script
3486 3486
3487 class C 3487 class C
3488 this.val: number 3488 this.val: number
3509 3509
3510 F() 3510 F()
3511 assert_equal(3, current.val) 3511 assert_equal(3, current.val)
3512 G() 3512 G()
3513 assert_equal(2, current.val) 3513 assert_equal(2, current.val)
3514 END
3515 v9.CheckSourceSuccess(lines)
3516 enddef
3517
3518 " Test trying to lock an object variable from various places
3519 def Test_lockvar_object_variable()
3520 # An object variable lockvar has several cases:
3521 # object method, scriptlevel, scriplevel from :def, :def arg
3522 # method arg, static method arg.
3523 # Also different depths
3524
3525 # TODO: handle inside_class in vim9class
3526 # lockvar of a read-only currently fails even if inside
3527
3528 #
3529 # lockvar of read-only object variable
3530 #
3531
3532 # read-only lockvar from object method
3533 var lines =<< trim END
3534 vim9script
3535
3536 class C
3537 this.val1: number
3538 def Lock()
3539 lockvar this.val1
3540 enddef
3541 endclass
3542 var o = C.new(3)
3543 o.Lock()
3544 END
3545 # TODO: wrong error
3546 v9.CheckSourceFailure(lines, 'E1335: Variable "val1" in class "C" is not writable')
3547
3548 # read-only lockvar from scriptlevel
3549 lines =<< trim END
3550 vim9script
3551
3552 class C
3553 this.val2: number
3554 endclass
3555 var o = C.new(3)
3556 lockvar o.val2
3557 END
3558 v9.CheckSourceFailure(lines, 'E1335: Variable "val2" in class "C" is not writable')
3559
3560 # read-only lockvar of scriptlevel variable from def
3561 lines =<< trim END
3562 vim9script
3563
3564 class C
3565 this.val3: number
3566 endclass
3567 var o = C.new(3)
3568 def Lock()
3569 lockvar o.val3
3570 enddef
3571 Lock()
3572 END
3573 v9.CheckSourceFailure(lines, 'E1335: Variable "val3" in class "C" is not writable')
3574
3575 # read-only lockvar of def argument variable
3576 lines =<< trim END
3577 vim9script
3578
3579 class C
3580 this.val4: number
3581 endclass
3582 def Lock(o: C)
3583 lockvar o.val4
3584 enddef
3585 Lock(C.new(3))
3586 END
3587 v9.CheckSourceFailure(lines, 'E1335: Variable "val4" in class "C" is not writable')
3588
3589 # TODO: the following tests use type "any" for argument. Need a run time
3590 # check for access. Probably OK as is for now.
3591
3592 # read-only lockvar from object method arg
3593 lines =<< trim END
3594 vim9script
3595
3596 class C
3597 this.val5: number
3598 def Lock(o_any: any)
3599 lockvar o_any.val5
3600 enddef
3601 endclass
3602 var o = C.new(3)
3603 o.Lock(C.new(5))
3604 END
3605 # TODO: wrong error, tricky since type "any"
3606 v9.CheckSourceFailure(lines, 'E1335: Variable "val5" in class "C" is not writable')
3607
3608 # read-only lockvar from class method arg
3609 lines =<< trim END
3610 vim9script
3611
3612 class C
3613 this.val6: number
3614 static def Lock(o_any: any)
3615 lockvar o_any.val6
3616 enddef
3617 endclass
3618 var o = C.new(3)
3619 C.Lock(o)
3620 END
3621 # TODO: wrong error, tricky since type "any"
3622 v9.CheckSourceFailure(lines, 'E1335: Variable "val6" in class "C" is not writable')
3623
3624 #
3625 # lockvar of public object variable
3626 #
3627
3628 # lockvar from object method
3629 lines =<< trim END
3630 vim9script
3631
3632 class C
3633 public this.val1: number
3634 def Lock()
3635 lockvar this.val1
3636 enddef
3637 endclass
3638 var o = C.new(3)
3639 o.Lock()
3640 END
3641 v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "this.val1" in class "C"', 1)
3642
3643 # lockvar from scriptlevel
3644 lines =<< trim END
3645 vim9script
3646
3647 class C
3648 public this.val2: number
3649 endclass
3650 var o = C.new(3)
3651 lockvar o.val2
3652 END
3653 v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o.val2" in class "C"', 7)
3654
3655 # lockvar of scriptlevel variable from def
3656 lines =<< trim END
3657 vim9script
3658
3659 class C
3660 public this.val3: number
3661 endclass
3662 var o = C.new(3)
3663 def Lock()
3664 lockvar o.val3
3665 enddef
3666 Lock()
3667 END
3668 v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o.val3" in class "C"', 1)
3669
3670 # lockvar of def argument variable
3671 lines =<< trim END
3672 vim9script
3673
3674 class C
3675 public this.val4: number
3676 endclass
3677 def Lock(o: C)
3678 lockvar o.val4
3679 enddef
3680 Lock(C.new(3))
3681 END
3682 v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o.val4" in class "C"', 1)
3683
3684 # lockvar from object method arg
3685 lines =<< trim END
3686 vim9script
3687
3688 class C
3689 public this.val5: number
3690 def Lock(o_any: any)
3691 lockvar o_any.val5
3692 enddef
3693 endclass
3694 var o = C.new(3)
3695 o.Lock(C.new(5))
3696 END
3697 v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o_any.val5" in class "C"', 1)
3698
3699 # lockvar from class method arg
3700 lines =<< trim END
3701 vim9script
3702
3703 class C
3704 public this.val6: number
3705 static def Lock(o_any: any)
3706 lockvar o_any.val6
3707 enddef
3708 endclass
3709 var o = C.new(3)
3710 C.Lock(o)
3711 END
3712 v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o_any.val6" in class "C"', 1)
3713 enddef
3714
3715 " Test trying to lock a class variable from various places
3716 def Test_lockvar_class_variable()
3717
3718 # lockvar bare static from object method
3719 var lines =<< trim END
3720 vim9script
3721
3722 class C
3723 public static sval1: number
3724 def Lock()
3725 lockvar sval1
3726 enddef
3727 endclass
3728 var o = C.new()
3729 o.Lock()
3730 END
3731 v9.CheckSourceFailure(lines, 'E1392: Cannot (un)lock class variable "sval1" in class "C"', 1)
3732
3733 # lockvar C.static from object method
3734 lines =<< trim END
3735 vim9script
3736
3737 class C
3738 public static sval2: number
3739 def Lock()
3740 lockvar C.sval2
3741 enddef
3742 endclass
3743 var o = C.new()
3744 o.Lock()
3745 END
3746 v9.CheckSourceFailure(lines, 'E1392: Cannot (un)lock class variable "C.sval2" in class "C"', 1)
3747
3748 # lockvar bare static from class method
3749 lines =<< trim END
3750 vim9script
3751
3752 class C
3753 public static sval3: number
3754 static def Lock()
3755 lockvar sval3
3756 enddef
3757 endclass
3758 C.Lock()
3759 END
3760 v9.CheckSourceFailure(lines, 'E1392: Cannot (un)lock class variable "sval3" in class "C"', 1)
3761
3762 # lockvar C.static from class method
3763 lines =<< trim END
3764 vim9script
3765
3766 class C
3767 public static sval4: number
3768 static def Lock()
3769 lockvar C.sval4
3770 enddef
3771 endclass
3772 C.Lock()
3773 END
3774 v9.CheckSourceFailure(lines, 'E1392: Cannot (un)lock class variable "C.sval4" in class "C"', 1)
3775
3776 # lockvar C.static from script level
3777 lines =<< trim END
3778 vim9script
3779
3780 class C
3781 public static sval5: number
3782 endclass
3783 lockvar C.sval5
3784 END
3785 v9.CheckSourceFailure(lines, 'E1392: Cannot (un)lock class variable "C.sval5" in class "C"', 6)
3786
3787 # lockvar o.static from script level
3788 lines =<< trim END
3789 vim9script
3790
3791 class C
3792 public static sval6: number
3793 endclass
3794 var o = C.new()
3795 lockvar o.sval6
3796 END
3797 v9.CheckSourceFailure(lines, 'E1375: Class variable "sval6" accessible only using class "C"', 7)
3798 enddef
3799
3800 " Test locking an argument to :def
3801 def Test_lockvar_argument()
3802 # Lockvar a function arg
3803 var lines =<< trim END
3804 vim9script
3805
3806 def Lock(val: any)
3807 lockvar val
3808 enddef
3809
3810 var d = {a: 1, b: 2}
3811 Lock(d)
3812
3813 d->extend({c: 3})
3814 END
3815 v9.CheckSourceFailure(lines, 'E741: Value is locked: extend() argument')
3816
3817 # Lockvar a function arg. Verify "sval" is interpreted as argument and not a
3818 # class member in "C". This tests lval_root_is_arg.
3819 lines =<< trim END
3820 vim9script
3821
3822 class C
3823 public static sval: list<number>
3824 endclass
3825
3826 def Lock2(sval: any)
3827 lockvar sval
3828 enddef
3829
3830 var o = C.new()
3831 Lock2(o)
3832 END
3833 v9.CheckSourceSuccess(lines)
3834
3835 # Lock a class.
3836 lines =<< trim END
3837 vim9script
3838
3839 class C
3840 public static sval: list<number>
3841 endclass
3842
3843 def Lock2(sval: any)
3844 lockvar sval
3845 enddef
3846
3847 Lock2(C)
3848 END
3849 v9.CheckSourceSuccess(lines)
3850
3851 # Lock an object.
3852 lines =<< trim END
3853 vim9script
3854
3855 class C
3856 public static sval: list<number>
3857 endclass
3858
3859 def Lock2(sval: any)
3860 lockvar sval
3861 enddef
3862
3863 Lock2(C.new())
3864 END
3865 v9.CheckSourceSuccess(lines)
3866
3867 # In this case (unlike previous) "lockvar sval" is a class member.
3868 lines =<< trim END
3869 vim9script
3870
3871 class C
3872 public static sval: list<number>
3873 def Lock2()
3874 lockvar sval
3875 enddef
3876 endclass
3877
3878
3879 var o = C.new()
3880 o.Lock2()
3881 END
3882 v9.CheckSourceFailure(lines, 'E1392: Cannot (un)lock class variable "sval" in class "C"', 1)
3883 enddef
3884
3885 " Test that this can be locked without error
3886 def Test_lockvar_this()
3887 # lockvar this
3888 var lines =<< trim END
3889 vim9script
3890 class C
3891 def TLock()
3892 lockvar this
3893 enddef
3894 endclass
3895 var o = C.new()
3896 o.TLock()
3897 END
3898 v9.CheckSourceSuccess(lines)
3899
3900 # lockvar four (four letter word, but not this)
3901 lines =<< trim END
3902 vim9script
3903 class C
3904 def TLock4()
3905 var four: number
3906 lockvar four
3907 enddef
3908 endclass
3909 var o = C.new()
3910 o.TLock4()
3911 END
3912 v9.CheckSourceFailure(lines, 'E1178: Cannot lock or unlock a local variable')
3913
3914 # lockvar this5; "this" + one char, 5 letter word, starting with "this"
3915 lines =<< trim END
3916 vim9script
3917 class C
3918 def TLock5()
3919 var this5: number
3920 lockvar this5
3921 enddef
3922 endclass
3923 var o = C.new()
3924 o.TLock5()
3925 END
3926 v9.CheckSourceFailure(lines, 'E1178: Cannot lock or unlock a local variable')
3927 enddef
3928
3929 " Test some general lockvar cases
3930 def Test_lockvar_general()
3931 # lockvar an object and a class. It does nothing
3932 var lines =<< trim END
3933 vim9script
3934 class C
3935 endclass
3936 var o = C.new()
3937 lockvar o
3938 lockvar C
3939 END
3940 v9.CheckSourceSuccess(lines)
3941
3942 # Lock a list element that's nested in an object variable from a :def
3943 lines =<< trim END
3944 vim9script
3945
3946 class C
3947 public this.val: list<list<number>> = [ [1], [2], [3] ]
3948 endclass
3949 def Lock2(obj: any)
3950 lockvar obj.val[1]
3951 enddef
3952
3953 var o = C.new()
3954 Lock2(o)
3955 o.val[0] = [9]
3956 assert_equal([ [9], [2], [3] ], o.val)
3957 try
3958 o.val[1] = [999]
3959 call assert_false(true, 'assign should have failed')
3960 catch
3961 assert_exception('E741:')
3962 endtry
3963 o.val[2] = [8]
3964 assert_equal([ [9], [2], [8] ], o.val)
3965 END
3966 v9.CheckSourceSuccess(lines)
3967
3968 # Lock a list element that's nested in an object variable from scriptlevel
3969 lines =<< trim END
3970 vim9script
3971
3972 class C
3973 public this.val: list<list<number>> = [ [1], [2], [3] ]
3974 endclass
3975
3976 var o = C.new()
3977 lockvar o.val[1]
3978 o.val[0] = [9]
3979 assert_equal([ [9], [2], [3] ], o.val)
3980 try
3981 o.val[1] = [999]
3982 call assert_false(true, 'assign should have failed')
3983 catch
3984 assert_exception('E741:')
3985 endtry
3986 o.val[2] = [8]
3987 assert_equal([ [9], [2], [8] ], o.val)
3514 END 3988 END
3515 v9.CheckSourceSuccess(lines) 3989 v9.CheckSourceSuccess(lines)
3516 enddef 3990 enddef
3517 3991
3518 " Test for a private object method 3992 " Test for a private object method