]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1838: Vim9: Cannot modify class member vars from def function v9.0.1838
authorYegappan Lakshmanan <yegappan@yahoo.com>
Fri, 1 Sep 2023 20:05:45 +0000 (22:05 +0200)
committerChristian Brabandt <cb@256bit.org>
Fri, 1 Sep 2023 20:05:45 +0000 (22:05 +0200)
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>
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

index 47bfa9d1f522fbd18337d249032d9cb96d549d3f..5fa0ab259161109b23081b47a6f7249f44a3a64d 100644 (file)
@@ -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);
index 127531d28f2927af125d0ee6e477c0a51ce2ef49..7ad53c763eff8fd7f5da6e26c524743a0b3b0fbe 100644 (file)
@@ -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
index d6c8ed14f3ecb91b6975e17ed6aaae266d9b97fc..512950a0ae0625a1ac5ece0b66c3dd021e6c2653 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1838,
 /**/
     1837,
 /**/
index 0e780fafaba3746ca867f062c9c62fdeb7cafe72..9c7badccb241ffae177bc876d5e489dc7d66bd62 100644 (file)
@@ -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;
index cc5a302a5343120469619485ff0aa172f846866f..62528e957007f48ccfff75e6f8b93a9c620937b1 100644 (file)
@@ -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)
index b26934dc4740ca66e6ffbdc74b180d4ffa84824b..2fbce780f789468051d23c4d8da1ea31b86c6c24 100644 (file)
@@ -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;
index bfbb369715b446abd2bbc8d258bfad3f6490a2be..e8949693841da2984adcbff8130cbd54871e9449 100644 (file)
@@ -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)
        {