diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 931354e6fe184..c916e0ad2cc95 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -4,6 +4,7 @@
c5ed3c1d-b572-46f1-8f96-522a85ce1179
System.Private.CoreLib.Strings
true
+
true
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorOnTypeBuilderInstantiation.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorOnTypeBuilderInstantiation.cs
index cc697cdc10a56..c4e80153cf1a3 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorOnTypeBuilderInstantiation.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorOnTypeBuilderInstantiation.cs
@@ -42,22 +42,7 @@ internal override Type[] GetParameterTypes()
public override object[] GetCustomAttributes(bool inherit) { return _ctor.GetCustomAttributes(inherit); }
public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _ctor.GetCustomAttributes(attributeType, inherit); }
public override bool IsDefined(Type attributeType, bool inherit) { return _ctor.IsDefined(attributeType, inherit); }
- public override int MetadataToken
- {
- get
- {
- ConstructorBuilder? cb = _ctor as ConstructorBuilder;
-
- if (cb != null)
- {
- return cb.MetadataToken;
- }
- else
- {
- return _ctor.MetadataToken;
- }
- }
- }
+ public override int MetadataToken => _ctor.MetadataToken;
public override Module Module => _ctor.Module;
#endregion
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldOnTypeBuilderInstantiation.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldOnTypeBuilderInstantiation.cs
index 1a9d8cc992169..006795ce3692e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldOnTypeBuilderInstantiation.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldOnTypeBuilderInstantiation.cs
@@ -49,22 +49,7 @@ internal FieldOnTypeBuilderInstantiation(FieldInfo field, TypeBuilderInstantiati
public override object[] GetCustomAttributes(bool inherit) { return _field.GetCustomAttributes(inherit); }
public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _field.GetCustomAttributes(attributeType, inherit); }
public override bool IsDefined(Type attributeType, bool inherit) { return _field.IsDefined(attributeType, inherit); }
- public override int MetadataToken
- {
- get
- {
- FieldBuilder? fb = _field as FieldBuilder;
-
- if (fb != null)
- {
- return fb.MetadataToken;
- }
- else
- {
- return _field.MetadataToken;
- }
- }
- }
+ public override int MetadataToken => _field.MetadataToken;
public override Module Module => _field.Module;
#endregion
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilderInstantiation.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilderInstantiation.cs
index eec5d2eb32550..6c0867dbe3158 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilderInstantiation.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilderInstantiation.cs
@@ -32,10 +32,12 @@ internal MethodBuilderInstantiation(MethodInfo method, Type[] inst)
}
#endregion
+#if SYSTEM_PRIVATE_CORELIB
internal override Type[] GetParameterTypes()
{
return _method.GetParameterTypes();
}
+#endif
#region MemberBase
public override MemberTypes MemberType => _method.MemberType;
@@ -82,6 +84,7 @@ public override bool ContainsGenericParameters
}
}
+ [RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override MethodInfo MakeGenericMethod(params Type[] arguments)
{
diff --git a/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx b/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
index c0f82bed38998..6572d94d71d67 100644
--- a/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
+++ b/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
@@ -225,4 +225,7 @@
Should not specify exception type for catch clause for filter block.
+
+ {0} is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.
+
\ No newline at end of file
diff --git a/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj b/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj
index 8580d8bacb8a6..ede82acce0a97 100644
--- a/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj
+++ b/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj
@@ -8,6 +8,7 @@
+
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs
index 0a06117c21e91..510cb8e680119 100644
--- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs
@@ -293,7 +293,7 @@ public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? bind
[RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
- public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
- => throw new NotImplementedException();
+ public override MethodInfo MakeGenericMethod(params Type[] typeArguments) =>
+ MethodBuilderInstantiation.MakeGenericMethod(this, typeArguments);
}
}
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs
index bcc533954e926..68d839986bd32 100644
--- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs
@@ -18,7 +18,7 @@ internal sealed class ModuleBuilderImpl : ModuleBuilder
private readonly AssemblyBuilderImpl _assemblyBuilder;
private readonly Dictionary _assemblyReferences = new();
private readonly Dictionary _typeReferences = new();
- private readonly Dictionary _memberReferences = new();
+ private readonly Dictionary _memberReferences = new();
private readonly List _typeDefinitions = new();
private readonly Dictionary _ctorReferences = new();
private Dictionary? _moduleReferences;
@@ -372,13 +372,26 @@ private EntityHandle GetTypeReferenceOrSpecificationHandle(Type type)
private TypeSpecificationHandle AddTypeSpecification(Type type) =>
_metadataBuilder.AddTypeSpecification(
- signature: _metadataBuilder.GetOrAddBlob(MetadataSignatureHelper.GetTypeSignature(type, this)));
+ signature: _metadataBuilder.GetOrAddBlob(MetadataSignatureHelper.GetTypeSpecificationSignature(type, this)));
- private MemberReferenceHandle GetMemberReference(MemberInfo member)
+ private MethodSpecificationHandle AddMethodSpecification(EntityHandle methodHandle, Type[] genericArgs) =>
+ _metadataBuilder.AddMethodSpecification(
+ method: methodHandle,
+ instantiation: _metadataBuilder.GetOrAddBlob(MetadataSignatureHelper.GetMethodSpecificationSignature(genericArgs, this)));
+
+ private EntityHandle GetMemberReference(MemberInfo member)
{
if (!_memberReferences.TryGetValue(member, out var memberHandle))
{
- memberHandle = AddMemberReference(member.Name, GetTypeReferenceOrSpecificationHandle(member.DeclaringType!), GetMemberSignature(member));
+ if (member is MethodInfo method && method.IsConstructedGenericMethod)
+ {
+ memberHandle = AddMethodSpecification(GetMemberReference(method.GetGenericMethodDefinition()), method.GetGenericArguments());
+ }
+ else
+ {
+ memberHandle = AddMemberReference(member.Name, GetTypeHandle(member.DeclaringType!), GetMemberSignature(member));
+ }
+
_memberReferences.Add(member, memberHandle);
}
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
index 4d0cea3ecac7a..c84052be93741 100644
--- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
@@ -56,12 +56,25 @@ internal static BlobBuilder ConstructorSignatureEncoder(ParameterInfo[]? paramet
return constructorSignature;
}
- internal static BlobBuilder GetTypeSignature(Type type, ModuleBuilderImpl module)
+ internal static BlobBuilder GetTypeSpecificationSignature(Type type, ModuleBuilderImpl module)
{
- BlobBuilder typeSignature = new();
- WriteSignatureForType(new BlobEncoder(typeSignature).TypeSpecificationSignature(), type, module);
+ BlobBuilder typeSpecSignature = new();
+ WriteSignatureForType(new BlobEncoder(typeSpecSignature).TypeSpecificationSignature(), type, module);
- return typeSignature;
+ return typeSpecSignature;
+ }
+
+ internal static BlobBuilder GetMethodSpecificationSignature(Type[] genericArguments, ModuleBuilderImpl module)
+ {
+ BlobBuilder methodSpecSignature = new();
+ GenericTypeArgumentsEncoder encoder = new BlobEncoder(methodSpecSignature).MethodSpecificationSignature(genericArguments.Length);
+
+ foreach (Type argument in genericArguments)
+ {
+ WriteSignatureForType(encoder.AddArgument(), argument, module);
+ }
+
+ return methodSpecSignature;
}
internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl module, Type[]? parameters,
diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs
index fccd631f7e311..a5d646811c76d 100644
--- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs
+++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs
@@ -653,9 +653,7 @@ void Main(int a)
}
}
-
-
- /*[Fact] // TODO: Resolve MethodBuilderInstantiation access
+ [Fact]
public void ReferenceConstructedGenericMethod()
{
using (TempFile file = TempFile.Create())
@@ -672,7 +670,6 @@ public void ReferenceConstructedGenericMethod()
ilg.Emit(OpCodes.Ret);
MethodBuilder mainMethod = type.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static);
ilg = mainMethod.GetILGenerator();
- //MethodInfo SampleOfGM = TypeBuilder.GetMethod(type, genericMethod);
MethodInfo GMOfString = genericMethod.MakeGenericMethod(typeof(string));
ilg.Emit(OpCodes.Ldstr, "Hello, world!");
ilg.EmitCall(OpCodes.Call, GMOfString, null);
@@ -681,11 +678,16 @@ public void ReferenceConstructedGenericMethod()
saveMethod.Invoke(ab, new[] { file.Path });
Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path);
- Type myTypeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
- Assert.True(myTypeFromDisk.IsGenericType);
- Assert.True(myTypeFromDisk.IsGenericTypeDefinition);
+ Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
+ MethodInfo genericMethodFromDisk = typeFromDisk.GetMethod("GM");
+ Assert.True(genericMethodFromDisk.IsGenericMethod);
+ Assert.True(genericMethodFromDisk.IsGenericMethodDefinition);
+ byte[] ilBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray();
+ Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]);
+ Assert.Equal(OpCodes.Call.Value, ilBytes[5]);
+ Assert.Equal(OpCodes.Ret.Value, ilBytes[10]);
}
- }*/
+ }
[Fact]
public void ReferenceConstructedGenericMethodFieldOfConstructedType()
@@ -727,7 +729,7 @@ public void ReferenceConstructedGenericMethodFieldOfConstructedType()
ilg.EmitCall(OpCodes.Call, GMOfString, null);
ilg.Emit(OpCodes.Ret);
dummy.CreateType();
-/* TODO: verify 'MyType.GM("HelloWorld");' emitted correctly after 'MethodBuilderImpl.GetParameters()' implemented
+/* Generated IL would like this in C#:
public class MyType
{
public T Field;
@@ -744,15 +746,37 @@ internal class Dummy
{
public static void Main()
{
- MyType.GM("HelloWorld");
+ MyType.GM("HelloWorld");
}
} */
saveMethod.Invoke(ab, new[] { file.Path });
- Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path);
- Type myTypeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
+ Module module = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First();
+ Type myTypeFromDisk = module.GetType("MyType");
Assert.True(myTypeFromDisk.IsGenericType);
Assert.True(myTypeFromDisk.IsGenericTypeDefinition);
+ Assert.Equal("T", myTypeFromDisk.GetGenericArguments()[0].Name);
+ Assert.Equal("T", myTypeFromDisk.GetField("Field").FieldType.Name);
+ MethodInfo genericMethodFromDisk = myTypeFromDisk.GetMethod("GM");
+ Assert.True(genericMethodFromDisk.IsGenericMethod);
+ Assert.True(genericMethodFromDisk.IsGenericMethodDefinition);
+ Assert.Equal(1, genericMethodFromDisk.GetMethodBody().LocalVariables.Count);
+ Assert.Equal("MyType[U]", genericMethodFromDisk.GetMethodBody().LocalVariables[0].LocalType.ToString());
+ byte[] gmIlBytes = genericMethodFromDisk.GetMethodBody().GetILAsByteArray();
+ Assert.Equal(OpCodes.Newobj.Value, gmIlBytes[0]);
+ Assert.Equal(OpCodes.Stloc_0.Value, gmIlBytes[5]);
+ Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[6]);
+ Assert.Equal(OpCodes.Ldarg_0.Value, gmIlBytes[7]);
+ Assert.Equal(OpCodes.Stfld.Value, gmIlBytes[8]);
+ Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[13]);
+ Assert.Equal(OpCodes.Ldfld.Value, gmIlBytes[14]);
+ Assert.Equal(OpCodes.Box.Value, gmIlBytes[19]);
+ Assert.Equal(OpCodes.Call.Value, gmIlBytes[24]);
+ Assert.Equal(OpCodes.Ret.Value, gmIlBytes[29]);
+ byte[] ilBytes = module.GetType("Dummy").GetMethod("Main").GetMethodBody().GetILAsByteArray();
+ Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]);
+ Assert.Equal(OpCodes.Call.Value, ilBytes[5]);
+ Assert.Equal(OpCodes.Ret.Value, ilBytes[10]);
}
}
diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs
index 65c9f005b754a..6f92cc3a6e855 100644
--- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs
+++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs
@@ -137,8 +137,6 @@ internal static void AssertMethods(MethodInfo[] sourceMethods, MethodInfo[] meth
{
MethodInfo sourceMethod = sourceMethods[j];
MethodInfo methodFromDisk = methodsFromDisk[j];
- if (methodFromDisk.Name == ".ctor")
- continue;
Assert.Equal(sourceMethod.Name, methodFromDisk.Name);
Assert.Equal(sourceMethod.Attributes, methodFromDisk.Attributes);