interface IFoo {
}
+
+ [Test]
+ public void GenericFieldInCreatedType () {
+ /*
+ * Regression test for #47867.
+ * We construct the following, but only call CreateType on R.
+ *
+ * public class S<T> {
+ * public T t;
+ * }
+ * public class R {
+ * public static S<R> sr;
+ * }
+ */
+ var aname = new AssemblyName ("example1");
+ var ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
+ var mb = ab.DefineDynamicModule (aname.Name);
+ var tbS = mb.DefineType ("S", TypeAttributes.Public);
+ tbS.DefineGenericParameters (new String [] { "T" });
+ var tbR = mb.DefineType ("R", TypeAttributes.Public);
+ tbR.DefineField ("sr", tbS.MakeGenericType(new Type[] { tbR }), FieldAttributes.Public | FieldAttributes.Static);
+
+ Type r = tbR.CreateType ();
+
+ Assert.IsNotNull (r);
+ }
+
+ [Test]
+ public void GenericFieldInCreatedTypeIncompleteTypeTLE () {
+ /*
+ * Regression test for #47867.
+ * We construct the following, but only call CreateType on R.
+ * Then we try to use R.sr which is expected throw a
+ * TLE because S hasn't been created yet.
+ *
+ * public class S<T> {
+ * public T t;
+ * }
+ * public class R {
+ * public static S<R> sr;
+ * }
+ */
+ var aname = new AssemblyName ("example1");
+ var ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
+ var mb = ab.DefineDynamicModule (aname.Name);
+ var tbS = mb.DefineType ("S", TypeAttributes.Public);
+ tbS.DefineGenericParameters (new String [] { "T" });
+ var tbR = mb.DefineType ("R", TypeAttributes.Public);
+ tbR.DefineField ("sr", tbS.MakeGenericType(new Type[] { tbR }), FieldAttributes.Public | FieldAttributes.Static);
+
+ Type r = tbR.CreateType ();
+
+ Assert.IsNotNull (r);
+
+ // N.B. tbS has not had CreateType called yet, so expect this to fail.
+ Assert.Throws<TypeLoadException> (delegate { var ft = r.GetField("sr").FieldType; });
+ }
+
}
}
return res;
}
- /* This MonoGenericClass hack is no longer necessary. Let's leave it here until we finish with the 2-stage type-builder setup.*/
- if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !type->data.generic_class->container_class->wastypebuilder)
- g_assert (0);
+ if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !type->data.generic_class->container_class->wastypebuilder) {
+ /* This can happen if a TypeBuilder for a generic class K<T,U>
+ * had reflection_create_generic_class) called on it, but not
+ * ves_icall_TypeBuilder_create_runtime_class. This can happen
+ * if the K`2 is refernced from a generic instantiation
+ * (e.g. K<int,string>) that appears as type argument
+ * (e.g. Dict<string,K<int,string>>), field (e.g. K<int,string>
+ * Foo) or method signature, parent class or any of the above
+ * in a nested class of some other TypeBuilder. Such an
+ * occurrence caused mono_reflection_type_get_handle to be
+ * called on the sre generic instance (K<int,string>) which
+ * required the container_class for the generic class K`2 to be
+ * set up, but the remainder of class construction for K`2 has
+ * not been done. */
+ char * full_name = mono_type_get_full_name (klass);
+ /* I would have expected ReflectionTypeLoadException, but evidently .NET throws TLE in this case. */
+ mono_error_set_type_load_class (error, klass, "TypeBuilder.CreateType() not called for generic class %s", full_name);
+ g_free (full_name);
+ mono_domain_unlock (domain);
+ mono_loader_unlock ();
+ return NULL;
+ }
if (mono_class_get_ref_info (klass) && !klass->wastypebuilder && !type->byref) {
mono_domain_unlock (domain);
if (mono_is_sre_type_builder (mono_object_class (type))) {
is_dynamic = TRUE;
} else if (mono_is_sre_generic_instance (mono_object_class (type))) {
+ /* Does this ever make sense? what does instantiating a generic instance even mean? */
+ g_assert_not_reached ();
MonoReflectionGenericClass *rgi = (MonoReflectionGenericClass *) type;
MonoReflectionType *gtd = rgi->generic_type;
static gboolean ensure_runtime_vtable (MonoClass *klass, MonoError *error);
static void reflection_methodbuilder_from_dynamic_method (ReflectionMethodBuilder *rmb, MonoReflectionDynamicMethod *mb);
static gboolean reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error);
+static gboolean reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error);
+
static gpointer register_assembly (MonoDomain *domain, MonoReflectionAssembly *res, MonoAssembly *assembly);
#endif
return NULL;
}
}
-
+ /* Need to resolve the generic_type in order for it to create its generic context. */
+ MonoType *gtd = mono_reflection_type_get_handle (gclass->generic_type, error);
+ if (!is_ok (error)) {
+ g_free (types);
+ return NULL;
+ }
+ MonoClass *gtd_klass = mono_class_from_mono_type (gtd);
+ if (is_sre_type_builder (mono_object_class (gclass->generic_type))) {
+ reflection_create_generic_class ((MonoReflectionTypeBuilder*)gclass->generic_type, error);
+ if (!is_ok (error)) {
+ g_free (types);
+ return NULL;
+ }
+ }
+ g_assert (count == 0 || mono_class_is_gtd (gtd_klass));
res = mono_reflection_bind_generic_parameters (gclass->generic_type, count, types, error);
g_free (types);
g_assert (res);
mono_error_init (error);
reflection_setup_internal_class (tb, error);
+ return_val_if_nok (error, FALSE);
klass = mono_class_from_mono_type (tb->type.type);
if (count == 0)
return TRUE;
+ if (mono_class_try_get_generic_container (klass) != NULL)
+ return TRUE; /* already setup */
+
MonoGenericContainer *generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
generic_container->owner.klass = klass;