1
0
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:
Yegappan Lakshmanan
2023-10-02 21:43:58 +02:00
committed by Christian Brabandt
parent 6d11347260
commit b32064fedb
6 changed files with 58 additions and 41 deletions

View File

@@ -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 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);
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 : */

View File

@@ -6338,7 +6338,31 @@ def Test_extended_obj_method_type_check()
endclass
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()
enddef
endclass
@@ -6362,12 +6386,12 @@ def Test_extended_obj_method_type_check()
endclass
class Bar extends Foo
def Doit(p: C): B
def Doit(p: A): 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)
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
vim9script

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1974,
/**/
1973,
/**/

View File

@@ -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)
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 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".
*/
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)
return TRUE;
if (covariance_check)
// Recursively check the base classes.
for (; cl != NULL; cl = cl->class_extends)
{
// Recursively check the base classes.
for (; cl != NULL; cl = cl->class_extends)
if (cl == other_cl)
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)
return TRUE;
// 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];
while (intf != NULL)
{
class_T *intf = cl->class_interfaces_cl[i];
while (intf != NULL)
{
if (intf == other_cl)
return TRUE;
// check the super interfaces
intf = intf->class_extends;
}
if (intf == other_cl)
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;
}
@@ -2938,7 +2928,7 @@ f_instanceof(typval_T *argvars, typval_T *rettv)
}
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;
return;
@@ -2947,9 +2937,8 @@ f_instanceof(typval_T *argvars, typval_T *rettv)
}
else if (classinfo_tv->v_type == VAR_CLASS)
{
rettv->vval.v_number = class_instance_of(
object_tv->vval.v_object->obj_class,
classinfo_tv->vval.v_class, TRUE);
rettv->vval.v_number = class_instance_of(object_tv->vval.v_object->obj_class,
classinfo_tv->vval.v_class);
}
}

View File

@@ -925,10 +925,14 @@ check_type_maybe(
if (actual->tt_class == NULL)
return OK; // A null object matches
// For object method arguments, do a contra-variance type check in
// an extended class. For all others, do a co-variance type check.
if (class_instance_of(actual->tt_class, expected->tt_class,
where.wt_kind != WT_METHOD_ARG) == FALSE)
// For object method arguments, do a invariant type check in
// an extended class. For all others, do a covariance type check.
if (where.wt_kind == WT_METHOD_ARG)
{
if (actual->tt_class != expected->tt_class)
ret = FAIL;
}
else if (!class_instance_of(actual->tt_class, expected->tt_class))
ret = FAIL;
}