Skip to content

Commit

Permalink
Handle explicit conversions between enums and native integers (#48041)
Browse files Browse the repository at this point in the history
  • Loading branch information
cston authored Sep 30, 2020
1 parent c2a866c commit 1c155c5
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,7 @@ private Conversion ClassifyExplicitOnlyConversionFromExpression(BoundExpression
return GetExplicitUserDefinedConversion(sourceExpression, sourceType, destination, ref useSiteDiagnostics);
}

#nullable enable
private static bool HasImplicitEnumerationConversion(BoundExpression source, TypeSymbol destination)
{
Debug.Assert((object)source != null);
Expand All @@ -1239,9 +1240,11 @@ private static bool HasImplicitEnumerationConversion(BoundExpression source, Typ

var sourceConstantValue = source.ConstantValue;
return sourceConstantValue != null &&
IsNumericType(source.Type.GetSpecialTypeSafe()) &&
source.Type is object &&
IsNumericType(source.Type) &&
IsConstantNumericZero(sourceConstantValue);
}
#nullable disable

private static LambdaConversionResult IsAnonymousFunctionCompatibleWithDelegate(UnboundLambda anonymousFunction, TypeSymbol type)
{
Expand Down Expand Up @@ -1785,6 +1788,7 @@ private static int GetNumericTypeIndex(SpecialType specialType)
}
}

#nullable enable
private static bool HasImplicitNumericConversion(TypeSymbol source, TypeSymbol destination)
{
Debug.Assert((object)source != null);
Expand Down Expand Up @@ -1827,7 +1831,7 @@ private static bool HasExplicitNumericConversion(TypeSymbol source, TypeSymbol d
return s_explicitNumericConversions[sourceIndex, destinationIndex];
}

public static bool IsConstantNumericZero(ConstantValue value)
private static bool IsConstantNumericZero(ConstantValue value)
{
switch (value.Discriminator)
{
Expand All @@ -1838,12 +1842,14 @@ public static bool IsConstantNumericZero(ConstantValue value)
case ConstantValueTypeDiscriminator.Int16:
return value.Int16Value == 0;
case ConstantValueTypeDiscriminator.Int32:
case ConstantValueTypeDiscriminator.NInt:
return value.Int32Value == 0;
case ConstantValueTypeDiscriminator.Int64:
return value.Int64Value == 0;
case ConstantValueTypeDiscriminator.UInt16:
return value.UInt16Value == 0;
case ConstantValueTypeDiscriminator.UInt32:
case ConstantValueTypeDiscriminator.NUInt:
return value.UInt32Value == 0;
case ConstantValueTypeDiscriminator.UInt64:
return value.UInt64Value == 0;
Expand All @@ -1856,9 +1862,9 @@ public static bool IsConstantNumericZero(ConstantValue value)
return false;
}

public static bool IsNumericType(SpecialType specialType)
private static bool IsNumericType(TypeSymbol type)
{
switch (specialType)
switch (type.SpecialType)
{
case SpecialType.System_Char:
case SpecialType.System_SByte:
Expand All @@ -1872,6 +1878,8 @@ public static bool IsNumericType(SpecialType specialType)
case SpecialType.System_Single:
case SpecialType.System_Double:
case SpecialType.System_Decimal:
case SpecialType.System_IntPtr when type.IsNativeIntegerType:
case SpecialType.System_UIntPtr when type.IsNativeIntegerType:
return true;
default:
return false;
Expand Down Expand Up @@ -1970,16 +1978,16 @@ private static bool HasExplicitEnumerationConversion(TypeSymbol source, TypeSymb
Debug.Assert((object)destination != null);

// SPEC: The explicit enumeration conversions are:
// SPEC: From sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, or decimal to any enum-type.
// SPEC: From any enum-type to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, or decimal.
// SPEC: From sbyte, byte, short, ushort, int, uint, long, ulong, nint, nuint, char, float, double, or decimal to any enum-type.
// SPEC: From any enum-type to sbyte, byte, short, ushort, int, uint, long, ulong, nint, nuint, char, float, double, or decimal.
// SPEC: From any enum-type to any other enum-type.

if (IsNumericType(source.SpecialType) && destination.IsEnumType())
if (IsNumericType(source) && destination.IsEnumType())
{
return true;
}

if (IsNumericType(destination.SpecialType) && source.IsEnumType())
if (IsNumericType(destination) && source.IsEnumType())
{
return true;
}
Expand All @@ -1991,6 +1999,7 @@ private static bool HasExplicitEnumerationConversion(TypeSymbol source, TypeSymb

return false;
}
#nullable disable

private Conversion ClassifyImplicitNullableConversion(TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ internal static bool ContainsOnlyEmptyConstraintClauses(this ImmutableArray<Type
}

// Returns true if constraintClauses was updated with value.
// Returns false if constraintClauses already had a value with expected 'IgnoresNullableContext'
// or was updated to a value with the expected 'IgnoresNullableContext' value on another thread.
// Returns false if constraintClauses already had a value with sufficient 'IgnoresNullableContext'
// or was updated to a value with sufficient 'IgnoresNullableContext' on another thread.
internal static bool InterlockedUpdate(ref ImmutableArray<TypeParameterConstraintClause> constraintClauses, ImmutableArray<TypeParameterConstraintClause> value)
{
bool canIgnoreNullableContext = value.IgnoresNullableContext();
Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ internal static bool HasValue(this TypeParameterBounds? boundsOpt, bool canIgnor
}

// Returns true if bounds was updated with value.
// Returns false if bounds already had a value with expected 'IgnoresNullableContext'
// or was updated to a value with the expected 'IgnoresNullableContext' value on another thread.
// Returns false if bounds already had a value with sufficient 'IgnoresNullableContext'
// or was updated to a value with sufficient 'IgnoresNullableContext' on another thread.
internal static bool InterlockedUpdate(ref TypeParameterBounds? bounds, TypeParameterBounds? value)
{
bool canIgnoreNullableContext = (value?.IgnoresNullableContext == true);
Expand Down
Loading

0 comments on commit 1c155c5

Please sign in to comment.