mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
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 <cb@256bit.org> Co-authored-by: Ernie Rael <errael@raelity.com> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
committed by
Christian Brabandt
parent
f7ac0ef509
commit
cf138d4ea5
@@ -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
|
||||
|
@@ -699,6 +699,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1880,
|
||||
/**/
|
||||
1879,
|
||||
/**/
|
||||
|
@@ -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;
|
||||
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 == cl && i2c->i2c_is_method == is_method)
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user