Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle explicit conversions between enums and native integers #48041

Merged
merged 8 commits into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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