patch 9.0.1838: Vim9: Cannot modify class member vars from def function

Commit: 
https://github.com/vim/vim/commit/3775f777a6add2a8d5060b40414e9c53062c8cd9
Author: Yegappan Lakshmanan <[email protected]>
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 <[email protected]>
    Co-authored-by: Yegappan Lakshmanan <[email protected]>

diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro
index 47bfa9d1f..5fa0ab259 100644
--- 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
index 127531d28..7ad53c763 100644
--- 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_func()
   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
index d6c8ed14f..512950a0a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1838,
 /**/
     1837,
 /**/
diff --git a/src/vim9class.c b/src/vim9class.c
index 0e780fafa..9c7badccb 100644
--- 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_abstract, int 
has_static)
  */
     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
index cc5a302a5..62528e957 100644
--- 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, char_u 
*var_start, cctx_T *cctx)
           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
index b26934dc4..2fbce780f 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2144,7 +2144,7 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
     // 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 *ectx)
        }
        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
index bfbb36971..e89496938 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -438,7 +438,14 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, 
type_T *type)
        {
            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)
        {

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qcAXo-00B2uk-2J%40256bit.org.

Raspunde prin e-mail lui