[metadata] expand uninstantiated generic type definitions used as generic type args
Assert.AreSame (expectedType, r, "#2");
}
+ public class BConstrained<Y> where Y : BConstrained<Y> {
+ }
+
+ public class AConstrained<X> : BConstrained<AConstrained<X>> {
+ }
+
+ [Test] // Bug https://bugzilla.xamarin.com/show_bug.cgi?id=54485
+ public void MakeGenericType_GTD_Constraint ()
+ {
+ // This is pretty weird, but match .NET behavior (note
+ // that typeof(BConstrained<AConstrained<>>) is a
+ // compile-time error with roslyn, but it's apparently
+ // an ok thing to make with reflection.
+ var tb = typeof (BConstrained<>);
+ var ta = typeof (AConstrained<>);
+ var result = tb.MakeGenericType (ta);
+ Assert.IsNotNull (result, "#1");
+ // lock down the answer to match what .NET makes
+ Assert.IsTrue (result.IsGenericType, "#2");
+ Assert.AreEqual (tb, result.GetGenericTypeDefinition (), "#3");
+ var bargs = result.GetGenericArguments ();
+ Assert.AreEqual (1, bargs.Length, "#4");
+ var arg = bargs [0];
+ Assert.IsTrue (arg.IsGenericType, "#5");
+ // N.B. evidently AConstrained`1 and AConstrained`1<!0> are the same type
+ Assert.IsTrue (arg.IsGenericTypeDefinition, "#6");
+ Assert.AreEqual (ta, arg.GetGenericTypeDefinition (), "#7");
+ var aargs = arg.GetGenericArguments ();
+ Assert.AreEqual (1, aargs.Length, "#8");
+ Assert.AreEqual (ta.GetGenericArguments () [0], aargs [0], "#9");
+ }
+
[Test]
public void EqualsUserType () {
UserType2 t1 = new UserType2(null);
mono_loader_unlock ();
#endif
}
+
+MonoType*
+mono_class_gtd_get_canonical_inst (MonoClass *klass)
+{
+ g_assert (mono_class_is_gtd (klass));
+ return &((MonoClassGtd*)klass)->canonical_inst;
+}
typedef struct {
MonoClassDef class;
MonoGenericContainer *generic_container;
+ /* The canonical GENERICINST where we instantiate a generic type definition with its own generic parameters.*/
+ /* Suppose we have class T`2<A,B> {...}. canonical_inst is the GTD T`2 applied to A and B. */
+ MonoType canonical_inst;
} MonoClassGtd;
typedef struct {
void
mono_class_set_generic_container (MonoClass *klass, MonoGenericContainer *container);
+MonoType*
+mono_class_gtd_get_canonical_inst (MonoClass *klass);
+
guint32
mono_class_get_first_method_idx (MonoClass *klass);
generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
context = &generic_container->context;
mono_class_set_generic_container (klass, generic_container);
+ MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
+ canonical_inst->type = MONO_TYPE_GENERICINST;
+ canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
enable_gclass_recording ();
}
return set;
}
+static gboolean
+type_is_gtd (MonoType *type)
+{
+ switch (type->type) {
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_VALUETYPE:
+ return mono_class_is_gtd (type->data.klass);
+ default:
+ return FALSE;
+ }
+}
+
/*
* mono_metadata_get_generic_inst:
*
ginst->type_argc = type_argc;
memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
+ for (i = 0; i < type_argc; ++i) {
+ MonoType *t = ginst->type_argv [i];
+ if (type_is_gtd (t)) {
+ ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
+ }
+ }
+
return mono_metadata_get_canonical_generic_inst (ginst);
}
}
generic_container->context.class_inst = mono_get_shared_generic_inst (generic_container);
+ MonoGenericContext* context = &generic_container->context;
+ MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
+ canonical_inst->type = MONO_TYPE_GENERICINST;
+ canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
+
leave:
HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
}