# HG changeset patch # User Christian Brabandt # Date 1693599304 -7200 # Node ID 2b5cc29b0a0e0c4b03c9c41a844c0c963a2add75 # Parent 3acd40c4c684af2aa2684c926797739dad2a0029 patch 9.0.1838: Vim9: Cannot modify class member vars from def function Commit: https://github.com/vim/vim/commit/3775f777a6add2a8d5060b40414e9c53062c8cd9 Author: Yegappan Lakshmanan Date: Fri Sep 1 22:05:45 2023 +0200 patch 9.0.1838: Vim9: Cannot modify class member vars from def function Problem: Vim9: Cannot modify class member vars from def function Solution: Add support for modifying class member variables from a def function closes: #12995 Signed-off-by: Christian Brabandt Co-authored-by: Yegappan Lakshmanan diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro --- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -1,7 +1,7 @@ /* vim9class.c */ int object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl); void ex_class(exarg_T *eap); -type_T *class_member_type(class_T *cl, char_u *name, char_u *name_end, int *member_idx, ocmember_T **m); +type_T *class_member_type(class_T *cl, int is_object, char_u *name, char_u *name_end, int *member_idx, ocmember_T **m); void ex_enum(exarg_T *eap); void ex_type(exarg_T *eap); int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose); diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -3783,4 +3783,28 @@ def Test_readonly_member_change_in_def_f v9.CheckScriptFailure(lines, 'E46: Cannot change read-only variable "val"') enddef +" Test for reading and writing a class member from a def function +def Test_modify_class_member_from_def_function() + var lines =<< trim END + vim9script + class A + this.var1: number = 10 + public static var2 = 20 + public static var3 = 30 + static _priv_var4: number = 40 + endclass + def T() + assert_equal(20, A.var2) + assert_equal(30, A.var3) + A.var2 = 50 + A.var3 = 60 + assert_equal(50, A.var2) + assert_equal(60, A.var3) + assert_fails('echo A._priv_var4', 'E1333: Cannot access private member: _priv_var4') + enddef + T() + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1838, +/**/ 1837, /**/ 1836, diff --git a/src/vim9class.c b/src/vim9class.c --- a/src/vim9class.c +++ b/src/vim9class.c @@ -33,9 +33,9 @@ parse_member( exarg_T *eap, char_u *line, char_u *varname, - int has_public, // TRUE if "public" seen before "varname" + int has_public, // TRUE if "public" seen before "varname" char_u **varname_end, - garray_T *type_list, + garray_T *type_list, type_T **type_ret, char_u **init_expr) { @@ -119,12 +119,12 @@ parse_member( */ static int add_member( - garray_T *gap, - char_u *varname, - char_u *varname_end, - int has_public, - type_T *type, - char_u *init_expr) + garray_T *gap, + char_u *varname, + char_u *varname_end, + int has_public, + type_T *type, + char_u *init_expr) { if (ga_grow(gap, 1) == FAIL) return FAIL; @@ -629,8 +629,8 @@ is_valid_constructor(ufunc_T *uf, int is */ static int update_member_method_lookup_table( - class_T *ifcl, - class_T *cl, + class_T *ifcl, + class_T *cl, garray_T *objmethods, int pobj_method_offset, int is_interface) @@ -1553,12 +1553,15 @@ cleanup: /* * Find member "name" in class "cl", set "member_idx" to the member index and * return its type. + * When "is_object" is TRUE, then look for object members. Otherwise look for + * class members. * When not found "member_idx" is set to -1 and t_any is returned. * Set *p_m ocmmember_T if not NULL */ type_T * class_member_type( class_T *cl, + int is_object, char_u *name, char_u *name_end, int *member_idx, @@ -1566,10 +1569,14 @@ class_member_type( { *member_idx = -1; // not found (yet) size_t len = name_end - name; + int member_count = is_object ? cl->class_obj_member_count + : cl->class_class_member_count; + ocmember_T *members = is_object ? cl->class_obj_members + : cl->class_class_members; - for (int i = 0; i < cl->class_obj_member_count; ++i) + for (int i = 0; i < member_count; ++i) { - ocmember_T *m = cl->class_obj_members + i; + ocmember_T *m = members + i; if (STRNCMP(m->ocm_name, name, len) == 0 && m->ocm_name[len] == NUL) { *member_idx = i; diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1868,8 +1868,10 @@ compile_lhs( class_T *cl = lhs->lhs_type->tt_class; ocmember_T *m; - lhs->lhs_member_type = class_member_type(cl, after + 1, - lhs->lhs_end, &lhs->lhs_member_idx, &m); + lhs->lhs_member_type = class_member_type(cl, + lhs->lhs_type->tt_type == VAR_OBJECT, + after + 1, lhs->lhs_end, + &lhs->lhs_member_idx, &m); if (lhs->lhs_member_idx < 0) return FAIL; @@ -2091,7 +2093,7 @@ compile_load_lhs_with_index(lhs_T *lhs, return FAIL; class_T *cl = lhs->lhs_type->tt_class; - type_T *type = class_member_type(cl, dot + 1, + type_T *type = class_member_type(cl, TRUE, dot + 1, lhs->lhs_end, &lhs->lhs_member_idx, NULL); if (lhs->lhs_member_idx < 0) diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2144,7 +2144,7 @@ execute_storeindex(isn_T *iptr, ectx_T * // Stack contains: // -3 value to be stored // -2 index - // -1 dict, list, blob or object + // -1 dict, list, blob, object or class tv = STACK_TV_BOT(-3); SOURCING_LNUM = iptr->isn_lnum; @@ -2306,14 +2306,25 @@ execute_storeindex(isn_T *iptr, ectx_T * } else if (dest_type == VAR_CLASS || dest_type == VAR_OBJECT) { - object_T *obj = tv_dest->vval.v_object; - typval_T *otv = (typval_T *)(obj + 1); - - class_T *itf = iptr->isn_arg.storeindex.si_class; - if (itf != NULL) - // convert interface member index to class member index - lidx = object_index_from_itf_index(itf, FALSE, - lidx, obj->obj_class); + typval_T *otv; + + if (dest_type == VAR_OBJECT) + { + object_T *obj = tv_dest->vval.v_object; + + otv = (typval_T *)(obj + 1); + class_T *itf = iptr->isn_arg.storeindex.si_class; + if (itf != NULL) + // convert interface member index to class member index + lidx = object_index_from_itf_index(itf, FALSE, + lidx, obj->obj_class); + } + else + { + // VAR_CLASS + class_T *class = tv_dest->vval.v_class; + otv = class->class_members_tv; + } clear_tv(&otv[lidx]); otv[lidx] = *tv; diff --git a/src/vim9expr.c b/src/vim9expr.c --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -438,7 +438,14 @@ compile_class_object_index(cctx_T *cctx, { ocmember_T *m = &cl->class_class_members[idx]; 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; + } break; + } } if (idx < cl->class_class_member_count) {