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
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
6 changed files with 58 additions and 41 deletions

View File

@ -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).
*E1356* *E1357* *E1358*
Object methods of the base class can be overruled. The number of arguments
must be exactly the same. The method argument type can be a contra-variant
type of the base class method argument type. The method return value type can
be a covariant type of the base class method return value type. The method of
the base class can be called by prefixing "super.".
Object methods of the base class can be overruled. The signature (arguments,
argument types and return type) must be exactly the same. The method of the
base class can be called by prefixing "super.".
*E1377*
The access level of a method (public or private) in a child class should be

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,13 +2871,11 @@ 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)
{
@ -2896,14 +2894,6 @@ class_instance_of(class_T *cl, class_T *other_cl, int covariance_check)
}
}
}
}
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;
}