summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2023-10-02 21:43:58 +0200
committerChristian Brabandt <cb@256bit.org>2023-10-02 21:43:58 +0200
commitb32064fedbeb689ecb0481e9473cb7b87d5bb805 (patch)
treeceebd338012f6a58fd4bff67750cfd2938e360e9
parent6d113472601fa6f3a444a95ef7b11d4309215117 (diff)
patch 9.0.1974: vim9: using contra-variant type-checksv9.0.1974
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>
-rw-r--r--runtime/doc/vim9class.txt8
-rw-r--r--src/proto/vim9class.pro2
-rw-r--r--src/testdir/test_vim9_class.vim30
-rw-r--r--src/version.c2
-rw-r--r--src/vim9class.c45
-rw-r--r--src/vim9type.c12
6 files changed, 58 insertions, 41 deletions
diff --git a/runtime/doc/vim9class.txt b/runtime/doc/vim9class.txt
index 0660254696..d8bd0328cd 100644
--- a/runtime/doc/vim9class.txt
+++ b/runtime/doc/vim9class.txt
@@ -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
diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro
index 31e2be70f4..9edf35408e 100644
--- a/src/proto/vim9class.pro
+++ b/src/proto/vim9class.pro
@@ -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 : */
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 856ee03108..4a92a3d3a2 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index e93ee41947..b46d20c2c8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1974,
+/**/
1973,
/**/
1972,
diff --git a/src/vim9class.c b/src/vim9class.c
index 790c2c36f6..885ac0385c 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -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);
}
}
diff --git a/src/vim9type.c b/src/vim9type.c
index 4b8064df1b..de1033c2e9 100644
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -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;
}