From d43c9c7b6d74bb0c7941555b02b6793eadc38e68 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 9 Dec 2022 15:07:56 -0500 Subject: [PATCH 1/6] ifdef out unsupported Enum underlying types for nativeaot --- .../System.Private.CoreLib/src/System/Enum.cs | 237 ++++++++++++------ 1 file changed, 157 insertions(+), 80 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 4b148acfee72b..831b4b23faae2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -41,21 +41,22 @@ public abstract partial class Enum : ValueType, IComparable, ISpanFormattable, I RuntimeType rt = (RuntimeType)typeof(TEnum); Type underlyingType = typeof(TEnum).GetEnumUnderlyingType(); + if (underlyingType == typeof(sbyte)) return GetNameInlined(GetEnumInfo(rt), *(sbyte*)&value); + if (underlyingType == typeof(byte)) return GetNameInlined(GetEnumInfo(rt), *(byte*)&value); + if (underlyingType == typeof(short)) return GetNameInlined(GetEnumInfo(rt), *(short*)&value); + if (underlyingType == typeof(ushort)) return GetNameInlined(GetEnumInfo(rt), *(ushort*)&value); if (underlyingType == typeof(int)) return GetNameInlined(GetEnumInfo(rt), *(int*)&value); if (underlyingType == typeof(uint)) return GetNameInlined(GetEnumInfo(rt), *(uint*)&value); if (underlyingType == typeof(long)) return GetNameInlined(GetEnumInfo(rt), *(long*)&value); if (underlyingType == typeof(ulong)) return GetNameInlined(GetEnumInfo(rt), *(ulong*)&value); - if (underlyingType == typeof(byte)) return GetNameInlined(GetEnumInfo(rt), *(byte*)&value); - if (underlyingType == typeof(sbyte)) return GetNameInlined(GetEnumInfo(rt), *(sbyte*)&value); - if (underlyingType == typeof(short)) return GetNameInlined(GetEnumInfo(rt), *(short*)&value); - if (underlyingType == typeof(ushort)) return GetNameInlined(GetEnumInfo(rt), *(ushort*)&value); +#if !NATIVEAOT if (underlyingType == typeof(nint)) return GetNameInlined(GetEnumInfo(rt), *(nint*)&value); if (underlyingType == typeof(nuint)) return GetNameInlined(GetEnumInfo(rt), *(nuint*)&value); - if (underlyingType == typeof(char)) return GetNameInlined(GetEnumInfo(rt), *(char*)&value); if (underlyingType == typeof(float)) return GetNameInlined(GetEnumInfo(rt), *(float*)&value); if (underlyingType == typeof(double)) return GetNameInlined(GetEnumInfo(rt), *(double*)&value); + if (underlyingType == typeof(char)) return GetNameInlined(GetEnumInfo(rt), *(char*)&value); if (underlyingType == typeof(bool)) return GetNameInlined(GetEnumInfo(rt), *(bool*)&value ? (byte)1 : (byte)0); - +#endif throw CreateUnknownEnumTypeException(); } @@ -100,10 +101,6 @@ public abstract partial class Enum : ValueType, IComparable, ISpanFormattable, I if (uint64Value > byte.MaxValue) return null; return GetName(GetEnumInfo(enumType), (byte)uint64Value); - case TypeCode.Boolean: - if (uint64Value > 1) return null; - return GetName(GetEnumInfo(enumType), (byte)uint64Value); - case TypeCode.Int16: if ((long)uint64Value < short.MinValue || (long)uint64Value > short.MaxValue) return null; return GetName(GetEnumInfo(enumType), (short)uint64Value); @@ -112,25 +109,32 @@ public abstract partial class Enum : ValueType, IComparable, ISpanFormattable, I if (uint64Value > ushort.MaxValue) return null; return GetName(GetEnumInfo(enumType), (ushort)uint64Value); - case TypeCode.Char: - if (uint64Value > char.MaxValue) return null; - return GetName(GetEnumInfo(enumType), (char)uint64Value); + case TypeCode.Int32: + if ((long)uint64Value < int.MinValue || (long)uint64Value > int.MaxValue) return null; + return GetName(GetEnumInfo(enumType), (int)uint64Value); case TypeCode.UInt32: if (uint64Value > uint.MaxValue) return null; return GetName(GetEnumInfo(enumType), (uint)uint64Value); - case TypeCode.Int32: - if ((long)uint64Value < int.MinValue || (long)uint64Value > int.MaxValue) return null; - return GetName(GetEnumInfo(enumType), (int)uint64Value); + case TypeCode.Int64: + return GetName(GetEnumInfo(enumType), (long)uint64Value); case TypeCode.UInt64: return GetName(GetEnumInfo(enumType), uint64Value); - case TypeCode.Int64: - return GetName(GetEnumInfo(enumType), (long)uint64Value); +#if !NATIVEAOT + case TypeCode.Char: + if (uint64Value > char.MaxValue) return null; + return GetName(GetEnumInfo(enumType), (char)uint64Value); + + case TypeCode.Boolean: + if (uint64Value > 1) return null; + return GetName(GetEnumInfo(enumType), (byte)uint64Value); +#endif }; +#if !NATIVEAOT if (underlyingType == typeof(nint)) { if ((long)uint64Value < nint.MinValue || (long)uint64Value > nint.MaxValue) return null; @@ -142,6 +146,7 @@ public abstract partial class Enum : ValueType, IComparable, ISpanFormattable, I if (uint64Value > nuint.MaxValue) return null; return GetName(GetEnumInfo(enumType), (nuint)uint64Value); } +#endif throw CreateUnknownEnumTypeException(); } @@ -211,20 +216,22 @@ public static string[] GetNames() where TEnum : struct, Enum Type underlyingType = typeof(TEnum).GetEnumUnderlyingType(); // Get the cached names array. - if (underlyingType == typeof(int)) names = GetEnumInfo(rt).Names; - else if (underlyingType == typeof(uint)) names = GetEnumInfo(rt).Names; - else if (underlyingType == typeof(long)) names = GetEnumInfo(rt).Names; - else if (underlyingType == typeof(ulong)) names = GetEnumInfo(rt).Names; + if (underlyingType == typeof(sbyte)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(byte)) names = GetEnumInfo(rt).Names; - else if (underlyingType == typeof(sbyte)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(short)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(ushort)) names = GetEnumInfo(rt).Names; + else if (underlyingType == typeof(int)) names = GetEnumInfo(rt).Names; + else if (underlyingType == typeof(uint)) names = GetEnumInfo(rt).Names; + else if (underlyingType == typeof(long)) names = GetEnumInfo(rt).Names; + else if (underlyingType == typeof(ulong)) names = GetEnumInfo(rt).Names; +#if !NATIVEAOT else if (underlyingType == typeof(nint)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(nuint)) names = GetEnumInfo(rt).Names; - else if (underlyingType == typeof(char)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(float)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(double)) names = GetEnumInfo(rt).Names; + else if (underlyingType == typeof(char)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(bool)) names = GetEnumInfo(rt).Names; +#endif else throw CreateUnknownEnumTypeException(); // Return a clone of the array to avoid exposing the cached array instance. @@ -258,12 +265,14 @@ internal static string[] GetNamesNoCopy(RuntimeType enumType) CorElementType.ELEMENT_TYPE_U4 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_I8 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_U8 => GetEnumInfo(enumType).Names, +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_R8 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_I => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_U => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_CHAR => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_BOOLEAN => GetEnumInfo(enumType).Names, +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -345,12 +354,14 @@ internal static Array GetValuesAsUnderlyingType(RuntimeType enumType) CorElementType.ELEMENT_TYPE_U4 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_I8 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_U8 => GetEnumInfo(enumType, getNames: false).CloneValues(), +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_R8 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_I => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_U => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_CHAR => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_BOOLEAN => CopyByteArrayToNewBoolArray(GetEnumInfo(enumType, getNames: false).Values), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -371,12 +382,14 @@ internal static Array GetValuesAsUnderlyingTypeNoCopy(RuntimeType enumType) CorElementType.ELEMENT_TYPE_U4 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_I8 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_U8 => GetEnumInfo(enumType, getNames: false).Values, +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_R8 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_I => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_U => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_CHAR => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_BOOLEAN => CopyByteArrayToNewBoolArray(GetEnumInfo(enumType, getNames: false).Values), // this is the only case that clones, out of necessity +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -400,7 +413,6 @@ public bool HasFlag(Enum flag) { case CorElementType.ELEMENT_TYPE_I1: case CorElementType.ELEMENT_TYPE_U1: - case CorElementType.ELEMENT_TYPE_BOOLEAN: { byte flagsValue = pFlagsValue; return (pThisValue & flagsValue) == flagsValue; @@ -408,7 +420,6 @@ public bool HasFlag(Enum flag) case CorElementType.ELEMENT_TYPE_I2: case CorElementType.ELEMENT_TYPE_U2: - case CorElementType.ELEMENT_TYPE_CHAR: { ushort flagsValue = Unsafe.As(ref pFlagsValue); return (Unsafe.As(ref pThisValue) & flagsValue) == flagsValue; @@ -416,11 +427,6 @@ public bool HasFlag(Enum flag) case CorElementType.ELEMENT_TYPE_I4: case CorElementType.ELEMENT_TYPE_U4: -#if TARGET_32BIT - case CorElementType.ELEMENT_TYPE_I: - case CorElementType.ELEMENT_TYPE_U: -#endif - case CorElementType.ELEMENT_TYPE_R4: { uint flagsValue = Unsafe.As(ref pFlagsValue); return (Unsafe.As(ref pThisValue) & flagsValue) == flagsValue; @@ -428,16 +434,33 @@ public bool HasFlag(Enum flag) case CorElementType.ELEMENT_TYPE_I8: case CorElementType.ELEMENT_TYPE_U8: -#if TARGET_64BIT - case CorElementType.ELEMENT_TYPE_I: - case CorElementType.ELEMENT_TYPE_U: -#endif - case CorElementType.ELEMENT_TYPE_R8: { ulong flagsValue = Unsafe.As(ref pFlagsValue); return (Unsafe.As(ref pThisValue) & flagsValue) == flagsValue; } +#if !NATIVEAOT + case CorElementType.ELEMENT_TYPE_BOOLEAN: + goto case CorElementType.ELEMENT_TYPE_U1; + + case CorElementType.ELEMENT_TYPE_CHAR: + goto case CorElementType.ELEMENT_TYPE_U2; + + case CorElementType.ELEMENT_TYPE_R4: + goto case CorElementType.ELEMENT_TYPE_U4; + + case CorElementType.ELEMENT_TYPE_R8: + goto case CorElementType.ELEMENT_TYPE_U8; + + case CorElementType.ELEMENT_TYPE_I: + case CorElementType.ELEMENT_TYPE_U: +#if TARGET_32BIT + goto case CorElementType.ELEMENT_TYPE_U4; +#else + goto case CorElementType.ELEMENT_TYPE_U8; +#endif +#endif + default: Debug.Fail("Unknown enum underlying type"); return false; @@ -471,20 +494,22 @@ public static unsafe bool IsDefined(TEnum value) where TEnum : struct, En RuntimeType rt = (RuntimeType)typeof(TEnum); Type underlyingType = typeof(TEnum).GetEnumUnderlyingType(); + if (underlyingType == typeof(sbyte)) return IsDefinedPrimitive(rt, *(sbyte*)&value); + if (underlyingType == typeof(byte)) return IsDefinedPrimitive(rt, *(byte*)&value); + if (underlyingType == typeof(short)) return IsDefinedPrimitive(rt, *(short*)&value); + if (underlyingType == typeof(ushort)) return IsDefinedPrimitive(rt, *(ushort*)&value); if (underlyingType == typeof(int)) return IsDefinedPrimitive(rt, *(int*)&value); if (underlyingType == typeof(uint)) return IsDefinedPrimitive(rt, *(uint*)&value); if (underlyingType == typeof(long)) return IsDefinedPrimitive(rt, *(long*)&value); if (underlyingType == typeof(ulong)) return IsDefinedPrimitive(rt, *(ulong*)&value); - if (underlyingType == typeof(byte)) return IsDefinedPrimitive(rt, *(byte*)&value); - if (underlyingType == typeof(sbyte)) return IsDefinedPrimitive(rt, *(sbyte*)&value); - if (underlyingType == typeof(short)) return IsDefinedPrimitive(rt, *(short*)&value); - if (underlyingType == typeof(ushort)) return IsDefinedPrimitive(rt, *(ushort*)&value); +#if !NATIVEAOT if (underlyingType == typeof(nint)) return IsDefinedPrimitive(rt, *(nint*)&value); if (underlyingType == typeof(nuint)) return IsDefinedPrimitive(rt, *(nuint*)&value); - if (underlyingType == typeof(char)) return IsDefinedPrimitive(rt, *(char*)&value); if (underlyingType == typeof(float)) return IsDefinedPrimitive(rt, *(float*)&value); if (underlyingType == typeof(double)) return IsDefinedPrimitive(rt, *(double*)&value); + if (underlyingType == typeof(char)) return IsDefinedPrimitive(rt, *(char*)&value); if (underlyingType == typeof(bool)) return IsDefinedPrimitive(rt, *(bool*)&value ? (byte)1 : (byte)0); +#endif throw CreateUnknownEnumTypeException(); } @@ -774,6 +799,9 @@ private static unsafe bool TryParse(Type enumType, ReadOnlySpan value, boo [MethodImpl(MethodImplOptions.NoInlining)] static bool TryParseRareTypes(RuntimeType rt, ReadOnlySpan value, bool ignoreCase, bool throwOnFailure, [NotNullWhen(true)] out long result) { +#if NATIVEAOT + throw CreateUnknownEnumTypeException(); +#else bool parsed; switch (InternalGetCorElementType(rt)) @@ -825,6 +853,7 @@ static bool TryParseRareTypes(RuntimeType rt, ReadOnlySpan value, bool ign } return parsed; +#endif } } @@ -895,20 +924,22 @@ private static bool TryParse(ReadOnlySpan value, bool ignoreCase, b RuntimeType rt = (RuntimeType)typeof(TEnum); Type underlyingType = typeof(TEnum).GetEnumUnderlyingType(); + if (underlyingType == typeof(sbyte)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(byte)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(short)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(ushort)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(int)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(uint)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(long)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(ulong)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(byte)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(sbyte)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(short)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(ushort)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); +#if !NATIVEAOT if (underlyingType == typeof(float)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(double)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(char)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(nint)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(nuint)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(char)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(bool)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); +#endif if (throwOnFailure) { @@ -1145,16 +1176,19 @@ internal static ulong ToUInt64(object value) { case TypeCode.SByte: return (ulong)(sbyte)value; case TypeCode.Byte: return (byte)value; - case TypeCode.Boolean: return (bool)value ? 1UL : 0UL; case TypeCode.Int16: return (ulong)(short)value; case TypeCode.UInt16: return (ushort)value; - case TypeCode.Char: return (char)value; - case TypeCode.UInt32: return (uint)value; case TypeCode.Int32: return (ulong)(int)value; - case TypeCode.UInt64: return (ulong)value; case TypeCode.Int64: return (ulong)(long)value; + case TypeCode.UInt32: return (uint)value; + case TypeCode.UInt64: return (ulong)value; +#if !NATIVEAOT + case TypeCode.Char: return (char)value; + case TypeCode.Boolean: return (bool)value ? 1UL : 0UL; +#endif }; +#if !NATIVEAOT if (value is not null) { Type valueType = value.GetType(); @@ -1166,6 +1200,7 @@ internal static ulong ToUInt64(object value) if (valueType == typeof(nint)) return (ulong)(nint)value; if (valueType == typeof(nuint)) return (nuint)value; } +#endif throw CreateUnknownEnumTypeException(); } @@ -1184,12 +1219,14 @@ internal object GetValue() CorElementType.ELEMENT_TYPE_U4 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_I8 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_U8 => Unsafe.As(ref data), +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_R8 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_I => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_U => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_CHAR => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_BOOLEAN => Unsafe.As(ref data), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -1213,31 +1250,41 @@ public override bool Equals([NotNullWhen(true)] object? obj) { case CorElementType.ELEMENT_TYPE_I1: case CorElementType.ELEMENT_TYPE_U1: - case CorElementType.ELEMENT_TYPE_BOOLEAN: return pThisValue == pOtherValue; case CorElementType.ELEMENT_TYPE_I2: case CorElementType.ELEMENT_TYPE_U2: - case CorElementType.ELEMENT_TYPE_CHAR: return Unsafe.As(ref pThisValue) == Unsafe.As(ref pOtherValue); case CorElementType.ELEMENT_TYPE_I4: case CorElementType.ELEMENT_TYPE_U4: -#if TARGET_32BIT - case CorElementType.ELEMENT_TYPE_I: - case CorElementType.ELEMENT_TYPE_U: -#endif - case CorElementType.ELEMENT_TYPE_R4: return Unsafe.As(ref pThisValue) == Unsafe.As(ref pOtherValue); case CorElementType.ELEMENT_TYPE_I8: case CorElementType.ELEMENT_TYPE_U8: -#if TARGET_64BIT + return Unsafe.As(ref pThisValue) == Unsafe.As(ref pOtherValue); + +#if !NATIVEAOT + case CorElementType.ELEMENT_TYPE_BOOLEAN: + goto case CorElementType.ELEMENT_TYPE_U1; + + case CorElementType.ELEMENT_TYPE_CHAR: + goto case CorElementType.ELEMENT_TYPE_U2; + + case CorElementType.ELEMENT_TYPE_R4: + goto case CorElementType.ELEMENT_TYPE_U4; + + case CorElementType.ELEMENT_TYPE_R8: + goto case CorElementType.ELEMENT_TYPE_U8; + case CorElementType.ELEMENT_TYPE_I: case CorElementType.ELEMENT_TYPE_U: +#if TARGET_32BIT + goto case CorElementType.ELEMENT_TYPE_U4; +#else + goto case CorElementType.ELEMENT_TYPE_U8; +#endif #endif - case CorElementType.ELEMENT_TYPE_R8: - return Unsafe.As(ref pThisValue) == Unsafe.As(ref pOtherValue); default: Debug.Fail("Unknown enum underlying type"); @@ -1262,12 +1309,14 @@ public override int GetHashCode() CorElementType.ELEMENT_TYPE_U4 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_I8 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_U8 => Unsafe.As(ref data).GetHashCode(), +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_R8 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_I => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_U => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_CHAR => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_BOOLEAN => Unsafe.As(ref data).GetHashCode(), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -1293,46 +1342,52 @@ public int CompareTo(object? target) return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); case CorElementType.ELEMENT_TYPE_U1: - case CorElementType.ELEMENT_TYPE_BOOLEAN: return pThisValue.CompareTo(pTargetValue); case CorElementType.ELEMENT_TYPE_I2: return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); case CorElementType.ELEMENT_TYPE_U2: - case CorElementType.ELEMENT_TYPE_CHAR: return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); case CorElementType.ELEMENT_TYPE_I4: -#if TARGET_32BIT - case CorElementType.ELEMENT_TYPE_I: -#endif return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); case CorElementType.ELEMENT_TYPE_U4: -#if TARGET_32BIT - case CorElementType.ELEMENT_TYPE_U: -#endif return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); case CorElementType.ELEMENT_TYPE_I8: -#if TARGET_64BIT - case CorElementType.ELEMENT_TYPE_I: -#endif return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); case CorElementType.ELEMENT_TYPE_U8: -#if TARGET_64BIT - case CorElementType.ELEMENT_TYPE_U: -#endif return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); +#if !NATIVEAOT case CorElementType.ELEMENT_TYPE_R4: return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); case CorElementType.ELEMENT_TYPE_R8: return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); + case CorElementType.ELEMENT_TYPE_BOOLEAN: + goto case CorElementType.ELEMENT_TYPE_U1; + + case CorElementType.ELEMENT_TYPE_CHAR: + goto case CorElementType.ELEMENT_TYPE_U2; + +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_I: + goto case CorElementType.ELEMENT_TYPE_I4; + case CorElementType.ELEMENT_TYPE_U: + goto case CorElementType.ELEMENT_TYPE_U4; +#else + case CorElementType.ELEMENT_TYPE_I: + goto case CorElementType.ELEMENT_TYPE_I8; + case CorElementType.ELEMENT_TYPE_U: + goto case CorElementType.ELEMENT_TYPE_U8; +#endif +#endif + default: Debug.Fail("Unknown enum underlying type"); return 0; @@ -1363,12 +1418,14 @@ public override string ToString() static string HandleRareTypes(RuntimeType enumType, ref byte rawData) => InternalGetCorElementType(enumType) switch { +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_R8 => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_I => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_U => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_CHAR => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_BOOLEAN => ToStringBool(enumType, null, ref rawData), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -1411,12 +1468,14 @@ public string ToString([StringSyntax(StringSyntaxAttribute.EnumFormat)] string? static string HandleRareTypes(RuntimeType enumType, char formatChar, ref byte rawData) => InternalGetCorElementType(enumType) switch { +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_R8 => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_I => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_U => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_CHAR => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_BOOLEAN => ToStringBool(enumType, formatChar.ToString(), ref rawData), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -1704,12 +1763,14 @@ public static string Format(Type enumType, object value, [StringSyntax(StringSyn CorElementType.ELEMENT_TYPE_U4 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_I8 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_U8 => ToString(rtType, formatChar, ref rawData), +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_R8 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_I => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_U => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_CHAR => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_BOOLEAN => ToStringBool(rtType, format, ref rawData), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -1742,12 +1803,14 @@ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, Re CorElementType.ELEMENT_TYPE_U4 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_I8 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_U8 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_R8 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_I => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_U => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_CHAR => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_BOOLEAN => TryFormatBool(enumType, rawData != 0, destination, out charsWritten, format), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -1763,12 +1826,14 @@ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, Re CorElementType.ELEMENT_TYPE_U4 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_I8 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_U8 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), +#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_R8 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_I => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_U => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_CHAR => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_BOOLEAN => TryFormatBool(enumType, rawData != 0, destination, out charsWritten, format), +#endif _ => throw CreateUnknownEnumTypeException(), }; } @@ -1801,12 +1866,14 @@ public static unsafe bool TryFormat(TEnum value, Span destination, if (underlyingType == typeof(sbyte)) return TryFormatPrimitiveDefault(rt, *(sbyte*)&value, destination, out charsWritten); if (underlyingType == typeof(short)) return TryFormatPrimitiveDefault(rt, *(short*)&value, destination, out charsWritten); if (underlyingType == typeof(ushort)) return TryFormatPrimitiveDefault(rt, *(ushort*)&value, destination, out charsWritten); +#if !NATIVEAOT if (underlyingType == typeof(nint)) return TryFormatPrimitiveDefault(rt, *(nint*)&value, destination, out charsWritten); if (underlyingType == typeof(nuint)) return TryFormatPrimitiveDefault(rt, *(nuint*)&value, destination, out charsWritten); - if (underlyingType == typeof(char)) return TryFormatPrimitiveDefault(rt, *(char*)&value, destination, out charsWritten); if (underlyingType == typeof(float)) return TryFormatPrimitiveDefault(rt, *(float*)&value, destination, out charsWritten); if (underlyingType == typeof(double)) return TryFormatPrimitiveDefault(rt, *(double*)&value, destination, out charsWritten); + if (underlyingType == typeof(char)) return TryFormatPrimitiveDefault(rt, *(char*)&value, destination, out charsWritten); if (underlyingType == typeof(bool)) return TryFormatBool(rt, *(bool*)&value, destination, out charsWritten, format: default); +#endif } else { @@ -1818,12 +1885,14 @@ public static unsafe bool TryFormat(TEnum value, Span destination, if (underlyingType == typeof(sbyte)) return TryFormatPrimitiveNonDefault(rt, *(sbyte*)&value, destination, out charsWritten, format); if (underlyingType == typeof(short)) return TryFormatPrimitiveNonDefault(rt, *(short*)&value, destination, out charsWritten, format); if (underlyingType == typeof(ushort)) return TryFormatPrimitiveNonDefault(rt, *(ushort*)&value, destination, out charsWritten, format); +#if !NATIVEAOT if (underlyingType == typeof(nint)) return TryFormatPrimitiveNonDefault(rt, *(nint*)&value, destination, out charsWritten, format); if (underlyingType == typeof(nuint)) return TryFormatPrimitiveNonDefault(rt, *(nuint*)&value, destination, out charsWritten, format); - if (underlyingType == typeof(char)) return TryFormatPrimitiveNonDefault(rt, *(char*)&value, destination, out charsWritten, format); if (underlyingType == typeof(float)) return TryFormatPrimitiveNonDefault(rt, *(float*)&value, destination, out charsWritten, format); if (underlyingType == typeof(double)) return TryFormatPrimitiveNonDefault(rt, *(double*)&value, destination, out charsWritten, format); + if (underlyingType == typeof(char)) return TryFormatPrimitiveNonDefault(rt, *(char*)&value, destination, out charsWritten, format); if (underlyingType == typeof(bool)) return TryFormatBool(rt, *(bool*)&value, destination, out charsWritten, format); +#endif } throw CreateUnknownEnumTypeException(); @@ -1858,12 +1927,14 @@ internal static unsafe bool TryFormatUnconstrained(TEnum value, Span(TEnum value, Span Date: Mon, 12 Dec 2022 18:33:35 -0800 Subject: [PATCH 2/6] Use dedicated ifdef --- .../System.Private.CoreLib/src/System/Enum.cs | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 831b4b23faae2..2c8ccd2f30951 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -1,6 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// Rare enums types not expressible in C# are not supported in native AOT +#if !NATIVEAOT +#define RARE_ENUMS +#endif + using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -49,7 +54,7 @@ public abstract partial class Enum : ValueType, IComparable, ISpanFormattable, I if (underlyingType == typeof(uint)) return GetNameInlined(GetEnumInfo(rt), *(uint*)&value); if (underlyingType == typeof(long)) return GetNameInlined(GetEnumInfo(rt), *(long*)&value); if (underlyingType == typeof(ulong)) return GetNameInlined(GetEnumInfo(rt), *(ulong*)&value); -#if !NATIVEAOT +#if RARE_ENUMS if (underlyingType == typeof(nint)) return GetNameInlined(GetEnumInfo(rt), *(nint*)&value); if (underlyingType == typeof(nuint)) return GetNameInlined(GetEnumInfo(rt), *(nuint*)&value); if (underlyingType == typeof(float)) return GetNameInlined(GetEnumInfo(rt), *(float*)&value); @@ -123,7 +128,7 @@ public abstract partial class Enum : ValueType, IComparable, ISpanFormattable, I case TypeCode.UInt64: return GetName(GetEnumInfo(enumType), uint64Value); -#if !NATIVEAOT +#if RARE_ENUMS case TypeCode.Char: if (uint64Value > char.MaxValue) return null; return GetName(GetEnumInfo(enumType), (char)uint64Value); @@ -134,7 +139,7 @@ public abstract partial class Enum : ValueType, IComparable, ISpanFormattable, I #endif }; -#if !NATIVEAOT +#if RARE_ENUMS if (underlyingType == typeof(nint)) { if ((long)uint64Value < nint.MinValue || (long)uint64Value > nint.MaxValue) return null; @@ -224,7 +229,7 @@ public static string[] GetNames() where TEnum : struct, Enum else if (underlyingType == typeof(uint)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(long)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(ulong)) names = GetEnumInfo(rt).Names; -#if !NATIVEAOT +#if RARE_ENUMS else if (underlyingType == typeof(nint)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(nuint)) names = GetEnumInfo(rt).Names; else if (underlyingType == typeof(float)) names = GetEnumInfo(rt).Names; @@ -265,7 +270,7 @@ internal static string[] GetNamesNoCopy(RuntimeType enumType) CorElementType.ELEMENT_TYPE_U4 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_I8 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_U8 => GetEnumInfo(enumType).Names, -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_R8 => GetEnumInfo(enumType).Names, CorElementType.ELEMENT_TYPE_I => GetEnumInfo(enumType).Names, @@ -354,7 +359,7 @@ internal static Array GetValuesAsUnderlyingType(RuntimeType enumType) CorElementType.ELEMENT_TYPE_U4 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_I8 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_U8 => GetEnumInfo(enumType, getNames: false).CloneValues(), -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_R8 => GetEnumInfo(enumType, getNames: false).CloneValues(), CorElementType.ELEMENT_TYPE_I => GetEnumInfo(enumType, getNames: false).CloneValues(), @@ -382,7 +387,7 @@ internal static Array GetValuesAsUnderlyingTypeNoCopy(RuntimeType enumType) CorElementType.ELEMENT_TYPE_U4 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_I8 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_U8 => GetEnumInfo(enumType, getNames: false).Values, -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_R8 => GetEnumInfo(enumType, getNames: false).Values, CorElementType.ELEMENT_TYPE_I => GetEnumInfo(enumType, getNames: false).Values, @@ -439,7 +444,7 @@ public bool HasFlag(Enum flag) return (Unsafe.As(ref pThisValue) & flagsValue) == flagsValue; } -#if !NATIVEAOT +#if RARE_ENUMS case CorElementType.ELEMENT_TYPE_BOOLEAN: goto case CorElementType.ELEMENT_TYPE_U1; @@ -502,7 +507,7 @@ public static unsafe bool IsDefined(TEnum value) where TEnum : struct, En if (underlyingType == typeof(uint)) return IsDefinedPrimitive(rt, *(uint*)&value); if (underlyingType == typeof(long)) return IsDefinedPrimitive(rt, *(long*)&value); if (underlyingType == typeof(ulong)) return IsDefinedPrimitive(rt, *(ulong*)&value); -#if !NATIVEAOT +#if RARE_ENUMS if (underlyingType == typeof(nint)) return IsDefinedPrimitive(rt, *(nint*)&value); if (underlyingType == typeof(nuint)) return IsDefinedPrimitive(rt, *(nuint*)&value); if (underlyingType == typeof(float)) return IsDefinedPrimitive(rt, *(float*)&value); @@ -799,9 +804,7 @@ private static unsafe bool TryParse(Type enumType, ReadOnlySpan value, boo [MethodImpl(MethodImplOptions.NoInlining)] static bool TryParseRareTypes(RuntimeType rt, ReadOnlySpan value, bool ignoreCase, bool throwOnFailure, [NotNullWhen(true)] out long result) { -#if NATIVEAOT - throw CreateUnknownEnumTypeException(); -#else +#if RARE_ENUMS bool parsed; switch (InternalGetCorElementType(rt)) @@ -853,6 +856,8 @@ static bool TryParseRareTypes(RuntimeType rt, ReadOnlySpan value, bool ign } return parsed; +#else + throw CreateUnknownEnumTypeException(); #endif } } @@ -932,7 +937,7 @@ private static bool TryParse(ReadOnlySpan value, bool ignoreCase, b if (underlyingType == typeof(uint)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(long)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(ulong)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); -#if !NATIVEAOT +#if RARE_ENUMS if (underlyingType == typeof(float)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(double)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(nint)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); @@ -941,12 +946,7 @@ private static bool TryParse(ReadOnlySpan value, bool ignoreCase, b if (underlyingType == typeof(bool)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); #endif - if (throwOnFailure) - { - throw CreateUnknownEnumTypeException(); - } - result = default; - return false; + throw CreateUnknownEnumTypeException(); } /// Core implementation for all {Try}Parse methods, both generic and non-generic, parsing either by value or by name. @@ -1041,7 +1041,7 @@ private static unsafe bool TryParseByValueOrName( } else { - // Rare types not expressible in C# +#if RARE_ENUMS Type underlyingType = GetUnderlyingType(enumType); try { @@ -1056,6 +1056,9 @@ private static unsafe bool TryParseByValueOrName( { status = Number.ParsingStatus.Overflow; // fall through to returning failure } +#else + throw CreateUnknownEnumTypeException(); +#endif } if (status != Number.ParsingStatus.Overflow) @@ -1182,13 +1185,13 @@ internal static ulong ToUInt64(object value) case TypeCode.Int64: return (ulong)(long)value; case TypeCode.UInt32: return (uint)value; case TypeCode.UInt64: return (ulong)value; -#if !NATIVEAOT +#if RARE_ENUMS case TypeCode.Char: return (char)value; case TypeCode.Boolean: return (bool)value ? 1UL : 0UL; #endif }; -#if !NATIVEAOT +#if RARE_ENUMS if (value is not null) { Type valueType = value.GetType(); @@ -1219,7 +1222,7 @@ internal object GetValue() CorElementType.ELEMENT_TYPE_U4 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_I8 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_U8 => Unsafe.As(ref data), -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_R8 => Unsafe.As(ref data), CorElementType.ELEMENT_TYPE_I => Unsafe.As(ref data), @@ -1264,7 +1267,7 @@ public override bool Equals([NotNullWhen(true)] object? obj) case CorElementType.ELEMENT_TYPE_U8: return Unsafe.As(ref pThisValue) == Unsafe.As(ref pOtherValue); -#if !NATIVEAOT +#if RARE_ENUMS case CorElementType.ELEMENT_TYPE_BOOLEAN: goto case CorElementType.ELEMENT_TYPE_U1; @@ -1309,7 +1312,7 @@ public override int GetHashCode() CorElementType.ELEMENT_TYPE_U4 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_I8 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_U8 => Unsafe.As(ref data).GetHashCode(), -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_R8 => Unsafe.As(ref data).GetHashCode(), CorElementType.ELEMENT_TYPE_I => Unsafe.As(ref data).GetHashCode(), @@ -1362,7 +1365,7 @@ public int CompareTo(object? target) case CorElementType.ELEMENT_TYPE_U8: return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); -#if !NATIVEAOT +#if RARE_ENUMS case CorElementType.ELEMENT_TYPE_R4: return Unsafe.As(ref pThisValue).CompareTo(Unsafe.As(ref pTargetValue)); @@ -1416,18 +1419,20 @@ public override string ToString() [MethodImpl(MethodImplOptions.NoInlining)] static string HandleRareTypes(RuntimeType enumType, ref byte rawData) => +#if RARE_ENUMS InternalGetCorElementType(enumType) switch { -#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_R8 => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_I => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_U => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_CHAR => ToString(enumType, ref rawData), CorElementType.ELEMENT_TYPE_BOOLEAN => ToStringBool(enumType, null, ref rawData), -#endif _ => throw CreateUnknownEnumTypeException(), }; +#else + throw CreateUnknownEnumTypeException(); +#endif } /// Converts the value of this instance to its equivalent string representation using the specified format. @@ -1466,18 +1471,20 @@ public string ToString([StringSyntax(StringSyntaxAttribute.EnumFormat)] string? [MethodImpl(MethodImplOptions.NoInlining)] static string HandleRareTypes(RuntimeType enumType, char formatChar, ref byte rawData) => +#if RARE_ENUMS InternalGetCorElementType(enumType) switch { -#if !NATIVEAOT CorElementType.ELEMENT_TYPE_R4 => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_R8 => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_I => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_U => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_CHAR => ToString(enumType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_BOOLEAN => ToStringBool(enumType, formatChar.ToString(), ref rawData), -#endif _ => throw CreateUnknownEnumTypeException(), }; +#else + throw CreateUnknownEnumTypeException(); +#endif } /// This method overload is obsolete; use . @@ -1763,7 +1770,7 @@ public static string Format(Type enumType, object value, [StringSyntax(StringSyn CorElementType.ELEMENT_TYPE_U4 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_I8 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_U8 => ToString(rtType, formatChar, ref rawData), -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_R8 => ToString(rtType, formatChar, ref rawData), CorElementType.ELEMENT_TYPE_I => ToString(rtType, formatChar, ref rawData), @@ -1803,7 +1810,7 @@ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, Re CorElementType.ELEMENT_TYPE_U4 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_I8 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_U8 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_R8 => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), CorElementType.ELEMENT_TYPE_I => TryFormatPrimitiveDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten), @@ -1826,7 +1833,7 @@ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, Re CorElementType.ELEMENT_TYPE_U4 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_I8 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_U8 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), -#if !NATIVEAOT +#if RARE_ENUMS CorElementType.ELEMENT_TYPE_R4 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_R8 => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), CorElementType.ELEMENT_TYPE_I => TryFormatPrimitiveNonDefault(enumType, Unsafe.As(ref rawData), destination, out charsWritten, format), @@ -1866,7 +1873,7 @@ public static unsafe bool TryFormat(TEnum value, Span destination, if (underlyingType == typeof(sbyte)) return TryFormatPrimitiveDefault(rt, *(sbyte*)&value, destination, out charsWritten); if (underlyingType == typeof(short)) return TryFormatPrimitiveDefault(rt, *(short*)&value, destination, out charsWritten); if (underlyingType == typeof(ushort)) return TryFormatPrimitiveDefault(rt, *(ushort*)&value, destination, out charsWritten); -#if !NATIVEAOT +#if RARE_ENUMS if (underlyingType == typeof(nint)) return TryFormatPrimitiveDefault(rt, *(nint*)&value, destination, out charsWritten); if (underlyingType == typeof(nuint)) return TryFormatPrimitiveDefault(rt, *(nuint*)&value, destination, out charsWritten); if (underlyingType == typeof(float)) return TryFormatPrimitiveDefault(rt, *(float*)&value, destination, out charsWritten); @@ -1885,7 +1892,7 @@ public static unsafe bool TryFormat(TEnum value, Span destination, if (underlyingType == typeof(sbyte)) return TryFormatPrimitiveNonDefault(rt, *(sbyte*)&value, destination, out charsWritten, format); if (underlyingType == typeof(short)) return TryFormatPrimitiveNonDefault(rt, *(short*)&value, destination, out charsWritten, format); if (underlyingType == typeof(ushort)) return TryFormatPrimitiveNonDefault(rt, *(ushort*)&value, destination, out charsWritten, format); -#if !NATIVEAOT +#if RARE_ENUMS if (underlyingType == typeof(nint)) return TryFormatPrimitiveNonDefault(rt, *(nint*)&value, destination, out charsWritten, format); if (underlyingType == typeof(nuint)) return TryFormatPrimitiveNonDefault(rt, *(nuint*)&value, destination, out charsWritten, format); if (underlyingType == typeof(float)) return TryFormatPrimitiveNonDefault(rt, *(float*)&value, destination, out charsWritten, format); @@ -1927,7 +1934,7 @@ internal static unsafe bool TryFormatUnconstrained(TEnum value, Span(TEnum value, Span Date: Tue, 13 Dec 2022 10:17:24 -0800 Subject: [PATCH 3/6] Revert ToObject change --- src/libraries/System.Private.CoreLib/src/System/Enum.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 2c8ccd2f30951..f11023c69407b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -2317,13 +2317,10 @@ public static object ToObject(Type enumType, object value) case TypeCode.UInt64: return ToObject(enumType, (ulong)value); case TypeCode.Single: return ToObject(enumType, BitConverter.SingleToInt32Bits((float)value)); case TypeCode.Double: return ToObject(enumType, BitConverter.DoubleToInt64Bits((double)value)); -#if RARE_ENUMS case TypeCode.Char: return ToObject(enumType, (char)value); case TypeCode.Boolean: return ToObject(enumType, (bool)value ? 1L : 0L); -#endif }; -#if RARE_ENUMS Type valueType = value.GetType(); if (valueType.IsEnum) { @@ -2332,7 +2329,6 @@ public static object ToObject(Type enumType, object value) if (valueType == typeof(nint)) ToObject(enumType, (nint)value); if (valueType == typeof(nuint)) ToObject(enumType, (nuint)value); -#endif throw new ArgumentException(SR.Arg_MustBeEnumBaseTypeOrEnum, nameof(value)); } From d903544ddef1c4bf68c3d3491b91d7912bacfe8b Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 13 Dec 2022 11:44:04 -0800 Subject: [PATCH 4/6] Disable the rare enums support for Mono --- .../TestUtilities/System/PlatformDetection.cs | 2 + .../tests/ConversionsTests.cs | 53 +++++---------- .../tests/Cast/CastTests.cs | 2 +- .../System.Private.CoreLib/src/System/Enum.cs | 2 +- .../System.Runtime/tests/System/EnumTests.cs | 64 +++++++++---------- 5 files changed, 51 insertions(+), 72 deletions(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index 245ff9ccaee00..c0e677ddcb873 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -189,6 +189,8 @@ private static bool GetLinqExpressionsBuiltWithIsInterpretingOnly() public static bool IsPreciseGcSupported => !IsMonoRuntime; + public static bool IsRareEnumsSupported => !IsNativeAot && !IsMonoRuntime; + public static bool IsNotIntMaxValueArrayIndexSupported => s_largeArrayIsNotSupported.Value; public static bool IsAssemblyLoadingSupported => !IsNativeAot; diff --git a/src/libraries/Microsoft.VisualBasic.Core/tests/ConversionsTests.cs b/src/libraries/Microsoft.VisualBasic.Core/tests/ConversionsTests.cs index 354a744d01888..3d0366a96bb2f 100644 --- a/src/libraries/Microsoft.VisualBasic.Core/tests/ConversionsTests.cs +++ b/src/libraries/Microsoft.VisualBasic.Core/tests/ConversionsTests.cs @@ -13,29 +13,6 @@ namespace Microsoft.VisualBasic.Tests { public class ConversionsTests { - private static bool? s_reflectionEmitSupported = null; - - public static bool ReflectionEmitSupported - { - get - { - if (s_reflectionEmitSupported == null) - { - try - { - object o = FloatEnum; - s_reflectionEmitSupported = true; - } - catch (PlatformNotSupportedException) - { - s_reflectionEmitSupported = false; - } - } - - return s_reflectionEmitSupported.Value; - } - } - public static IEnumerable InvalidString_TestData() { yield return new object[] { "" }; @@ -49,7 +26,7 @@ public static IEnumerable InvalidString_TestData() public static IEnumerable InvalidBool_TestData() { - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { FloatEnum }; yield return new object[] { DoubleEnum }; @@ -65,7 +42,7 @@ public static IEnumerable InvalidNumberObject_TestData() yield return new object[] { char.MaxValue }; yield return new object[] { new DateTime(10) }; yield return new object[] { new object() }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { CharEnum }; } @@ -182,7 +159,7 @@ public static IEnumerable ToByte_Object_TestData() // bool. yield return new object[] { true, byte.MaxValue }; yield return new object[] { false, byte.MinValue }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, byte.MinValue }; } @@ -363,7 +340,7 @@ public static IEnumerable ToSByte_Object_TestData() // bool. yield return new object[] { true, (sbyte)(-1) }; yield return new object[] { false, (sbyte)0 }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, (sbyte)0 }; } @@ -537,7 +514,7 @@ public static IEnumerable ToUShort_Object_TestData() // bool. yield return new object[] { true, ushort.MaxValue }; yield return new object[] { false, ushort.MinValue }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, ushort.MinValue }; } @@ -721,7 +698,7 @@ public static IEnumerable ToShort_Object_TestData() // bool. yield return new object[] { true, (short)(-1) }; yield return new object[] { false, (short)0 }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, (short)0 }; } @@ -899,7 +876,7 @@ public static IEnumerable ToUInteger_Object_TestData() // bool. yield return new object[] { true, uint.MaxValue }; yield return new object[] { false, uint.MinValue }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, uint.MinValue }; } @@ -1089,7 +1066,7 @@ public static IEnumerable ToInteger_Object_TestData() // bool. yield return new object[] { true, -1 }; yield return new object[] { false, 0 }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, 0 }; } @@ -1275,7 +1252,7 @@ public static IEnumerable ToULong_Object_TestData() // bool. yield return new object[] { true, ulong.MaxValue }; yield return new object[] { false, ulong.MinValue }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, ulong.MinValue }; } @@ -1503,7 +1480,7 @@ public static IEnumerable ToLong_Object_TestData() // bool. yield return new object[] { true, (long)(-1) }; yield return new object[] { false, (long)0 }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, (long)0 }; } @@ -1729,7 +1706,7 @@ public static IEnumerable ToSingle_Object_TestData() // bool. yield return new object[] { true, (float)(-1) }; yield return new object[] { false, (float)0 }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, (float)0 }; } @@ -1922,7 +1899,7 @@ public static IEnumerable ToDouble_Object_TestData() // bool. yield return new object[] { true, (double)(-1) }; yield return new object[] { false, (double)0 }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, (double)0 }; } @@ -2118,7 +2095,7 @@ public static IEnumerable ToDecimal_Object_TestData() // bool. yield return new object[] { true, (decimal)(-1) }; yield return new object[] { false, (decimal)0 }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, (decimal)0 }; } @@ -2344,7 +2321,7 @@ public static IEnumerable ToBoolean_Object_TestData() // bool. yield return new object[] { true, true }; yield return new object[] { false, false }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, false }; } @@ -2659,7 +2636,7 @@ public static IEnumerable ToString_IConvertible_TestData() // bool. yield return new object[] { true, "True" }; yield return new object[] { false, "False" }; - if (ReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { BoolEnum, "False" }; } diff --git a/src/libraries/System.Linq.Expressions/tests/Cast/CastTests.cs b/src/libraries/System.Linq.Expressions/tests/Cast/CastTests.cs index 0f0294a58465c..8a3b0569baa2c 100644 --- a/src/libraries/System.Linq.Expressions/tests/Cast/CastTests.cs +++ b/src/libraries/System.Linq.Expressions/tests/Cast/CastTests.cs @@ -2373,7 +2373,7 @@ public static IEnumerable EnumerableTypes() yield return typeof(Int64Enum); yield return typeof(UInt64Enum); - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return NonCSharpTypes.CharEnumType; yield return NonCSharpTypes.BoolEnumType; diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index f11023c69407b..6878616b15f33 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // Rare enums types not expressible in C# are not supported in native AOT -#if !NATIVEAOT +#if !NATIVEAOT && !MONO #define RARE_ENUMS #endif diff --git a/src/libraries/System.Runtime/tests/System/EnumTests.cs b/src/libraries/System.Runtime/tests/System/EnumTests.cs index 5c0928a5900d9..d87abc5bdbc7c 100644 --- a/src/libraries/System.Runtime/tests/System/EnumTests.cs +++ b/src/libraries/System.Runtime/tests/System/EnumTests.cs @@ -77,7 +77,7 @@ public static IEnumerable Parse_TestData() yield return new object[] { ulong.MinValue.ToString(), false, (UInt64Enum)ulong.MinValue }; yield return new object[] { ulong.MaxValue.ToString(), false, (UInt64Enum)ulong.MaxValue }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // Char yield return new object[] { "Value1", false, Enum.ToObject(s_charEnumType, (char)1) }; @@ -204,7 +204,7 @@ public static IEnumerable Parse_Invalid_TestData() yield return new object[] { typeof(UInt64Enum), "-1", false, typeof(OverflowException) }; yield return new object[] { typeof(UInt64Enum), "18446744073709551616", false, typeof(OverflowException) }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // Char yield return new object[] { s_charEnumType, ((char)1).ToString(), false, typeof(ArgumentException) }; @@ -456,7 +456,7 @@ public static IEnumerable GetName_CharEnum_TestData() yield return new object[] { (char)4, null }; } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] [MemberData(nameof(GetName_CharEnum_TestData))] public void GetName_InvokeCharEnum_ReturnsExpected(object value, string expected) { @@ -471,7 +471,7 @@ public static IEnumerable GetName_BoolEnum_TestData() yield return new object[] { false, "Value2" }; } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] [MemberData(nameof(GetName_BoolEnum_TestData))] public void GetName_InvokeBoolEnum_ReturnsExpected(object value, string expected) { @@ -712,7 +712,7 @@ public static IEnumerable IsDefined_CharEnum_TestData() yield return new object[] { (char)99, false }; } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] [MemberData(nameof(IsDefined_CharEnum_TestData))] public void IsDefined_InvokeCharEnum_ReturnsExpected(object value, bool expected) { @@ -729,7 +729,7 @@ public static IEnumerable IsDefined_BoolEnum_TestData() yield return new object[] { false, true }; } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] [MemberData(nameof(IsDefined_BoolEnum_TestData))] public void IsDefined_InvokeBoolEnum_ReturnsExpected(object value, bool expected) { @@ -845,7 +845,7 @@ public static IEnumerable HasFlag_TestData() yield return new object[] { (UInt64Enum)0x3f06, (UInt64Enum)0x0010, false }; yield return new object[] { (UInt64Enum)0x3f06, (UInt64Enum)0x3f16, false }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // Char yield return new object[] { Enum.Parse(s_charEnumType, "Value0x3f06"), Enum.Parse(s_charEnumType, "Value0x3000"), true }; @@ -962,7 +962,7 @@ public static IEnumerable ToObject_TestData() yield return new object[] { typeof(UInt64Enum), (ulong)77, (UInt64Enum)77 }; yield return new object[] { typeof(UInt64Enum), (ulong)0x0123456789abcdefL, (UInt64Enum)0x0123456789abcdefL }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // Char yield return new object[] { s_charEnumType, (char)1, Enum.Parse(s_charEnumType, "Value1") }; @@ -995,7 +995,7 @@ public static IEnumerable ToObject_InvalidEnumType_TestData() yield return new object[] { typeof(Enum), typeof(ArgumentException) }; yield return new object[] { typeof(object), typeof(ArgumentException) }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) yield return new object[] { GetNonRuntimeEnumTypeBuilder(typeof(int)), typeof(ArgumentException) }; } @@ -1020,7 +1020,7 @@ public static IEnumerable ToObject_InvalidValue_TestData() yield return new object[] { typeof(SimpleEnum), null, typeof(ArgumentNullException) }; yield return new object[] { typeof(SimpleEnum), "Hello", typeof(ArgumentException) }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { s_intPtrEnumType, (IntPtr)1, typeof(ArgumentException) }; yield return new object[] { s_uintPtrEnumType, (UIntPtr)1, typeof(ArgumentException) }; @@ -1105,7 +1105,7 @@ public static IEnumerable Equals_TestData() yield return new object[] { UInt64Enum.One, new object(), false }; yield return new object[] { UInt64Enum.One, null, false }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // Char yield return new object[] { Enum.Parse(s_charEnumType, "Value1"), Enum.Parse(s_charEnumType, "Value1"), true }; @@ -1216,7 +1216,7 @@ public static IEnumerable CompareTo_TestData() yield return new object[] { UInt64Enum.One, UInt64Enum.Max, -1 }; yield return new object[] { UInt64Enum.One, null, 1 }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // Char yield return new object[] { Enum.Parse(s_charEnumType, "Value2"), Enum.Parse(s_charEnumType, "Value2"), 0 }; @@ -1281,7 +1281,7 @@ public static IEnumerable GetUnderlyingType_TestData() yield return new object[] { typeof(Int64Enum), typeof(long) }; yield return new object[] { typeof(UInt64Enum), typeof(ulong) }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { s_charEnumType, typeof(char) }; yield return new object[] { s_boolEnumType, typeof(bool) }; @@ -1387,7 +1387,7 @@ public void GetNames_InvokeUInt64Enum_ReturnsExpected() Assert.Equal(expected, Enum.GetNames()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetNames_InvokeCharEnum_ReturnsExpected() { var expected = new string[] { "Value0x0000", "Value1", "Value2", "Value0x0010", "Value0x0f06", "Value0x1000", "Value0x3000", "Value0x3f06", "Value0x3f16" }; @@ -1395,7 +1395,7 @@ public void GetNames_InvokeCharEnum_ReturnsExpected() Assert.NotSame(Enum.GetNames(s_charEnumType), Enum.GetNames(s_charEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetNames_InvokeBoolEnum_ReturnsExpected() { var expected = new string[] { "Value2", "Value1" }; @@ -1403,7 +1403,7 @@ public void GetNames_InvokeBoolEnum_ReturnsExpected() Assert.NotSame(Enum.GetNames(s_boolEnumType), Enum.GetNames(s_boolEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetNames_InvokeSingleEnum_ReturnsExpected() { var expected = new string[] { "Value0x0000", "Value1", "Value2", "Value0x0010", "Value0x0f06", "Value0x1000", "Value0x3000", "Value0x3f06", "Value0x3f16" }; @@ -1411,7 +1411,7 @@ public void GetNames_InvokeSingleEnum_ReturnsExpected() Assert.NotSame(Enum.GetNames(s_floatEnumType), Enum.GetNames(s_floatEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetNames_InvokeDoubleEnum_ReturnsExpected() { var expected = new string[] { "Value0x0000", "Value1", "Value2", "Value0x0010", "Value0x0f06", "Value0x1000", "Value0x3000", "Value0x3f06", "Value0x3f16" }; @@ -1419,7 +1419,7 @@ public void GetNames_InvokeDoubleEnum_ReturnsExpected() Assert.NotSame(Enum.GetNames(s_doubleEnumType), Enum.GetNames(s_doubleEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetNames_InvokeIntPtrEnum_ReturnsExpected() { var expected = new string[0]; @@ -1427,7 +1427,7 @@ public void GetNames_InvokeIntPtrEnum_ReturnsExpected() Assert.Same(Enum.GetNames(s_intPtrEnumType), Enum.GetNames(s_intPtrEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetNames_InvokeUIntPtrEnum_ReturnsExpected() { var expected = new string[0]; @@ -1532,7 +1532,7 @@ public void GetValues_InvokeUInt64Enum_ReturnsExpected() Assert.Equal(expected, Enum.GetValues()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetValues_InvokeCharEnum_ReturnsExpected() { var expected = new object[] { Enum.Parse(s_charEnumType, "Value0x0000"), Enum.Parse(s_charEnumType, "Value1"), Enum.Parse(s_charEnumType, "Value2"), Enum.Parse(s_charEnumType, "Value0x0010"), Enum.Parse(s_charEnumType, "Value0x0f06"), Enum.Parse(s_charEnumType, "Value0x1000"), Enum.Parse(s_charEnumType, "Value0x3000"), Enum.Parse(s_charEnumType, "Value0x3f06"), Enum.Parse(s_charEnumType, "Value0x3f16") }; @@ -1540,7 +1540,7 @@ public void GetValues_InvokeCharEnum_ReturnsExpected() Assert.NotSame(Enum.GetValues(s_charEnumType), Enum.GetValues(s_charEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetValues_InvokeBoolEnum_ReturnsExpected() { var expected = new object[] { Enum.Parse(s_boolEnumType, "Value2"), Enum.Parse(s_boolEnumType, "Value1") }; @@ -1548,7 +1548,7 @@ public void GetValues_InvokeBoolEnum_ReturnsExpected() Assert.NotSame(Enum.GetValues(s_boolEnumType), Enum.GetValues(s_boolEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetValues_InvokeSingleEnum_ReturnsExpected() { var expected = new object[] { Enum.Parse(s_floatEnumType, "Value0x0000"), Enum.Parse(s_floatEnumType, "Value1"), Enum.Parse(s_floatEnumType, "Value2"), Enum.Parse(s_floatEnumType, "Value0x0010"), Enum.Parse(s_floatEnumType, "Value0x0f06"), Enum.Parse(s_floatEnumType, "Value0x1000"), Enum.Parse(s_floatEnumType, "Value0x3000"), Enum.Parse(s_floatEnumType, "Value0x3f06"), Enum.Parse(s_floatEnumType, "Value0x3f16") }; @@ -1556,7 +1556,7 @@ public void GetValues_InvokeSingleEnum_ReturnsExpected() Assert.NotSame(Enum.GetValues(s_floatEnumType), Enum.GetValues(s_floatEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetValues_InvokeDoubleEnum_ReturnsExpected() { var expected = new object[] { Enum.Parse(s_doubleEnumType, "Value0x0000"), Enum.Parse(s_doubleEnumType, "Value1"), Enum.Parse(s_doubleEnumType, "Value2"), Enum.Parse(s_doubleEnumType, "Value0x0010"), Enum.Parse(s_doubleEnumType, "Value0x0f06"), Enum.Parse(s_doubleEnumType, "Value0x1000"), Enum.Parse(s_doubleEnumType, "Value0x3000"), Enum.Parse(s_doubleEnumType, "Value0x3f06"), Enum.Parse(s_doubleEnumType, "Value0x3f16") }; @@ -1564,7 +1564,7 @@ public void GetValues_InvokeDoubleEnum_ReturnsExpected() Assert.NotSame(Enum.GetValues(s_doubleEnumType), Enum.GetValues(s_doubleEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetValues_InvokeIntPtrEnum_ReturnsExpected() { var expected = new object[0]; @@ -1572,7 +1572,7 @@ public void GetValues_InvokeIntPtrEnum_ReturnsExpected() Assert.NotSame(Enum.GetValues(s_intPtrEnumType), Enum.GetValues(s_intPtrEnumType)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] public void GetValues_InvokeUIntPtrEnum_ReturnsExpected() { var expected = new object[0]; @@ -1751,7 +1751,7 @@ public static IEnumerable ToString_Format_TestData() yield return new object[] { (UInt64Enum)99, "D", "99" }; yield return new object[] { UInt64Enum.Max, "D", "18446744073709551615" }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // "D": Char yield return new object[] { Enum.ToObject(s_charEnumType, (char)0), "D", ((char)0).ToString() }; @@ -1834,7 +1834,7 @@ public static IEnumerable ToString_Format_TestData() yield return new object[] { (UInt64Enum)99, "X", "0000000000000063" }; yield return new object[] { UInt64Enum.Max, "X", "FFFFFFFFFFFFFFFF" }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // "X": Char yield return new object[] { Enum.ToObject(s_charEnumType, (char)0), "X", "0000" }; @@ -1900,7 +1900,7 @@ public static IEnumerable ToString_Format_TestData() yield return new object[] { (UInt64Enum)5, "F", "5" }; yield return new object[] { UInt64Enum.Max, "F", "Max" }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // "F": Char yield return new object[] { Enum.ToObject(s_charEnumType, (char)1), "F", "Value1" }; @@ -1928,7 +1928,7 @@ public static IEnumerable ToString_Format_TestData() // "F": Flags Attribute yield return new object[] { AttributeTargets.Class | AttributeTargets.Delegate, "F", "Class, Delegate" }; - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { // "G": Char yield return new object[] { Enum.ToObject(s_charEnumType, char.MaxValue), "G", char.MaxValue.ToString() }; @@ -2289,7 +2289,7 @@ public static IEnumerable Format_TestData() yield return new object[] { typeof(AttributeTargets), (int)(AttributeTargets.Class | AttributeTargets.Delegate), "G", "Class, Delegate" }; // nint/nuint types - if (PlatformDetection.IsReflectionEmitSupported) + if (PlatformDetection.IsReflectionEmitSupported && PlatformDetection.IsRareEnumsSupported) { yield return new object[] { s_intPtrEnumType, (nint)1, "G", "1" }; yield return new object[] { s_uintPtrEnumType, (nuint)2, "F", "2" }; @@ -2416,7 +2416,7 @@ public static IEnumerable UnsupportedEnum_TestData() yield return new object[] { Enum.ToObject(s_doubleEnumType, 2) }; } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported), nameof(PlatformDetection.IsRareEnumsSupported))] [MemberData(nameof(UnsupportedEnum_TestData))] public static void ToString_UnsupportedEnumType_ThrowsArgumentException(Enum e) { @@ -2427,7 +2427,7 @@ public static void ToString_UnsupportedEnumType_ThrowsArgumentException(Enum e) private static EnumBuilder GetNonRuntimeEnumTypeBuilder(Type underlyingType) { - if (!PlatformDetection.IsReflectionEmitSupported) + if (!PlatformDetection.IsReflectionEmitSupported || !PlatformDetection.IsRareEnumsSupported) return null; AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Name"), AssemblyBuilderAccess.Run); From 07359942f4203824e7d5f34d49dc29e8ded4fe41 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 13 Dec 2022 17:44:42 -0800 Subject: [PATCH 5/6] More fixes for rare enums --- .../System.Private.CoreLib/src/System/Enum.cs | 4 --- .../tests/CustomAttributeBuilderTests.cs | 29 ++++++++++++------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 6878616b15f33..1dad9e19d99f1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -1185,13 +1185,10 @@ internal static ulong ToUInt64(object value) case TypeCode.Int64: return (ulong)(long)value; case TypeCode.UInt32: return (uint)value; case TypeCode.UInt64: return (ulong)value; -#if RARE_ENUMS case TypeCode.Char: return (char)value; case TypeCode.Boolean: return (bool)value ? 1UL : 0UL; -#endif }; -#if RARE_ENUMS if (value is not null) { Type valueType = value.GetType(); @@ -1203,7 +1200,6 @@ internal static ulong ToUInt64(object value) if (valueType == typeof(nint)) return (ulong)(nint)value; if (valueType == typeof(nuint)) return (nuint)value; } -#endif throw CreateUnknownEnumTypeException(); } diff --git a/src/libraries/System.Reflection.Emit.ILGeneration/tests/CustomAttributeBuilderTests.cs b/src/libraries/System.Reflection.Emit.ILGeneration/tests/CustomAttributeBuilderTests.cs index 60e319982fd29..b349b1796d587 100644 --- a/src/libraries/System.Reflection.Emit.ILGeneration/tests/CustomAttributeBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit.ILGeneration/tests/CustomAttributeBuilderTests.cs @@ -577,14 +577,20 @@ public static void NullConstructorArgs_ThrowsArgumentNullException() public static IEnumerable NotSupportedObject_Constructor_TestData() { yield return new object[] { new int[0, 0] }; - yield return new object[] { Enum.GetValues(CreateEnum(typeof(char), 'a')).GetValue(0) }; - yield return new object[] { Enum.GetValues(CreateEnum(typeof(bool), true)).GetValue(0) }; + if (PlatformDetection.IsRareEnumsSupported) + { + yield return new object[] { Enum.GetValues(CreateEnum(typeof(char), 'a')).GetValue(0) }; + yield return new object[] { Enum.GetValues(CreateEnum(typeof(bool), true)).GetValue(0) }; + } } public static IEnumerable FloatEnum_DoubleEnum_TestData() { - yield return new object[] { Enum.GetValues(CreateEnum(typeof(float), 0.0f)).GetValue(0) }; - yield return new object[] { Enum.GetValues(CreateEnum(typeof(double), 0.0)).GetValue(0) }; + if (PlatformDetection.IsRareEnumsSupported) + { + yield return new object[] { Enum.GetValues(CreateEnum(typeof(float), 0.0f)).GetValue(0) }; + yield return new object[] { Enum.GetValues(CreateEnum(typeof(double), 0.0)).GetValue(0) }; + } } public static IEnumerable NotSupportedObject_Others_TestData() @@ -639,12 +645,15 @@ public static IEnumerable InvalidAttributeTypes_TestData() { yield return new object[] { typeof(Guid), new Guid() }; yield return new object[] { typeof(int[,]), new int[5, 5] }; - yield return new object[] { CreateEnum(typeof(char), 'a'), 'a' }; - yield return new object[] { CreateEnum(typeof(bool), false), true }; - yield return new object[] { CreateEnum(typeof(float), 1.0f), 1.0f }; - yield return new object[] { CreateEnum(typeof(double), 1.0), 1.0 }; - yield return new object[] { CreateEnum(typeof(IntPtr)), (IntPtr)1 }; - yield return new object[] { CreateEnum(typeof(UIntPtr)), (UIntPtr)1 }; + if (PlatformDetection.IsRareEnumsSupported) + { + yield return new object[] { CreateEnum(typeof(char), 'a'), 'a' }; + yield return new object[] { CreateEnum(typeof(bool), false), true }; + yield return new object[] { CreateEnum(typeof(float), 1.0f), 1.0f }; + yield return new object[] { CreateEnum(typeof(double), 1.0), 1.0 }; + yield return new object[] { CreateEnum(typeof(IntPtr)), (IntPtr)1 }; + yield return new object[] { CreateEnum(typeof(UIntPtr)), (UIntPtr)1 }; + } } [Theory] From f6efccf0fffbd8abeaf127171513549ee0b4ea70 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 14 Dec 2022 08:30:43 -0800 Subject: [PATCH 6/6] Re-enable rare enums for Mono --- .../Common/tests/TestUtilities/System/PlatformDetection.cs | 2 +- src/libraries/System.Private.CoreLib/src/System/Enum.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index c0e677ddcb873..40474e2bdb8ea 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -189,7 +189,7 @@ private static bool GetLinqExpressionsBuiltWithIsInterpretingOnly() public static bool IsPreciseGcSupported => !IsMonoRuntime; - public static bool IsRareEnumsSupported => !IsNativeAot && !IsMonoRuntime; + public static bool IsRareEnumsSupported => !IsNativeAot; public static bool IsNotIntMaxValueArrayIndexSupported => s_largeArrayIsNotSupported.Value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 1dad9e19d99f1..22a796426a901 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // Rare enums types not expressible in C# are not supported in native AOT -#if !NATIVEAOT && !MONO +#if !NATIVEAOT #define RARE_ENUMS #endif