patch 9.0.1880: Vim9: Need more tests for inheritance

Commit: 
https://github.com/vim/vim/commit/cf138d4ea5b7e4495abbc867f9bb8a6be6482762
Author: Ernie Rael <err...@raelity.com>
Date:   Wed Sep 6 20:45:03 2023 +0200

    patch 9.0.1880: Vim9: Need more tests for inheritance
    
    Problem:  Vim9: Need more tests for inheritance
    Solution: Add access tests and fixes.
    
    `inside_class` fix from yegappan. `object_index_from_itf_index` fix
    access of member on class extending class implementing interface.
    
    Based on tests from Vim9: Class/Object member variable access control #12979
    
    closes: #13032
    related: #12979
    
    Signed-off-by: Christian Brabandt <c...@256bit.org>
    Co-authored-by: Ernie Rael <err...@raelity.com>
    Co-authored-by: Yegappan Lakshmanan <yegap...@yahoo.com>

diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index bf8f649d6..a6dd66bcc 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -933,6 +933,50 @@ def Test_class_object_member_access()
     endclass
   END
   v9.CheckScriptFailure(lines, 'E1368: Static cannot be followed by "this" in 
a member name')
+
+  # Access from child class extending a class:
+  lines =<< trim END
+      vim9script
+      class A
+        this.ro_obj_var = 10
+        public this.rw_obj_var = 20
+        this._priv_obj_var = 30
+
+        static ro_class_var = 40
+        public static rw_class_var = 50
+        static _priv_class_var = 60
+      endclass
+
+      class B extends A
+        def Foo()
+          var x: number
+          x = this.ro_obj_var
+          this.ro_obj_var = 0
+          x = this.rw_obj_var
+          this.rw_obj_var = 0
+          x = this._priv_obj_var
+          this._priv_obj_var = 0
+
+          x = ro_class_var
+          ro_class_var = 0
+          x = rw_class_var
+          rw_class_var = 0
+          x = _priv_class_var
+          _priv_class_var = 0
+
+          x = A.ro_class_var
+          A.ro_class_var = 0
+          x = A.rw_class_var
+          A.rw_class_var = 0
+          x = A._priv_class_var
+          A._priv_class_var = 0
+        enddef
+      endclass
+
+      var b = B.new()
+      b.Foo()
+  END
+  v9.CheckScriptSuccess(lines)
 enddef
 
 def Test_class_object_compare()
@@ -1867,6 +1911,171 @@ def Test_class_implements_interface()
       endclass
   END
   v9.CheckScriptFailure(lines, 'E1407: Member "IsEven": type mismatch, 
expected func(number): bool but got func(number, ...list<number>): bool')
+
+  # access superclass interface members from subclass, mix variable order
+  lines =<< trim END
+    vim9script
+
+    interface I1
+        public static svar1: number
+        public static svar2: number
+        public this.mvar1: number
+        public this.mvar2: number
+    endinterface
+
+    # NOTE: the order is swapped
+    class A implements I1
+        public this.mvar2: number
+        public this.mvar1: number
+        public static svar2: number
+        public static svar1: number
+        def new()
+            svar1 = 11
+            svar2 = 12
+            this.mvar1 = 111
+            this.mvar2 = 112
+        enddef
+    endclass
+
+    class B extends A
+        def new()
+            svar1 = 21
+            svar2 = 22
+            this.mvar1 = 121
+            this.mvar2 = 122
+        enddef
+    endclass
+
+    class C extends B
+        def new()
+            svar1 = 31
+            svar2 = 32
+            this.mvar1 = 131
+            this.mvar2 = 132
+        enddef
+    endclass
+
+    def F1(i: I1): list<number>
+        return [ i.svar1, i.svar2 ]
+    enddef
+
+    def F2(i: I1): list<number>
+        return [ i.mvar1, i.mvar2 ]
+    enddef
+
+    var oa = A.new()
+    var ob = B.new()
+    var oc = C.new()
+
+    assert_equal([11, 12],   F1(oa))
+    assert_equal([21, 22],   F1(ob))
+    assert_equal([31, 32],   F1(oc))
+
+    assert_equal([111, 112], F2(oa))
+    assert_equal([121, 122], F2(ob))
+    assert_equal([131, 132], F2(oc))
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # Access superclass interface members from subclass, mix variable order.
+  # Two interfaces, one on A, one on B; each has both kinds of variables
+  lines =<< trim END
+    vim9script
+
+    interface I1
+        public static svar1: number
+        public static svar2: number
+        public this.mvar1: number
+        public this.mvar2: number
+    endinterface
+
+    interface I2
+        public static svar3: number
+        public static svar4: number
+        public this.mvar3: number
+        public this.mvar4: number
+    endinterface
+
+    class A implements I1
+        public static svar1: number
+        public static svar2: number
+        public this.mvar1: number
+        public this.mvar2: number
+        def new()
+            svar1 = 11
+            svar2 = 12
+            this.mvar1 = 111
+            this.mvar2 = 112
+        enddef
+    endclass
+
+    class B extends A implements I2
+        public static svar3: number
+        public static svar4: number
+        public this.mvar3: number
+        public this.mvar4: number
+        def new()
+            svar1 = 21
+            svar2 = 22
+            svar3 = 23
+            svar4 = 24
+            this.mvar1 = 121
+            this.mvar2 = 122
+            this.mvar3 = 123
+            this.mvar4 = 124
+        enddef
+    endclass
+
+    class C extends B
+        public static svar5: number
+        def new()
+            svar1 = 31
+            svar2 = 32
+            svar3 = 33
+            svar4 = 34
+            svar5 = 1001
+            this.mvar1 = 131
+            this.mvar2 = 132
+            this.mvar3 = 133
+            this.mvar4 = 134
+        enddef
+    endclass
+
+    def F1(i: I1): list<number>
+        return [ i.svar1, i.svar2 ]
+    enddef
+
+    def F2(i: I1): list<number>
+        return [ i.mvar1, i.mvar2 ]
+    enddef
+
+    def F3(i: I2): list<number>
+        return [ i.svar3, i.svar4 ]
+    enddef
+
+    def F4(i: I2): list<number>
+        return [ i.mvar3, i.mvar4 ]
+    enddef
+
+    def F5(o: C): number
+        return o.svar5
+    enddef
+
+    var oa = A.new()
+    var ob = B.new()
+    var oc = C.new()
+
+    assert_equal([[11, 12]],   [F1(oa)])
+    assert_equal([[21, 22], [23, 24]], [F1(ob), F3(ob)])
+    assert_equal([[31, 32], [33, 34]], [F1(oc), F3(oc)])
+
+    assert_equal([[111, 112]], [F2(oa)])
+    assert_equal([[121, 122], [123, 124]], [F2(ob), F4(ob)])
+    assert_equal([[131, 132], [133, 134]], [F2(oc), F4(oc)])
+
+    assert_equal(1001, F5(oc))
+  END
+  v9.CheckScriptSuccess(lines)
 enddef
 
 def Test_call_interface_method()
@@ -3592,6 +3801,64 @@ def Test_objmethod_funcarg()
   v9.CheckScriptSuccess(lines)
 enddef
 
+def Test_static_inheritence()
+  # subclasses get their own static copy
+  var lines =<< trim END
+    vim9script
+
+    class A
+        static _svar: number
+        this._mvar: number
+        def new()
+            _svar = 1
+            this._mvar = 101
+        enddef
+        def AccessObject(): number
+            return this._mvar
+        enddef
+        def AccessStaticThroughObject(): number
+            return _svar
+        enddef
+    endclass
+
+    class B extends A
+        def new()
+            _svar = 2
+            this._mvar = 102
+        enddef
+    endclass
+
+    class C extends B
+        def new()
+            _svar = 3
+            this._mvar = 103
+        enddef
+
+        def AccessPrivateStaticThroughClassName(): number
+            assert_equal(1, A._svar)
+            assert_equal(2, B._svar)
+            assert_equal(3, C._svar)
+            return 444
+        enddef
+    endclass
+
+    var oa = A.new()
+    var ob = B.new()
+    var oc = C.new()
+    assert_equal(101, oa.AccessObject())
+    assert_equal(102, ob.AccessObject())
+    assert_equal(103, oc.AccessObject())
+
+    assert_equal(444, oc.AccessPrivateStaticThroughClassName())
+
+    # verify object properly resolves to correct static
+    assert_equal(1, oa.AccessStaticThroughObject())
+    assert_equal(2, ob.AccessStaticThroughObject())
+    assert_equal(3, oc.AccessStaticThroughObject())
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 " Test for declaring duplicate object and class members
 def Test_dup_member_variable()
   # Duplicate member variable
diff --git a/src/version.c b/src/version.c
index 4703b4291..a3d6ed0ef 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 */
+/**/
+    1880,
 /**/
     1879,
 /**/
diff --git a/src/vim9class.c b/src/vim9class.c
index cc4410d51..a65173d61 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -237,10 +237,16 @@ object_index_from_itf_index(class_T *itf, int is_method, 
int idx, class_T *cl,
     if (cl == itf)
        return idx;
 
-    itf2class_T *i2c;
-    for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next)
-       if (i2c->i2c_class == cl && i2c->i2c_is_method == is_method)
-           break;
+    itf2class_T *i2c = NULL;
+    int searching = TRUE;
+    for (class_T *super = cl; super != NULL && searching;
+                                               super = super->class_extends)
+       for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next)
+           if (i2c->i2c_class == super && i2c->i2c_is_method == is_method)
+           {
+               searching = FALSE;
+               break;
+           }
     if (i2c == NULL)
     {
        siemsg("class %s not found on interface %s",
@@ -1978,7 +1984,8 @@ class_member_index(char_u *name, size_t len, class_T 
**cl_ret, cctx_T *cctx)
 inside_class(cctx_T *cctx_arg, class_T *cl)
 {
     for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
-       if (cctx->ctx_ufunc != NULL && cctx->ctx_ufunc->uf_class == cl)
+       if (cctx->ctx_ufunc != NULL
+                       && class_instance_of(cctx->ctx_ufunc->uf_class, cl))
            return TRUE;
     return FALSE;
 }

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qdxkz-000j62-0P%40256bit.org.

Raspunde prin e-mail lui