patch 9.0.1887: Vim9: class members are accessible via object
Problem: Vim9: class members are accessible via object
Solution: Disable class member variable access using an object
Class methods can be accessed only using the class name and cannot be
accessed using an object. To be consistent with this, do the same for
class member variables also. They can be accessed only using the class
name and not using an object.
closes: #13057
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 2549f32..cf6122d 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -1955,10 +1955,6 @@
enddef
endclass
- def F1(i: I1): list<number>
- return [ i.svar1, i.svar2 ]
- enddef
-
def F2(i: I1): list<number>
return [ i.mvar1, i.mvar2 ]
enddef
@@ -1967,10 +1963,6 @@
var ob = B.new()
var oc = C.new()
- assert_equal([11, 12], F1(oa))
- assert_equal([21, 22], F1(ob))
- assert_equal([31, 32], F1(oc))
-
assert_equal([111, 112], F2(oa))
assert_equal([121, 122], F2(ob))
assert_equal([131, 132], F2(oc))
@@ -2041,39 +2033,21 @@
enddef
endclass
- def F1(i: I1): list<number>
- return [ i.svar1, i.svar2 ]
- enddef
-
def F2(i: I1): list<number>
return [ i.mvar1, i.mvar2 ]
enddef
- def F3(i: I2): list<number>
- return [ i.svar3, i.svar4 ]
- enddef
-
def F4(i: I2): list<number>
return [ i.mvar3, i.mvar4 ]
enddef
- def F5(o: C): number
- return o.svar5
- enddef
-
var oa = A.new()
var ob = B.new()
var oc = C.new()
- assert_equal([[11, 12]], [F1(oa)])
- assert_equal([[21, 22], [23, 24]], [F1(ob), F3(ob)])
- assert_equal([[31, 32], [33, 34]], [F1(oc), F3(oc)])
-
assert_equal([[111, 112]], [F2(oa)])
assert_equal([[121, 122], [123, 124]], [F2(ob), F4(ob)])
assert_equal([[131, 132], [133, 134]], [F2(oc), F4(oc)])
-
- assert_equal(1001, F5(oc))
END
v9.CheckScriptSuccess(lines)
enddef
@@ -4182,25 +4156,7 @@
return 11
enddef
- # access the class static through an interface argument
- def F2(i: I): number
- assert_equal(1, i.s_var1)
- assert_equal(2, i.s_var2)
- return 22
- enddef
-
- # access the class static through an object interface
- def F3(o: C): number
- assert_equal(1, o.s_var1)
- assert_equal(2, o.s_var2)
- assert_equal(7, o.x_static)
- return 33
- enddef
-
assert_equal(11, F1())
- var c = C.new()
- assert_equal(22, F2(c))
- assert_equal(33, F3(c))
END
v9.CheckScriptSuccess(lines)
enddef
@@ -4250,7 +4206,7 @@
enddef
T()
END
- v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
+ v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": _val')
# private static member variable
lines =<< trim END
@@ -4362,7 +4318,7 @@
enddef
" Test for accessing a class member variable using an object
-def Test_class_member_access_using_object()
+def Test_class_variable_access_using_object()
var lines =<< trim END
vim9script
class A
@@ -4374,26 +4330,74 @@
A.svar2->add(4)
assert_equal([1, 3], A.svar1)
assert_equal([2, 4], A.svar2)
- var a1 = A.new()
- a1.svar1->add(5)
- a1.svar2->add(6)
- assert_equal([1, 3, 5], a1.svar1)
- assert_equal([2, 4, 6], a1.svar2)
def Foo()
A.svar1->add(7)
A.svar2->add(8)
- assert_equal([1, 3, 5, 7], A.svar1)
- assert_equal([2, 4, 6, 8], A.svar2)
- var a2 = A.new()
- a2.svar1->add(9)
- a2.svar2->add(10)
- assert_equal([1, 3, 5, 7, 9], a2.svar1)
- assert_equal([2, 4, 6, 8, 10], a2.svar2)
+ assert_equal([1, 3, 7], A.svar1)
+ assert_equal([2, 4, 8], A.svar2)
enddef
Foo()
END
v9.CheckScriptSuccess(lines)
+
+ # Cannot read from a class variable using an object in script context
+ lines =<< trim END
+ vim9script
+ class A
+ public this.var1: number
+ public static svar2: list<number> = [1]
+ endclass
+
+ var a = A.new()
+ echo a.svar2
+ END
+ v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": svar2')
+
+ # Cannot write to a class variable using an object in script context
+ lines =<< trim END
+ vim9script
+ class A
+ public this.var1: number
+ public static svar2: list<number> = [1]
+ endclass
+
+ var a = A.new()
+ a.svar2 = [2]
+ END
+ v9.CheckScriptFailure(lines, 'E1334: Object member not found: svar2 = [2]')
+
+ # Cannot read from a class variable using an object in def method context
+ lines =<< trim END
+ vim9script
+ class A
+ public this.var1: number
+ public static svar2: list<number> = [1]
+ endclass
+
+ def T()
+ var a = A.new()
+ echo a.svar2
+ enddef
+ T()
+ END
+ v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": svar2')
+
+ # Cannot write to a class variable using an object in def method context
+ lines =<< trim END
+ vim9script
+ class A
+ public this.var1: number
+ public static svar2: list<number> = [1]
+ endclass
+
+ def T()
+ var a = A.new()
+ a.svar2 = [2]
+ enddef
+ T()
+ END
+ v9.CheckScriptFailure(lines, 'E1089: Unknown variable: svar2 = [2]')
enddef
" Test for using a interface method using a child object
diff --git a/src/version.c b/src/version.c
index 70dd46f..b8e7879 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1887,
+/**/
1886,
/**/
1885,
diff --git a/src/vim9class.c b/src/vim9class.c
index 8e2c88b..14d29c7 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -1966,8 +1966,7 @@
{
// Search in the object member variable table and the class member
// variable table.
- if (get_member_tv(cl, TRUE, name, len, rettv) == OK
- || get_member_tv(cl, FALSE, name, len, rettv) == OK)
+ if (get_member_tv(cl, TRUE, name, len, rettv) == OK)
{
*arg = name_end;
return OK;
diff --git a/src/vim9expr.c b/src/vim9expr.c
index f9756c0..3817e38 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -413,24 +413,6 @@
}
}
- for (int i = 0; i < cl->class_class_member_count; ++i)
- {
- ocmember_T *m = &cl->class_class_members[i];
- if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
- {
- if (*name == '_' && !inside_class(cctx, cl))
- {
- semsg(_(e_cannot_access_private_member_str), m->ocm_name);
- return FAIL;
- }
- *arg = name_end;
- if (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))
- return generate_GET_ITF_MEMBER(cctx, cl, i, m->ocm_type,
- TRUE);
- return generate_GET_OBJ_MEMBER(cctx, i, m->ocm_type, TRUE);
- }
- }
-
// Could be a function reference: "obj.Func".
for (int i = 0; i < cl->class_obj_method_count; ++i)
{