Skip to content

Commit b32064f

Browse files
yegappanchrisbra
authored andcommitted
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 <[email protected]> Co-authored-by: Yegappan Lakshmanan <[email protected]>
1 parent 6d11347 commit b32064f

6 files changed

Lines changed: 58 additions & 41 deletions

File tree

runtime/doc/vim9class.txt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -547,11 +547,9 @@ Object variables from the base class are all taken over by the child class. It
547547
is not possible to override them (unlike some other languages).
548548

549549
*E1356* *E1357* *E1358*
550-
Object methods of the base class can be overruled. The number of arguments
551-
must be exactly the same. The method argument type can be a contra-variant
552-
type of the base class method argument type. The method return value type can
553-
be a covariant type of the base class method return value type. The method of
554-
the base class can be called by prefixing "super.".
550+
Object methods of the base class can be overruled. The signature (arguments,
551+
argument types and return type) must be exactly the same. The method of the
552+
base class can be called by prefixing "super.".
555553

556554
*E1377*
557555
The access level of a method (public or private) in a child class should be

src/proto/vim9class.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ int object_free_nonref(int copyID);
2929
void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
3030
void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
3131
void f_instanceof(typval_T *argvars, typval_T *rettv);
32-
int class_instance_of(class_T *cl, class_T *other_cl, int covariance_check);
32+
int class_instance_of(class_T *cl, class_T *other_cl);
3333
/* vim: set ft=c : */

src/testdir/test_vim9_class.vim

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6338,7 +6338,31 @@ def Test_extended_obj_method_type_check()
63386338
endclass
63396339

63406340
class Bar extends Foo
6341-
def Doit(p: A): C
6341+
def Doit(p: C): B
6342+
return B.new()
6343+
enddef
6344+
endclass
6345+
END
6346+
v9.CheckSourceFailure(lines, 'E1383: Method "Doit": type mismatch, expected func(object<B>): object<B> but got func(object<C>): object<B>', 20)
6347+
6348+
lines =<< trim END
6349+
vim9script
6350+
6351+
class A
6352+
endclass
6353+
class B extends A
6354+
endclass
6355+
class C extends B
6356+
endclass
6357+
6358+
class Foo
6359+
def Doit(p: B): B
6360+
return B.new()
6361+
enddef
6362+
endclass
6363+
6364+
class Bar extends Foo
6365+
def Doit(p: B): C
63426366
return C.new()
63436367
enddef
63446368
endclass
@@ -6362,12 +6386,12 @@ def Test_extended_obj_method_type_check()
63626386
endclass
63636387

63646388
class Bar extends Foo
6365-
def Doit(p: C): B
6389+
def Doit(p: A): B
63666390
return B.new()
63676391
enddef
63686392
endclass
63696393
END
6370-
v9.CheckSourceFailure(lines, 'E1383: Method "Doit": type mismatch, expected func(object<B>): object<B> but got func(object<C>): object<B>', 20)
6394+
v9.CheckSourceFailure(lines, 'E1383: Method "Doit": type mismatch, expected func(object<B>): object<B> but got func(object<A>): object<B>', 20)
63716395

63726396
lines =<< trim END
63736397
vim9script

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
1974,
707709
/**/
708710
1973,
709711
/**/

src/vim9class.c

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2561,7 +2561,7 @@ inside_class(cctx_T *cctx_arg, class_T *cl)
25612561
{
25622562
for (cctx_T *cctx = cctx_arg; cctx != NULL; cctx = cctx->ctx_outer)
25632563
if (cctx->ctx_ufunc != NULL
2564-
&& class_instance_of(cctx->ctx_ufunc->uf_class, cl, TRUE))
2564+
&& class_instance_of(cctx->ctx_ufunc->uf_class, cl))
25652565
return TRUE;
25662566
return FALSE;
25672567
}
@@ -2871,39 +2871,29 @@ member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len)
28712871
* interfaces matches the class "other_cl".
28722872
*/
28732873
int
2874-
class_instance_of(class_T *cl, class_T *other_cl, int covariance_check)
2874+
class_instance_of(class_T *cl, class_T *other_cl)
28752875
{
28762876
if (cl == other_cl)
28772877
return TRUE;
28782878

2879-
if (covariance_check)
2879+
// Recursively check the base classes.
2880+
for (; cl != NULL; cl = cl->class_extends)
28802881
{
2881-
// Recursively check the base classes.
2882-
for (; cl != NULL; cl = cl->class_extends)
2882+
if (cl == other_cl)
2883+
return TRUE;
2884+
// Check the implemented interfaces and the super interfaces
2885+
for (int i = cl->class_interface_count - 1; i >= 0; --i)
28832886
{
2884-
if (cl == other_cl)
2885-
return TRUE;
2886-
// Check the implemented interfaces and the super interfaces
2887-
for (int i = cl->class_interface_count - 1; i >= 0; --i)
2887+
class_T *intf = cl->class_interfaces_cl[i];
2888+
while (intf != NULL)
28882889
{
2889-
class_T *intf = cl->class_interfaces_cl[i];
2890-
while (intf != NULL)
2891-
{
2892-
if (intf == other_cl)
2893-
return TRUE;
2894-
// check the super interfaces
2895-
intf = intf->class_extends;
2896-
}
2890+
if (intf == other_cl)
2891+
return TRUE;
2892+
// check the super interfaces
2893+
intf = intf->class_extends;
28972894
}
28982895
}
28992896
}
2900-
else
2901-
{
2902-
// contra-variance
2903-
for (; other_cl != NULL; other_cl = other_cl->class_extends)
2904-
if (cl == other_cl)
2905-
return TRUE;
2906-
}
29072897

29082898
return FALSE;
29092899
}
@@ -2938,7 +2928,7 @@ f_instanceof(typval_T *argvars, typval_T *rettv)
29382928
}
29392929

29402930
if (class_instance_of(object_tv->vval.v_object->obj_class,
2941-
li->li_tv.vval.v_class, TRUE) == TRUE)
2931+
li->li_tv.vval.v_class) == TRUE)
29422932
{
29432933
rettv->vval.v_number = VVAL_TRUE;
29442934
return;
@@ -2947,9 +2937,8 @@ f_instanceof(typval_T *argvars, typval_T *rettv)
29472937
}
29482938
else if (classinfo_tv->v_type == VAR_CLASS)
29492939
{
2950-
rettv->vval.v_number = class_instance_of(
2951-
object_tv->vval.v_object->obj_class,
2952-
classinfo_tv->vval.v_class, TRUE);
2940+
rettv->vval.v_number = class_instance_of(object_tv->vval.v_object->obj_class,
2941+
classinfo_tv->vval.v_class);
29532942
}
29542943
}
29552944

src/vim9type.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -925,10 +925,14 @@ check_type_maybe(
925925
if (actual->tt_class == NULL)
926926
return OK; // A null object matches
927927

928-
// For object method arguments, do a contra-variance type check in
929-
// an extended class. For all others, do a co-variance type check.
930-
if (class_instance_of(actual->tt_class, expected->tt_class,
931-
where.wt_kind != WT_METHOD_ARG) == FALSE)
928+
// For object method arguments, do a invariant type check in
929+
// an extended class. For all others, do a covariance type check.
930+
if (where.wt_kind == WT_METHOD_ARG)
931+
{
932+
if (actual->tt_class != expected->tt_class)
933+
ret = FAIL;
934+
}
935+
else if (!class_instance_of(actual->tt_class, expected->tt_class))
932936
ret = FAIL;
933937
}
934938

0 commit comments

Comments
 (0)