changeset 33109:2b5cc29b0a0e v9.0.1838

patch 9.0.1838: Vim9: Cannot modify class member vars from def function Commit: https://github.com/vim/vim/commit/3775f777a6add2a8d5060b40414e9c53062c8cd9 Author: Yegappan Lakshmanan <yegappan@yahoo.com> 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 <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author Christian Brabandt <cb@256bit.org>
date Fri, 01 Sep 2023 22:15:04 +0200
parents 3acd40c4c684
children d2b023b2eb46
files src/proto/vim9class.pro src/testdir/test_vim9_class.vim src/version.c src/vim9class.c src/vim9compile.c src/vim9execute.c src/vim9expr.c
diffstat 7 files changed, 78 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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
--- 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,
--- 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;
--- 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)
--- 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;
--- 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)
 	{