From: Aleksey Kliger Date: Fri, 22 Sep 2017 14:30:44 +0000 (-0400) Subject: [class] Use constraints of gparam T2 in T1.IsAssignableFrom (T2) X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=fa62f916a3c02931eb6d5f72e07b9aa37b477171 [class] Use constraints of gparam T2 in T1.IsAssignableFrom (T2) Suppose we want to know C.IsAssignableFrom (T1): ``` class C { } class G where T1 : T2, T2 : C { } ``` Previously, we would get `False`, because we only checked the constraints of T1 if C was an interface or another gparam. Now Instead we always consider the constraints in `A.IsAssignableFrom (B)` whenever `B` is a gparam. Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=58809 --- diff --git a/mono/metadata/class.c b/mono/metadata/class.c index f3e87fe6428..e1539de106c 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -8226,22 +8226,31 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) return mono_gparam_is_assignable_from (klass, oklass); } - if (MONO_CLASS_IS_INTERFACE (klass)) { - if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) { - MonoGenericParam *gparam = oklass->byval_arg.data.generic_param; - MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints; - int i; + /* This can happen if oklass is a tyvar that has a constraint which is another tyvar which in turn + * has a constraint which is a class type: + * + * class Foo { } + * class G where T1 : T2 where T2 : Foo { } + * + * In this case, Foo is assignable from T1. + */ + if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) { + MonoGenericParam *gparam = oklass->byval_arg.data.generic_param; + MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints; + int i; - if (constraints) { - for (i = 0; constraints [i]; ++i) { - if (mono_class_is_assignable_from (klass, constraints [i])) - return TRUE; - } + if (constraints) { + for (i = 0; constraints [i]; ++i) { + if (mono_class_is_assignable_from (klass, constraints [i])) + return TRUE; } - - return FALSE; } + return mono_class_has_parent (oklass, klass); + } + + if (MONO_CLASS_IS_INTERFACE (klass)) { + /* interface_offsets might not be set for dynamic classes */ if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) { /*