diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs index e619c24ca112d..3114e42d55ec6 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs @@ -18,10 +18,10 @@ internal sealed class ArrayMethod : MethodInfo #region Constructor // This is a kind of MethodInfo to represent methods for array type of unbaked type - internal ArrayMethod(ModuleBuilder module, Type arrayClass, string methodName, + internal ArrayMethod(ModuleBuilderImpl module, Type arrayClass, string methodName, CallingConventions callingConvention, Type? returnType, Type[]? parameterTypes) { - _returnType = returnType ?? typeof(void); + _returnType = returnType ?? module.GetTypeFromCoreAssembly(CoreTypeId.Void); if (parameterTypes != null) { _parameterTypes = new Type[parameterTypes.Length]; diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs index 69cc149d30d5b..c4480d7cee553 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs @@ -439,6 +439,7 @@ protected override FieldBuilder DefineUninitializedDataCore(string name, int siz return DefineDataHelper(name, new byte[size], size, attributes); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:DynamicallyAccessedMembers", Justification = "The members of 'ValueType' are not referenced in this context")] private FieldBuilder DefineDataHelper(string name, byte[] data, int size, FieldAttributes attributes) { ArgumentException.ThrowIfNullOrEmpty(name); @@ -456,7 +457,7 @@ private FieldBuilder DefineDataHelper(string name, byte[] data, int size, FieldA TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.ExplicitLayout | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass; // Define the backing value class - valueClassType = (TypeBuilderImpl)_module.DefineType(strValueClassName, typeAttributes, typeof(ValueType), PackingSize.Size1, size); + valueClassType = (TypeBuilderImpl)_module.DefineType(strValueClassName, typeAttributes, _module.GetTypeFromCoreAssembly(CoreTypeId.ValueType), PackingSize.Size1, size); valueClassType.CreateType(); } diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs index 29a94bacd15d8..3c569b815da63 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs @@ -67,6 +67,7 @@ public void DefineLiteral(Type underlyingType, object literalValue) EnumBuilder enumBuilder = CreateAssemblyAndDefineEnum(out PersistedAssemblyBuilder assemblyBuilder, out TypeBuilder type, underlyingType); FieldBuilder literal = enumBuilder.DefineLiteral("FieldOne", literalValue); enumBuilder.CreateTypeInfo(); + Assert.True(enumBuilder.IsEnum); type.CreateTypeInfo(); assemblyBuilder.Save(file.Path); @@ -79,15 +80,49 @@ public void DefineLiteral(Type underlyingType, object literalValue) Assert.True(testEnum.IsEnum); AssemblySaveTools.AssertTypeProperties(enumBuilder, testEnum); Assert.Equal(underlyingType.FullName, testEnum.GetEnumUnderlyingType().FullName); + Assert.Equal(mlc.CoreAssembly.GetType("System.Enum"), testEnum.BaseType); FieldInfo testField = testEnum.GetField("FieldOne"); Assert.Equal(enumBuilder.Name, testField.DeclaringType.Name); Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault, literal.Attributes); Assert.Equal(enumBuilder.AsType().FullName, testField.FieldType.FullName); + Assert.Equal(testEnum, testField.FieldType); } } } + [Fact] + public void CreateEnumWithMlc() + { + using (var stream = new MemoryStream()) + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(PopulateAssemblyName(), mlc.CoreAssembly); + ModuleBuilder mb = ab.DefineDynamicModule("My Module"); + Type intType = mlc.CoreAssembly.GetType("System.Int32"); + EnumBuilder enumBuilder = mb.DefineEnum("TestEnum", TypeAttributes.Public, typeof(int)); + FieldBuilder field = enumBuilder.DefineLiteral("Default", 0); + + enumBuilder.CreateTypeInfo(); + Assert.True(enumBuilder.IsEnum); + Assert.Equal(enumBuilder, field.FieldType); + + ab.Save(stream); + Assembly assemblyFromStream = mlc.LoadFromStream(stream); + Type createdEnum = assemblyFromStream.GetType("TestEnum"); + + Assert.True(createdEnum.IsEnum); + AssemblySaveTools.AssertTypeProperties(enumBuilder, createdEnum); + Assert.Equal(mlc.CoreAssembly.GetType("System.Enum"), createdEnum.BaseType); + Assert.Equal(intType, createdEnum.GetEnumUnderlyingType()); + + FieldInfo testField = createdEnum.GetField("Default"); + Assert.Equal(createdEnum, testField.FieldType); + Assert.Equal(typeof(int), enumBuilder.GetEnumUnderlyingType()); + Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault, testField.Attributes); + } + } + [Theory] [InlineData(0, "TestEnum[]")] [InlineData(1, "TestEnum[]")] diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs index 959ea0022d5ce..0c8a7a2aae81c 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs @@ -127,6 +127,25 @@ public void DefineUninitializedDataTest(FieldAttributes attributes) Assert.True(field.IsStatic); Assert.True((field.Attributes & FieldAttributes.HasFieldRVA) != 0); Assert.Equal(attributes | FieldAttributes.Static | FieldAttributes.HasFieldRVA, field.Attributes); + Assert.Equal(typeof(ValueType), field.FieldType.BaseType); + } + } + + [Fact] + public void DefineUninitializedDataFromMLC() + { + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), mlc.CoreAssembly); + ModuleBuilder module = ab.DefineDynamicModule("MyModule"); + FieldBuilder field = module.DefineUninitializedData("UninitializedDataField", 100, FieldAttributes.Public); + + Assert.Equal("UninitializedDataField", field.Name); + Assert.True(field.IsStatic); + Assert.True((field.Attributes & FieldAttributes.HasFieldRVA) != 0); + Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.HasFieldRVA, field.Attributes); + Assert.NotEqual(typeof(ValueType), field.FieldType.BaseType); + Assert.Equal(mlc.CoreAssembly.GetType("System.ValueType"), field.FieldType.BaseType); } } @@ -354,5 +373,34 @@ public void GetArrayMethod_InvalidArgument_ThrowsArgumentException() AssertExtensions.Throws("parameterTypes", () => module.GetArrayMethod(typeof(string[]), "TestMethod", CallingConventions.Standard, null, [null])); AssertExtensions.Throws(null, () => module.GetArrayMethod(typeof(Array), "TestMethod", CallingConventions.Standard, null, null)); } + + [Fact] + public void GetArrayMethodNullReturnType() + { + ModuleBuilder module = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")).DefineDynamicModule("MyModule"); + MethodInfo method = module.GetArrayMethod(typeof(int[]), "MethodName", CallingConventions.Standard, null, null); + + Assert.Equal(typeof(int[]), method.DeclaringType); + Assert.Equal("MethodName", method.Name); + Assert.Equal(CallingConventions.Standard, method.CallingConvention); + Assert.Equal(typeof(void), method.ReturnType); + } + + [Fact] + public void GetArrayMethodNullReturnTypeFromMLC() + { + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + ModuleBuilder module = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), mlc.CoreAssembly).DefineDynamicModule("MyModule"); + Type arrayType = mlc.CoreAssembly.GetType("System.Int32").MakeArrayType(); + MethodInfo method = module.GetArrayMethod(arrayType, "MethodName", CallingConventions.Standard, null, null); + + Assert.Equal(arrayType, method.DeclaringType); + Assert.Equal("MethodName", method.Name); + Assert.Equal(CallingConventions.Standard, method.CallingConvention); + Assert.NotEqual(typeof(void), method.ReturnType); + Assert.Equal(mlc.CoreAssembly.GetType("System.Void"), method.ReturnType); + } + } } }