summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2023-10-08 19:07:39 +0200
committerChristian Brabandt <cb@256bit.org>2023-10-08 19:07:39 +0200
commitb852305dbf42f1206ecc6ae414fc200235fe2963 (patch)
treef488c4f44ee33cfb1725e001eff7f8a88073d613 /src
parent75b277d35ce207ceb5e3645a962cfd59657d1d73 (diff)
patch 9.0.2002: Vim9: need cleanup of class related interface codev9.0.2002
Problem: Vim9: need cleanup of class related interface code Solution: Remove the unused class variable and class method related code for interfaces. Remove unused class variable and class method related code for interfaces. Refactor the code. Optimize the object/class member double lookup in compile_lhs(). Change unused global functions to static functions. closes: #13302 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Diffstat (limited to 'src')
-rw-r--r--src/proto/vim9class.pro4
-rw-r--r--src/testdir/test_vim9_class.vim57
-rw-r--r--src/version.c2
-rw-r--r--src/vim9class.c428
-rw-r--r--src/vim9cmds.c2
-rw-r--r--src/vim9compile.c29
6 files changed, 266 insertions, 256 deletions
diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro
index e36c7e288e..c9e19d0067 100644
--- a/src/proto/vim9class.pro
+++ b/src/proto/vim9class.pro
@@ -10,11 +10,8 @@ ufunc_T *find_class_func(char_u **arg);
int class_member_idx(class_T *cl, char_u *name, size_t namelen);
ocmember_T *class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
int class_method_idx(class_T *cl, char_u *name, size_t namelen);
-ufunc_T *class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
-int object_member_idx(class_T *cl, char_u *name, size_t namelen);
ocmember_T *object_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
int object_method_idx(class_T *cl, char_u *name, size_t namelen);
-ufunc_T *object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx);
ocmember_T *member_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx);
void emsg_var_cl_define(char *msg, char_u *name, size_t len, class_T *cl);
ufunc_T *method_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx);
@@ -26,7 +23,6 @@ void class_unref(class_T *cl);
int class_free_nonref(int copyID);
int set_ref_in_classes(int copyID);
void object_created(object_T *obj);
-void object_cleared(object_T *obj);
int object_free_nonref(int copyID);
void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 555c46cc8e..c911206c9f 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -975,6 +975,28 @@ def Test_class_new_with_object_member()
Check()
END
v9.CheckSourceSuccess(lines)
+
+ # Try using "this." argument in a class method
+ lines =<< trim END
+ vim9script
+ class A
+ this.val = 10
+ static def Foo(this.val: number)
+ enddef
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1390: Cannot use an object variable "this.val" except with the "new" method', 4)
+
+ # Try using "this." argument in an object method
+ lines =<< trim END
+ vim9script
+ class A
+ this.val = 10
+ def Foo(this.val: number)
+ enddef
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1390: Cannot use an object variable "this.val" except with the "new" method', 4)
enddef
def Test_class_object_member_inits()
@@ -1722,7 +1744,7 @@ def Test_class_member()
var a = A.new()
var v = a.bar
END
- v9.CheckSourceFailure(lines, 'E1326: Variable not found on object "A": bar', 5)
+ v9.CheckSourceFailure(lines, 'E1337: Class variable "bar" not found in class "A"', 5)
enddef
" These messages should show the defining class of the variable (base class),
@@ -4255,7 +4277,7 @@ def Test_private_object_method()
var a = A.new()
a._Foo()
END
- v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 9)
+ v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 9)
# Try calling a private method using an object (from a def function)
lines =<< trim END
@@ -4468,7 +4490,7 @@ def Test_private_object_method()
var c = C.new()
assert_equal(1234, c._Foo())
END
- v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 16)
+ v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 16)
# Using "_" prefix in a method name should fail outside of a class
lines =<< trim END
@@ -4494,7 +4516,7 @@ def Test_private_class_method()
endclass
A._Foo()
END
- v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()', 8)
+ v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 8)
# Try calling a class private method (from a def function)
lines =<< trim END
@@ -5122,7 +5144,7 @@ def Test_class_variable_access_using_object()
var a = A.new()
echo a.svar2
END
- v9.CheckSourceFailure(lines, 'E1375: Class variable "svar2" accessible only using class "A"', 8)
+ v9.CheckSourceFailure(lines, 'E1337: Class variable "svar2" not found in class "A"', 8)
# Cannot write to a class variable using an object in script context
lines =<< trim END
@@ -5597,7 +5619,7 @@ def Test_class_variable()
var a = A.new()
var i = a.val
END
- v9.CheckSourceFailure(lines, 'E1375: Class variable "val" accessible only using class "A"', 7)
+ v9.CheckSourceFailure(lines, 'E1337: Class variable "val" not found in class "A"', 7)
# Modifying a class variable using an object at function level
lines =<< trim END
@@ -5969,6 +5991,18 @@ def Test_extend_interface()
END
v9.CheckSourceSuccess(lines)
+ # extending empty interface
+ lines =<< trim END
+ vim9script
+ interface A
+ endinterface
+ interface B extends A
+ endinterface
+ class C implements B
+ endclass
+ END
+ v9.CheckSourceSuccess(lines)
+
lines =<< trim END
vim9script
interface A
@@ -6567,6 +6601,17 @@ def Test_reserved_varname()
o.F()
END
v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3)
+
+ # class variable name
+ if kword != 'this'
+ lines =<< trim eval END
+ vim9script
+ class C
+ public static {kword}: list<number> = [1, 2, 3]
+ endclass
+ END
+ v9.CheckSourceFailure(lines, $'E1034: Cannot use reserved name {kword}', 3)
+ endif
endfor
enddef
diff --git a/src/version.c b/src/version.c
index e408dc1f71..6a92ab75c7 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2002,
+/**/
2001,
/**/
2000,
diff --git a/src/vim9class.c b/src/vim9class.c
index 7d1a7fdcaa..0cb353bb57 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -555,7 +555,6 @@ validate_abstract_class_methods(
intf_variable_present(
char_u *intf_class_name,
ocmember_T *if_var,
- int is_class_var,
ocmember_T *cl_mt,
int cl_member_count,
class_T *extends_cl)
@@ -600,15 +599,10 @@ intf_variable_present(
if (!variable_present && extends_cl != NULL)
{
- int ext_cl_count = is_class_var
- ? extends_cl->class_class_member_count
- : extends_cl->class_obj_member_count;
- ocmember_T *ext_cl_mt = is_class_var
- ? extends_cl->class_class_members
- : extends_cl->class_obj_members;
+ int ext_cl_count = extends_cl->class_obj_member_count;
+ ocmember_T *ext_cl_mt = extends_cl->class_obj_members;
return intf_variable_present(intf_class_name, if_var,
- is_class_var, ext_cl_mt,
- ext_cl_count,
+ ext_cl_mt, ext_cl_count,
extends_cl->class_extends);
}
@@ -616,43 +610,32 @@ intf_variable_present(
}
/*
- * Check the variables of the interface class "ifcl" match the class variables
- * ("classmembers_gap") and object variables ("objmembers_gap") of a class.
- * Returns TRUE if the class and object variables names are valid.
+ * Check the variables of the interface class "ifcl" match object variables
+ * ("objmembers_gap") of a class.
+ * Returns TRUE if the object variables names are valid.
*/
static int
validate_interface_variables(
char_u *intf_class_name,
class_T *ifcl,
- garray_T *classmembers_gap,
garray_T *objmembers_gap,
class_T *extends_cl)
{
- for (int loop = 1; loop <= 2; ++loop)
+ int if_count = ifcl->class_obj_member_count;
+ if (if_count == 0)
+ return TRUE;
+
+ ocmember_T *if_ms = ifcl->class_obj_members;
+ ocmember_T *cl_ms = (ocmember_T *)(objmembers_gap->ga_data);
+ int cl_count = objmembers_gap->ga_len;
+ for (int if_i = 0; if_i < if_count; ++if_i)
{
- // loop == 1: check class variables
- // loop == 2: check object variables
- int is_class_var = (loop == 1);
- int if_count = is_class_var ? ifcl->class_class_member_count
- : ifcl->class_obj_member_count;
- if (if_count == 0)
- continue;
- ocmember_T *if_ms = is_class_var ? ifcl->class_class_members
- : ifcl->class_obj_members;
- ocmember_T *cl_ms = (ocmember_T *)(is_class_var
- ? classmembers_gap->ga_data
- : objmembers_gap->ga_data);
- int cl_count = is_class_var ? classmembers_gap->ga_len
- : objmembers_gap->ga_len;
- for (int if_i = 0; if_i < if_count; ++if_i)
- {
- if (!intf_variable_present(intf_class_name, &if_ms[if_i],
- is_class_var, cl_ms, cl_count, extends_cl))
- {
- semsg(_(e_variable_str_of_interface_str_not_implemented),
- if_ms[if_i].ocm_name, intf_class_name);
- return FALSE;
- }
+ if (!intf_variable_present(intf_class_name, &if_ms[if_i], cl_ms,
+ cl_count, extends_cl))
+ {
+ semsg(_(e_variable_str_of_interface_str_not_implemented),
+ if_ms[if_i].ocm_name, intf_class_name);
+ return FALSE;
}
}
@@ -685,7 +668,6 @@ intf_method_type_matches(ufunc_T *if_method, ufunc_T *cl_method)
static int
intf_method_present(
ufunc_T *if_ufunc,
- int is_class_method,
ufunc_T **cl_fp,
int cl_count,
class_T *extends_cl)
@@ -707,15 +689,10 @@ intf_method_present(
if (!method_present && extends_cl != NULL)
{
- ufunc_T **ext_cl_fp = (ufunc_T **)(is_class_method
- ? extends_cl->class_class_functions
- : extends_cl->class_obj_methods);
- int ext_cl_count = is_class_method
- ? extends_cl->class_class_function_count
- : extends_cl->class_obj_method_count;
- return intf_method_present(if_ufunc, is_class_method, ext_cl_fp,
- ext_cl_count,
- extends_cl->class_extends);
+ ufunc_T **ext_cl_fp = (ufunc_T **)(extends_cl->class_obj_methods);
+ int ext_cl_count = extends_cl->class_obj_method_count;
+ return intf_method_present(if_ufunc, ext_cl_fp, ext_cl_count,
+ extends_cl->class_extends);
}
return method_present;
@@ -733,37 +710,25 @@ intf_method_present(
validate_interface_methods(
char_u *intf_class_name,
class_T *ifcl,
- garray_T *classfunctions_gap,
garray_T *objmethods_gap,
class_T *extends_cl)
{
- for (int loop = 1; loop <= 2; ++loop)
+ int if_count = ifcl->class_obj_method_count;
+ if (if_count == 0)
+ return TRUE;
+
+ ufunc_T **if_fp = ifcl->class_obj_methods;
+ ufunc_T **cl_fp = (ufunc_T **)(objmethods_gap->ga_data);
+ int cl_count = objmethods_gap->ga_len;
+ for (int if_i = 0; if_i < if_count; ++if_i)
{
- // loop == 1: check class methods
- // loop == 2: check object methods
- int is_class_method = (loop == 1);
- int if_count = is_class_method ? ifcl->class_class_function_count
- : ifcl->class_obj_method_count;
- if (if_count == 0)
- continue;
- ufunc_T **if_fp = is_class_method ? ifcl->class_class_functions
- : ifcl->class_obj_methods;
- ufunc_T **cl_fp = (ufunc_T **)(is_class_method
- ? classfunctions_gap->ga_data
- : objmethods_gap->ga_data);
- int cl_count = is_class_method ? classfunctions_gap->ga_len
- : objmethods_gap->ga_len;
- for (int if_i = 0; if_i < if_count; ++if_i)
- {
- char_u *if_name = if_fp[if_i]->uf_name;
+ char_u *if_name = if_fp[if_i]->uf_name;
- if (!intf_method_present(if_fp[if_i], is_class_method, cl_fp,
- cl_count, extends_cl))
- {
- semsg(_(e_method_str_of_interface_str_not_implemented),
- if_name, intf_class_name);
- return FALSE;
- }
+ if (!intf_method_present(if_fp[if_i], cl_fp, cl_count, extends_cl))
+ {
+ semsg(_(e_method_str_of_interface_str_not_implemented),
+ if_name, intf_class_name);
+ return FALSE;
}
}
@@ -781,8 +746,6 @@ validate_interface_methods(
validate_implements_classes(
garray_T *impl_gap,
class_T **intf_classes,
- garray_T *classfunctions_gap,
- garray_T *classmembers_gap,
garray_T *objmethods_gap,
garray_T *objmembers_gap,
class_T *extends_cl)
@@ -816,15 +779,14 @@ validate_implements_classes(
++ifcl->class_refcount;
// check the variables of the interface match the members of the class
- success = validate_interface_variables(impl, ifcl, classmembers_gap,
- objmembers_gap, extends_cl);
+ success = validate_interface_variables(impl, ifcl, objmembers_gap,
+ extends_cl);
// check the functions/methods of the interface match the
// functions/methods of the class
if (success)
- success = validate_interface_methods(impl, ifcl,
- classfunctions_gap, objmethods_gap,
- extends_cl);
+ success = validate_interface_methods(impl, ifcl, objmethods_gap,
+ extends_cl);
clear_tv(&tv);
}
@@ -1873,9 +1835,7 @@ early_ret:
intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
success = validate_implements_classes(&ga_impl, intf_classes,
- &classfunctions, &classmembers,
- &objmethods, &objmembers,
- extends_cl);
+ &objmethods, &objmembers, extends_cl);
}
// Check no function argument name is used as a class member.
@@ -2172,18 +2132,90 @@ get_member_tv(
return FAIL;
}
- // The object only contains a pointer to the class, the member
- // values array follows right after that.
- object_T *obj = rettv->vval.v_object;
if (is_object)
{
+ // The object only contains a pointer to the class, the member values
+ // array follows right after that.
+ object_T *obj = rettv->vval.v_object;
typval_T *tv = (typval_T *)(obj + 1) + m_idx;
copy_tv(tv, rettv);
+ object_unref(obj);
}
else
+ {
copy_tv(&cl->class_members_tv[m_idx], rettv);
+ class_unref(cl);
+ }
+
+ return OK;
+}
- object_unref(obj);
+/*
+ * Call an object or class method "name" in class "cl". The method return
+ * value is returned in "rettv".
+ */
+ static int
+call_oc_method(
+ class_T *cl,
+ char_u *name,
+ size_t len,
+ char_u *name_end,
+ evalarg_T *evalarg,
+ char_u **arg,
+ typval_T *rettv)
+{
+ ufunc_T *fp;
+ typval_T argvars[MAX_FUNC_ARGS + 1];
+ int argcount = 0;
+
+ fp = method_lookup(cl, rettv->v_type, name, len, NULL);
+ if (fp == NULL)
+ {
+ method_not_found_msg(cl, rettv->v_type, name, len);
+ return FAIL;
+ }
+
+ if (*fp->uf_name == '_')
+ {
+ // Cannot access a private method outside of a class
+ semsg(_(e_cannot_access_private_method_str), fp->uf_name);
+ return FAIL;
+ }
+
+ char_u *argp = name_end;
+ int ret = get_func_arguments(&argp, evalarg, 0, argvars, &argcount);
+ if (ret == FAIL)
+ return FAIL;
+
+ funcexe_T funcexe;
+ CLEAR_FIELD(funcexe);
+ funcexe.fe_evaluate = TRUE;
+ if (rettv->v_type == VAR_OBJECT)
+ {
+ funcexe.fe_object = rettv->vval.v_object;
+ ++funcexe.fe_object->obj_refcount;
+ }
+
+ // Clear the class or object after calling the function, in
+ // case the refcount is one.
+ typval_T tv_tofree = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ // Call the user function. Result goes into rettv;
+ int error = call_user_func_check(fp, argcount, argvars, rettv, &funcexe,
+ NULL);
+
+ // Clear the previous rettv and the arguments.
+ clear_tv(&tv_tofree);
+ for (int idx = 0; idx < argcount; ++idx)
+ clear_tv(&argvars[idx]);
+
+ if (error != FCERR_NONE)
+ {
+ user_func_error(error, printable_func_name(fp), funcexe.fe_found_var);
+ return FAIL;
+ }
+ *arg = argp;
return OK;
}
@@ -2242,104 +2274,22 @@ class_object_index(
}
if (*name_end == '(')
- {
- ufunc_T *fp;
-
- fp = method_lookup(cl, rettv->v_type, name, len, NULL);
- if (fp == NULL)
- {
- method_not_found_msg(cl, rettv->v_type, name, len);
- return FAIL;
- }
-
- typval_T argvars[MAX_FUNC_ARGS + 1];
- int argcount = 0;
-
- if (*fp->uf_name == '_')
- {
- // Cannot access a private method outside of a class
- semsg(_(e_cannot_access_private_method_str), name);
- return FAIL;
- }
-
- char_u *argp = name_end;
- int ret = get_func_arguments(&argp, evalarg, 0,
- argvars, &argcount);
- if (ret == FAIL)
- return FAIL;
-
- funcexe_T funcexe;
- CLEAR_FIELD(funcexe);
- funcexe.fe_evaluate = TRUE;
- if (rettv->v_type == VAR_OBJECT)
- {
- funcexe.fe_object = rettv->vval.v_object;
- ++funcexe.fe_object->obj_refcount;
- }
-
- // Clear the class or object after calling the function, in
- // case the refcount is one.
- typval_T tv_tofree = *rettv;
- rettv->v_type = VAR_UNKNOWN;
-
- // Call the user function. Result goes into rettv;
- int error = call_user_func_check(fp, argcount, argvars,
- rettv, &funcexe, NULL);
-
- // Clear the previous rettv and the arguments.
- clear_tv(&tv_tofree);
- for (int idx = 0; idx < argcount; ++idx)
- clear_tv(&argvars[idx]);
-
- if (error != FCERR_NONE)
- {
- user_func_error(error, printable_func_name(fp),
- funcexe.fe_found_var);
- return FAIL;
- }
- *arg = argp;
- return OK;
- }
+ // Invoke the class or object method
+ return call_oc_method(cl, name, len, name_end, evalarg, arg, rettv);
- else if (rettv->v_type == VAR_OBJECT)
+ else if (rettv->v_type == VAR_OBJECT || rettv->v_type == VAR_CLASS)
{
// Search in the object member variable table and the class member
// variable table.
- if (get_member_tv(cl, TRUE, name, len, rettv) == OK)
+ int is_object = rettv->v_type == VAR_OBJECT;
+ if (get_member_tv(cl, is_object, name, len, rettv) == OK)
{
*arg = name_end;
return OK;
}
if (did_emsg == did_emsg_save)
- member_not_found_msg(cl, VAR_OBJECT, name, len);
- }
-
- else if (rettv->v_type == VAR_CLASS)
- {
- int m_idx;
-
- // class member
- ocmember_T *m = class_member_lookup(cl, name, len, &m_idx);
- if (m == NULL)
- {
- member_not_found_msg(cl, VAR_CLASS, name, len);
- return FAIL;
- }
-
- if (*name == '_')
- {
- emsg_var_cl_define(e_cannot_access_private_variable_str,
- m->ocm_name, 0, cl);
- return FAIL;
- }
-
- typval_T *tv = &cl->class_members_tv[m_idx];
- copy_tv(tv, rettv);
- class_unref(cl);
-
- *arg = name_end;
- return OK;
+ member_not_found_msg(cl, is_object, name, len);
}
return FAIL;
@@ -2433,23 +2383,11 @@ class_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
}
/*
- * Returns the index of class method "name" in the class "cl".
- * Returns -1, if the method is not found.
- */
- int
-class_method_idx(class_T *cl, char_u *name, size_t namelen)
-{
- int idx;
- class_method_lookup(cl, name, namelen, &idx);
- return idx;
-}
-
-/*
* Returns a pointer to the class method "name" in class "cl".
* Returns NULL if the method is not found.
* The method index is set in "idx".
*/
- ufunc_T *
+ static ufunc_T *
class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
{
ufunc_T *ret_fp = NULL;
@@ -2471,11 +2409,23 @@ class_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
}
/*
+ * Returns the index of class method "name" in the class "cl".
+ * Returns -1, if the method is not found.
+ */
+ int
+class_method_idx(class_T *cl, char_u *name, size_t namelen)
+{
+ int idx;
+ class_method_lookup(cl, name, namelen, &idx);
+ return idx;
+}
+
+/*
* Returns the index of object member variable "name" in the class "cl".
* Returns -1, if the variable is not found.
* If "namelen" is zero, then it is assumed that "name" is NUL terminated.
*/
- int
+ static int
object_member_idx(class_T *cl, char_u *name, size_t namelen)
{
int idx;
@@ -2519,23 +2469,11 @@ object_member_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
}
/*
- * Returns the index of object method "name" in the class "cl".
- * Returns -1, if the method is not found.
- */
- int
-object_method_idx(class_T *cl, char_u *name, size_t namelen)
-{
- int idx;
- object_method_lookup(cl, name, namelen, &idx);
- return idx;
-}
-
-/*
* Returns a pointer to the object method "name" in class "cl".
* Returns NULL if the method is not found.
* The object method index is set in "idx".
*/
- ufunc_T *
+ static ufunc_T *
object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
{
ufunc_T *ret_fp = NULL;
@@ -2559,6 +2497,18 @@ object_method_lookup(class_T *cl, char_u *name, size_t namelen, int *idx)
}
/*
+ * Returns the index of object method "name" in the class "cl".
+ * Returns -1, if the method is not found.
+ */
+ int
+object_method_idx(class_T *cl, char_u *name, size_t namelen)
+{
+ int idx;
+ object_method_lookup(cl, name, namelen, &idx);
+ return idx;
+}
+
+/*
* Lookup a class or object member variable by name. If v_type is VAR_CLASS,
* then lookup a class member variable and if it is VAR_OBJECT, then lookup a
* object member variable.
@@ -2682,42 +2632,6 @@ copy_object(typval_T *from, typval_T *to)
}
/*
- * Free an object.
- */
- static void
-object_clear(object_T *obj)
-{
- // Avoid a recursive call, it can happen if "obj" has a circular reference.
- obj->obj_refcount = INT_MAX;
-
- class_T *cl = obj->obj_class;
-
- if (!cl)
- return;
-
- // the member values are just after the object structure
- typval_T *tv = (typval_T *)(obj + 1);
- for (int i = 0; i < cl->class_obj_member_count; ++i)
- clear_tv(tv + i);
-
- // Remove from the list headed by "first_object".
- object_cleared(obj);
-
- vim_free(obj);
- class_unref(cl);
-}
-
-/*
- * Unreference an object.
- */
- void
-object_unref(object_T *obj)
-{
- if (obj != NULL && --obj->obj_refcount <= 0)
- object_clear(obj);
-}
-
-/*
* Make a copy of a class.
*/
void
@@ -2866,7 +2780,7 @@ static object_T *next_nonref_obj = NULL;
* Call this function when an object has been cleared and is about to be freed.
* It is removed from the list headed by "first_object".
*/
- void
+ static void
object_cleared(object_T *obj)
{
if (obj->obj_next_used != NULL)
@@ -2882,6 +2796,42 @@ object_cleared(object_T *obj)
}
/*
+ * Free an object.
+ */
+ static void
+object_clear(object_T *obj)
+{
+ // Avoid a recursive call, it can happen if "obj" has a circular reference.
+ obj->obj_refcount = INT_MAX;
+
+ class_T *cl = obj->obj_class;
+
+ if (!cl)
+ return;
+
+ // the member values are just after the object structure
+ typval_T *tv = (typval_T *)(obj + 1);
+ for (int i = 0; i < cl->class_obj_member_count; ++i)
+ clear_tv(tv + i);
+
+ // Remove from the list headed by "first_object".
+ object_cleared(obj);
+
+ vim_free(obj);
+ class_unref(cl);
+}
+
+/*
+ * Unreference an object.
+ */
+ void
+object_unref(object_T *obj)
+{
+ if (obj != NULL && --obj->obj_refcount <= 0)
+ object_clear(obj);
+}
+
+/*
* Go through the list of all objects and free items without "copyID".
*/
int
diff --git a/src/vim9cmds.c b/src/vim9cmds.c
index 0be207795f..8b5b569808 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -254,7 +254,7 @@ compile_lock_unlock(
{
// Push the class of the bare class variable name
name = cl->class_name;
- len = STRLEN(name);
+ len = (int)STRLEN(name);
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: ... cctx_class_member: name %s",
name);
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 828fe02e81..7e1914b694 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2011,16 +2011,33 @@ compile_lhs(
// for an object or class member get the type of the member
class_T *cl = lhs->lhs_type->tt_class;
int is_object = lhs->lhs_type->tt_type == VAR_OBJECT;
+ char_u *name = var_start + lhs->lhs_varlen + 1;
+ size_t namelen = lhs->lhs_end - var_start - lhs->lhs_varlen - 1;
- if (!lhs_class_member_modifiable(lhs, var_start, cctx))
+ ocmember_T *m = member_lookup(cl, lhs->lhs_type->tt_type,
+ name, namelen, &lhs->lhs_member_idx);
+ if (m == NULL)
+ {
+ member_not_found_msg(cl, lhs->lhs_type->tt_type, name, namelen);
return FAIL;
+ }
- lhs->lhs_member_type = class_member_type(cl,
- is_object,
- after + 1, lhs->lhs_end,
- &lhs->lhs_member_idx);
- if (lhs->lhs_member_idx < 0)
+ // If it is private member variable, then accessing it outside the
+ // class is not allowed.
+ // If it is a read only class variable, then it can be modified
+ // only inside the class where it is defined.
+ if ((m->ocm_access != VIM_ACCESS_ALL) &&
+ ((is_object && !inside_class(cctx, cl))
+ || (!is_object && cctx->ctx_ufunc->uf_class != cl)))
+ {
+ char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE)
+ ? e_cannot_access_private_variable_str
+ : e_variable_is_not_writable_str;
+ emsg_var_cl_define(msg, m->ocm_name, 0, cl);
return FAIL;
+ }
+
+ lhs->lhs_member_type = m->ocm_type;
}
else
{