forked from aniani/vim
patch 9.0.1974: vim9: using contra-variant type-checks
Problem: vim9: using contra-variant type-checks (after v9.0.1959) Solution: Use invariant type checking instead closes: #13248 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
parent
6d11347260
commit
b32064fedb
@ -547,11 +547,9 @@ Object variables from the base class are all taken over by the child class. It
|
|||||||
is not possible to override them (unlike some other languages).
|
is not possible to override them (unlike some other languages).
|
||||||
|
|
||||||
*E1356* *E1357* *E1358*
|
*E1356* *E1357* *E1358*
|
||||||
Object methods of the base class can be overruled. The number of arguments
|
Object methods of the base class can be overruled. The signature (arguments,
|
||||||
must be exactly the same. The method argument type can be a contra-variant
|
argument types and return type) must be exactly the same. The method of the
|
||||||
type of the base class method argument type. The method return value type can
|
base class can be called by prefixing "super.".
|
||||||
be a covariant type of the base class method return value type. The method of
|
|
||||||
the base class can be called by prefixing "super.".
|
|
||||||
|
|
||||||
*E1377*
|
*E1377*
|
||||||
The access level of a method (public or private) in a child class should be
|
The access level of a method (public or private) in a child class should be
|
||||||
|
@ -29,5 +29,5 @@ int object_free_nonref(int copyID);
|
|||||||
void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
|
void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
|
||||||
void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
|
void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
|
||||||
void f_instanceof(typval_T *argvars, typval_T *rettv);
|
void f_instanceof(typval_T *argvars, typval_T *rettv);
|
||||||
int class_instance_of(class_T *cl, class_T *other_cl, int covariance_check);
|
int class_instance_of(class_T *cl, class_T *other_cl);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@ -6338,7 +6338,31 @@ def Test_extended_obj_method_type_check()
|
|||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Bar extends Foo
|
class Bar extends Foo
|
||||||
def Doit(p: A): C
|
def Doit(p: C): B
|
||||||
|
return B.new()
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, 'E1383: Method "Doit": type mismatch, expected func(object<B>): object<B> but got func(object<C>): object<B>', 20)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class A
|
||||||
|
endclass
|
||||||
|
class B extends A
|
||||||
|
endclass
|
||||||
|
class C extends B
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Foo
|
||||||
|
def Doit(p: B): B
|
||||||
|
return B.new()
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Bar extends Foo
|
||||||
|
def Doit(p: B): C
|
||||||
return C.new()
|
return C.new()
|
||||||
enddef
|
enddef
|
||||||
endclass
|
endclass
|
||||||
@ -6362,12 +6386,12 @@ def Test_extended_obj_method_type_check()
|
|||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Bar extends Foo
|
class Bar extends Foo
|
||||||
def Doit(p: C): B
|
def Doit(p: A): B
|
||||||
return B.new()
|
return B.new()
|
||||||
enddef
|
enddef
|
||||||
endclass
|
endclass
|
||||||
END
|
END
|
||||||
v9.CheckSourceFailure(lines, 'E1383: Method "Doit": type mismatch, expected func(object<B>): object<B> but got func(object<C>): object<B>', 20)
|
v9.CheckSourceFailure(lines, 'E1383: Method "Doit": type mismatch, expected func(object<B>): object<B> but got func(object<A>): object<B>', 20)
|
||||||
|
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1974,
|
||||||
/**/
|
/**/
|
||||||
1973,
|
1973,
|
||||||
/**/
|
/**/
|
||||||
|
@ -2561,7 +2561,7 @@ inside_class(cctx_T *cctx_arg, class_T *cl)
|
|||||||
{
|
{
|
||||||
for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
|
for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
|
||||||
if (cctx->ctx_ufunc != NULL
|
if (cctx->ctx_ufunc != NULL
|
||||||
&& class_instance_of(cctx->ctx_ufunc->uf_class, cl, TRUE))
|
&& class_instance_of(cctx->ctx_ufunc->uf_class, cl))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -2871,39 +2871,29 @@ member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len)
|
|||||||
* interfaces matches the class "other_cl".
|
* interfaces matches the class "other_cl".
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
class_instance_of(class_T *cl, class_T *other_cl, int covariance_check)
|
class_instance_of(class_T *cl, class_T *other_cl)
|
||||||
{
|
{
|
||||||
if (cl == other_cl)
|
if (cl == other_cl)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (covariance_check)
|
// Recursively check the base classes.
|
||||||
|
for (; cl != NULL; cl = cl->class_extends)
|
||||||
{
|
{
|
||||||
// Recursively check the base classes.
|
if (cl == other_cl)
|
||||||
for (; cl != NULL; cl = cl->class_extends)
|
return TRUE;
|
||||||
|
// Check the implemented interfaces and the super interfaces
|
||||||
|
for (int i = cl->class_interface_count - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
if (cl == other_cl)
|
class_T *intf = cl->class_interfaces_cl[i];
|
||||||
return TRUE;
|
while (intf != NULL)
|
||||||
// Check the implemented interfaces and the super interfaces
|
|
||||||
for (int i = cl->class_interface_count - 1; i >= 0; --i)
|
|
||||||
{
|
{
|
||||||
class_T *intf = cl->class_interfaces_cl[i];
|
if (intf == other_cl)
|
||||||
while (intf != NULL)
|
return TRUE;
|
||||||
{
|
// check the super interfaces
|
||||||
if (intf == other_cl)
|
intf = intf->class_extends;
|
||||||
return TRUE;
|
|
||||||
// check the super interfaces
|
|
||||||
intf = intf->class_extends;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// contra-variance
|
|
||||||
for (; other_cl != NULL; other_cl = other_cl->class_extends)
|
|
||||||
if (cl == other_cl)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -2938,7 +2928,7 @@ f_instanceof(typval_T *argvars, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (class_instance_of(object_tv->vval.v_object->obj_class,
|
if (class_instance_of(object_tv->vval.v_object->obj_class,
|
||||||
li->li_tv.vval.v_class, TRUE) == TRUE)
|
li->li_tv.vval.v_class) == TRUE)
|
||||||
{
|
{
|
||||||
rettv->vval.v_number = VVAL_TRUE;
|
rettv->vval.v_number = VVAL_TRUE;
|
||||||
return;
|
return;
|
||||||
@ -2947,9 +2937,8 @@ f_instanceof(typval_T *argvars, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
else if (classinfo_tv->v_type == VAR_CLASS)
|
else if (classinfo_tv->v_type == VAR_CLASS)
|
||||||
{
|
{
|
||||||
rettv->vval.v_number = class_instance_of(
|
rettv->vval.v_number = class_instance_of(object_tv->vval.v_object->obj_class,
|
||||||
object_tv->vval.v_object->obj_class,
|
classinfo_tv->vval.v_class);
|
||||||
classinfo_tv->vval.v_class, TRUE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,10 +925,14 @@ check_type_maybe(
|
|||||||
if (actual->tt_class == NULL)
|
if (actual->tt_class == NULL)
|
||||||
return OK; // A null object matches
|
return OK; // A null object matches
|
||||||
|
|
||||||
// For object method arguments, do a contra-variance type check in
|
// For object method arguments, do a invariant type check in
|
||||||
// an extended class. For all others, do a co-variance type check.
|
// an extended class. For all others, do a covariance type check.
|
||||||
if (class_instance_of(actual->tt_class, expected->tt_class,
|
if (where.wt_kind == WT_METHOD_ARG)
|
||||||
where.wt_kind != WT_METHOD_ARG) == FALSE)
|
{
|
||||||
|
if (actual->tt_class != expected->tt_class)
|
||||||
|
ret = FAIL;
|
||||||
|
}
|
||||||
|
else if (!class_instance_of(actual->tt_class, expected->tt_class))
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user