Annotate CreateInstanceForAnotherGenericParameter as PublicParameterlessConstructor...
authorEric Erhardt <eric.erhardt@microsoft.com>
Tue, 30 Mar 2021 02:12:29 +0000 (21:12 -0500)
committerGitHub <noreply@github.com>
Tue, 30 Mar 2021 02:12:29 +0000 (19:12 -0700)
This allows private constructors on the Types to be trimmed.

Fix #50353

src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs
src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs

index f5eb863..6e99db3 100644 (file)
@@ -209,8 +209,13 @@ namespace System
             return outHandles;
         }
 
-        internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] RuntimeType type, RuntimeType genericParameter)
+        internal static object CreateInstanceForAnotherGenericParameter(
+            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
+            RuntimeType genericParameter)
         {
+            Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic,
+                $"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.");
+
             object? instantiatedObject = null;
 
             IntPtr typeHandle = genericParameter.GetTypeHandleInternal().Value;
@@ -224,8 +229,14 @@ namespace System
             return instantiatedObject!;
         }
 
-        internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] RuntimeType type, RuntimeType genericParameter1, RuntimeType genericParameter2)
+        internal static object CreateInstanceForAnotherGenericParameter(
+            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
+            RuntimeType genericParameter1,
+            RuntimeType genericParameter2)
         {
+            Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic,
+                $"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.");
+
             object? instantiatedObject = null;
 
             IntPtr* pTypeHandles = stackalloc IntPtr[]
index c21928a..cdfc29a 100644 (file)
@@ -120,7 +120,7 @@ namespace System.Collections.Generic
     [Serializable]
     internal sealed partial class EnumComparer<T> : Comparer<T>, ISerializable where T : struct, Enum
     {
-        internal EnumComparer() { }
+        public EnumComparer() { }
 
         // Used by the serialization engine.
         private EnumComparer(SerializationInfo info, StreamingContext context) { }
index 0af18e7..e7f23a8 100644 (file)
@@ -180,7 +180,7 @@ namespace System.Collections.Generic
     // Needs to be public to support binary serialization compatibility
     public sealed partial class EnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct, Enum
     {
-        internal EnumEqualityComparer() { }
+        public EnumEqualityComparer() { }
 
         // This is used by the serialization engine.
         private EnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
index 7e54e26..f58b2d5 100644 (file)
@@ -1835,11 +1835,15 @@ namespace System
             return constraints ?? Type.EmptyTypes;
         }
 
-        internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type genericType, RuntimeType genericArgument)
+        internal static object CreateInstanceForAnotherGenericParameter(
+            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type genericType,
+            RuntimeType genericArgument)
         {
             var gt = (RuntimeType)MakeGenericType(genericType, new Type[] { genericArgument });
             RuntimeConstructorInfo? ctor = gt.GetDefaultConstructor();
-            if (ctor is null)
+
+            // CreateInstanceForAnotherGenericParameter requires type to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.
+            if (ctor is null || !ctor.IsPublic)
                 throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, gt));
 
             return ctor.InternalInvoke(null, null, wrapExceptions: true)!;