patch 9.0.1959: Vim9: methods parameters and types are covariant
Problem: Vim9: methods parameters and types are covariant
Solution: Support contra-variant type check for object method arguments
(similar to Dart).
closes: #12965
closes: #13221
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
diff --git a/src/vim9class.c b/src/vim9class.c
index 885ac03..790c2c3 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -2561,7 +2561,7 @@
{
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))
+ && class_instance_of(cctx->ctx_ufunc->uf_class, cl, TRUE))
return TRUE;
return FALSE;
}
@@ -2871,29 +2871,39 @@
* interfaces matches the class "other_cl".
*/
int
-class_instance_of(class_T *cl, class_T *other_cl)
+class_instance_of(class_T *cl, class_T *other_cl, int covariance_check)
{
if (cl == other_cl)
return TRUE;
- // Recursively check the base classes.
- for (; cl != NULL; cl = cl->class_extends)
+ if (covariance_check)
{
- 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)
+ // Recursively check the base classes.
+ for (; cl != NULL; cl = cl->class_extends)
{
- class_T *intf = cl->class_interfaces_cl[i];
- while (intf != NULL)
+ 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 (intf == other_cl)
- return TRUE;
- // check the super interfaces
- intf = intf->class_extends;
+ 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;
+ }
}
}
}
+ else
+ {
+ // contra-variance
+ for (; other_cl != NULL; other_cl = other_cl->class_extends)
+ if (cl == other_cl)
+ return TRUE;
+ }
return FALSE;
}
@@ -2928,7 +2938,7 @@
}
if (class_instance_of(object_tv->vval.v_object->obj_class,
- li->li_tv.vval.v_class) == TRUE)
+ li->li_tv.vval.v_class, TRUE) == TRUE)
{
rettv->vval.v_number = VVAL_TRUE;
return;
@@ -2937,8 +2947,9 @@
}
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);
+ rettv->vval.v_number = class_instance_of(
+ object_tv->vval.v_object->obj_class,
+ classinfo_tv->vval.v_class, TRUE);
}
}