Thanks. Can't believe I didn't see that ;)
Index: mono/metadata/class.c
===================================================================
--- mono/metadata/class.c	(revision 126432)
+++ mono/metadata/class.c	(working copy)
@@ -67,6 +67,7 @@
 static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
 
 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
+static gboolean mono_class_has_variant_generic_params (MonoClass *klass);
 
 void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
 void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
@@ -2101,6 +2102,36 @@
 	return (key->interface_id - element->interface_id);
 }
 
+static gboolean
+mono_class_is_variant_of (MonoClass *klass, MonoClass *vklass) {
+	int i;
+	MonoClass *generic = klass->generic_class->container_class;
+	MonoClass *vgeneric = vklass->generic_class->container_class;
+	MonoGenericContainer *container = vgeneric->generic_container;
+
+	if (generic != vgeneric)
+		return FALSE;
+
+	for (i = 0; i < container->type_argc; i++) {
+		MonoClass *param_class = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [i]);
+		MonoClass *vparam_class = mono_class_from_mono_type (vklass->generic_class->context.class_inst->type_argv [i]);
+
+		// FIXME this is incorrect
+		if (param_class->valuetype || vparam_class->valuetype)
+			return FALSE;
+
+		if (container->type_params [i].flags & GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK) {
+			if ((container->type_params [i].flags & GENERIC_PARAMETER_ATTRIBUTE_CONTRAVARIANT) && !mono_class_is_assignable_from (param_class, vparam_class))
+				return FALSE;
+			if ((container->type_params [i].flags & GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) && !mono_class_is_assignable_from (vparam_class, param_class))
+				return FALSE;
+		} else if (param_class != vparam_class)
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
 int
 mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
 	MonoClass **result = bsearch (
@@ -2116,6 +2147,21 @@
 	}
 }
 
+int
+mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf) {
+	int i = mono_class_interface_offset (klass, itf);
+	if (i >= 0) {
+		return i;
+	} else if (mono_class_has_variant_generic_params (itf)) {
+		for (i = 0; i < klass->interface_offsets_count; i++) {
+			if (mono_class_is_variant_of (klass->interfaces_packed[i], itf)) {
+				return klass->interface_offsets_packed [i];
+			}
+		}
+	}
+	return -1;
+}
+
 static void
 print_implemented_interfaces (MonoClass *klass) {
 	GPtrArray *ifaces = NULL;
@@ -5935,38 +5981,8 @@
 					if ((container_class2->interfaces_packed [i] == container_class1) || (container_class2->interfaces_packed [i]->generic_class && (container_class2->interfaces_packed [i]->generic_class->container_class == container_class1)))
 						match = TRUE;
 
-				if (match) {
-					MonoGenericContainer *container;
-
-					container = klass->generic_class->container_class->generic_container;
-
-					match = TRUE;
-					for (i = 0; i < container->type_argc; ++i) {
-						MonoClass *param1_class = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [i]);
-						MonoClass *param2_class = mono_class_from_mono_type (oklass->generic_class->context.class_inst->type_argv [i]);
-
-						if (param1_class->valuetype != param2_class->valuetype) {
-							match = FALSE;
-							break;
-						}
-						/*
-						 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
-						 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
-						 */
-						if (param1_class != param2_class) {
-							if ((container->type_params [i].flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
-								;
-							else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
-								;
-							else {
-								match = FALSE;
-								break;
-							}
-						}
-					}
-
-					if (match)
-						return TRUE;
+				if (match && mono_class_is_variant_of (oklass, klass)) {
+					return TRUE;
 				}
 			}
 		}
Index: mono/metadata/ChangeLog
===================================================================
--- mono/metadata/ChangeLog	(revision 126432)
+++ mono/metadata/ChangeLog	(working copy)
@@ -1,3 +1,17 @@
+2009-02-10  Scott Peterson  <[email protected]>
+
+	This adds runtime generic variance support for reference types.
+	This patch is contributed under the MIT/X11 license.
+
+	* class.c: Added mono_class_has_variant_generic_params which determins
+	if a generic class has a variant type parameter. Added
+	mono_class_is_variant_of which determins if the first class is a legal
+	variant of the second. Added mono_class_interface_offset_with_variance
+	to look for interfaces in a variance-aware fashion. Modified
+	mono_class_is_assignable_from to use the two new methods.
+
+	* class-internals.h: Added mono_class_interface_offset_with_variance.
+
 2009-02-09  Geoff Norton  <[email protected]>
 
 	* appdomain.h:
Index: mono/metadata/class-internals.h
===================================================================
--- mono/metadata/class-internals.h	(revision 126432)
+++ mono/metadata/class-internals.h	(working copy)
@@ -407,6 +407,7 @@
 
 #define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= (k)->max_interface_id) && ((k)->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
 int mono_class_interface_offset (MonoClass *klass, MonoClass *itf);
+int mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf) MONO_INTERNAL;
 
 typedef gpointer MonoRuntimeGenericContext;
 
Index: mono/mini/ChangeLog
===================================================================
--- mono/mini/ChangeLog	(revision 126432)
+++ mono/mini/ChangeLog	(working copy)
@@ -1,3 +1,13 @@
+2009-02-10  Scott Peterson  <[email protected]>
+
+	Contributed under the MIT/X11 license.
+
+	* mini-trampolines.cs: Use the
+	new mono_class_interface_offset_with_variance method to find interface
+	offsets.
+
+	* generics-variant-types.cs: Added C# variance test.
+
 2009-02-10  Zoltan Varga  <[email protected]>
 
 	* mini-arm.c (mono_arch_output_basic_block): Disable AOT for OP_JMP.
Index: mono/mini/Makefile.am
===================================================================
--- mono/mini/Makefile.am	(revision 126432)
+++ mono/mini/Makefile.am	(working copy)
@@ -285,6 +285,7 @@
 	test.cs			\
 	generics.cs		\
 	generics-variant-types.il\
+	generics-variant-types.cs\
 	basic-simd.cs
 
 if MONO_DEBUGGER_SUPPORTED
Index: mono/mini/mini-trampolines.c
===================================================================
--- mono/mini/mini-trampolines.c	(revision 126432)
+++ mono/mini/mini-trampolines.c	(working copy)
@@ -60,7 +60,7 @@
 		int interface_offset;
 		int imt_slot = MONO_IMT_SIZE + displacement;
 
-		interface_offset = mono_class_interface_offset (vt->klass, imt_method->klass);
+		interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass);
 
 		if (interface_offset < 0) {
 			g_print ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, 0), mono_type_get_name_full (&imt_method->klass->byval_arg, 0));
_______________________________________________
Mono-devel-list mailing list
[email protected]
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to