Skip to content

Commit

Permalink
Make Enum.GetValues AOT-safe
Browse files Browse the repository at this point in the history
...at the cost of a small compat break. We return `int[]` instead of `SomeInt32Enum[]`.

Fixes dotnet#72140.

We can also delete intrinsic handling of `Enum.GetValues` in dataflow analysis but I don't want to conflict with Vitek's dotnet#71485.
  • Loading branch information
MichalStrehovsky committed Jul 15, 2022
1 parent 81a3dcd commit 031eef9
Show file tree
Hide file tree
Showing 6 changed files with 3 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,14 @@ public sealed override bool IsEnumDefined(object value)
}
}

[RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload instead.")]
public sealed override Array GetEnumValues()
{
if (!IsActualEnum)
throw new ArgumentException(SR.Arg_MustBeEnum, "enumType");

Array values = Enum.GetEnumInfo(this).ValuesAsUnderlyingType;
int count = values.Length;
// Without universal shared generics, chances are slim that we'll have the appropriate
// array type available. Offer an escape hatch that avoids a MissingMetadataException
// at the cost of a small appcompat risk.
Array result;
if (AppContext.TryGetSwitch("Switch.System.Enum.RelaxedGetValues", out bool isRelaxed) && isRelaxed)
result = Array.CreateInstance(Enum.InternalGetUnderlyingType(this), count);
else
result = Array.CreateInstance(this, count);
Array.Copy(values, result, values.Length);
return result;
// Compat: we should be returning SomeInt32Enum[]. Instead we return Int32[].
// This is a tradeoff since SomeInt32Enum[] type might not have been pregenerated.
return (Array)Enum.GetEnumInfo(this).ValuesAsUnderlyingType.Clone();
}

internal bool IsActualEnum
Expand Down
1 change: 0 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/Enum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ public static TEnum[] GetValues<TEnum>() where TEnum : struct, Enum =>
(TEnum[])GetValues(typeof(TEnum));
#endif

[RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload instead.")]
public static Array GetValues(Type enumType)
{
ArgumentNullException.ThrowIfNull(enumType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ public sealed override Type MakeArrayType(int rank)
public sealed override string GetEnumName(object value) => throw new NotSupportedException(SR.NotSupported_SignatureType);
public sealed override string[] GetEnumNames() => throw new NotSupportedException(SR.NotSupported_SignatureType);
public sealed override Type GetEnumUnderlyingType() => throw new NotSupportedException(SR.NotSupported_SignatureType);
[RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues<TEnum> instead.")]
public sealed override Array GetEnumValues() => throw new NotSupportedException(SR.NotSupported_SignatureType);
public sealed override Guid GUID => throw new NotSupportedException(SR.NotSupported_SignatureType);
protected sealed override TypeCode GetTypeCodeImpl() => throw new NotSupportedException(SR.NotSupported_SignatureType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ public override string[] GetEnumNames()
return new ReadOnlySpan<string>(ret).ToArray();
}

[RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload instead.")]
public override Array GetEnumValues()
{
if (!IsActualEnum)
Expand Down
1 change: 0 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,6 @@ public virtual Type GetEnumUnderlyingType()
return fields[0].FieldType;
}

[RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues<TEnum> instead.")]
public virtual Array GetEnumValues()
{
if (!IsEnum)
Expand Down
2 changes: 0 additions & 2 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2312,7 +2312,6 @@ protected Enum() { }
public static string[] GetNames<TEnum>() where TEnum: struct, System.Enum { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
public static System.Type GetUnderlyingType(System.Type enumType) { throw null; }
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload instead.")]
public static System.Array GetValues(System.Type enumType) { throw null; }
public static TEnum[] GetValues<TEnum>() where TEnum : struct, System.Enum { throw null; }
public bool HasFlag(System.Enum flag) { throw null; }
Expand Down Expand Up @@ -5860,7 +5859,6 @@ protected Type() { }
public virtual string? GetEnumName(object value) { throw null; }
public virtual string[] GetEnumNames() { throw null; }
public virtual System.Type GetEnumUnderlyingType() { throw null; }
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues<TEnum> instead.")]
public virtual System.Array GetEnumValues() { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents)]
public System.Reflection.EventInfo? GetEvent(string name) { throw null; }
Expand Down

0 comments on commit 031eef9

Please sign in to comment.