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). 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

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 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 : */

View File

@ -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

View File

@ -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,
/**/ /**/

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) 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,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". * 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. // Recursively check the base classes.
for (; cl != NULL; cl = cl->class_extends) 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; 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);
} }
} }

View File

@ -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;
} }