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