Skip to content

Commit

Permalink
PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
333fred committed Jul 20, 2022
1 parent cc0fc20 commit 17d61ef
Show file tree
Hide file tree
Showing 4 changed files with 383 additions and 22 deletions.
16 changes: 4 additions & 12 deletions src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ private static BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSy
convertedType = inputType;
}

if ((constantValueOpt?.IsNumeric == true) && HasBlockedINumberConversion(patternConversion, inputType))
if ((constantValueOpt?.IsNumeric == true) && ShouldBlockINumberBaseConversion(patternConversion, inputType))
{
// Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
diagnostics.Add(ErrorCode.ERR_CannotMatchOnINumberBase, node.Location, inputType);
Expand All @@ -437,7 +437,7 @@ private static BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSy
}
}

private bool HasBlockedINumberConversion(Conversion patternConversion, TypeSymbol inputType)
private bool ShouldBlockINumberBaseConversion(Conversion patternConversion, TypeSymbol inputType)
{
// We want to block constant and relation patterns that have an input type constrained to or inherited from INumberBase<T>, if we don't
// know how to represent the constant being matched against in the input type. For example, `1.0 is 1` will work when written inline, but
Expand All @@ -449,16 +449,8 @@ private bool HasBlockedINumberConversion(Conversion patternConversion, TypeSymbo
return false;
}

var iNumberBase = Compilation.GetWellKnownType(WellKnownType.System_Numerics_INumberBase_T);

if (iNumberBase.IsErrorType())
{
return false;
}

var interfaces = inputType is TypeParameterSymbol typeParam ? typeParam.EffectiveInterfacesNoUseSiteDiagnostics : inputType.AllInterfacesNoUseSiteDiagnostics;
return interfaces.Any(static (i, iNumberBase) => i.OriginalDefinition.Equals(iNumberBase, TypeCompareKind.AllIgnoreOptions), iNumberBase)
|| inputType.OriginalDefinition.Equals(iNumberBase, TypeCompareKind.AllIgnoreOptions);
return interfaces.Any(static (i, _) => i.IsWellKnownINumberBaseType(), 0) || inputType.IsWellKnownINumberBaseType();
}

private static ExpressionSyntax SkipParensAndNullSuppressions(ExpressionSyntax e, BindingDiagnosticBag diagnostics, ref bool hasErrors)
Expand Down Expand Up @@ -1663,7 +1655,7 @@ void addSubpatternsForTuple(ImmutableArray<TypeWithAnnotations> elementTypes)
constantValueOpt = ConstantValue.Bad;
}

if (!hasErrors && HasBlockedINumberConversion(patternConversion, inputType))
if (!hasErrors && ShouldBlockINumberBaseConversion(patternConversion, inputType))
{
// Cannot use a numeric constant or relational pattern on '{0}' because it inherits from or extends 'INumberBase&lt;T&gt;'. Consider using a type pattern to narrow to a specific numeric type.
diagnostics.Add(ErrorCode.ERR_CannotMatchOnINumberBase, node.Location, inputType);
Expand Down
26 changes: 21 additions & 5 deletions src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2060,18 +2060,34 @@ internal static bool IsCompilerServicesTopLevelType(this TypeSymbol typeSymbol)
internal static bool IsWellKnownSetsRequiredMembersAttribute(this TypeSymbol type)
=> type.Name == "SetsRequiredMembersAttribute" && type.IsWellKnownDiagnosticsCodeAnalysisTopLevelType();

internal static bool IsWellKnownINumberBaseType(this TypeSymbol type)
{
type = type.OriginalDefinition;
return type is NamedTypeSymbol { Name: "INumberBase", IsInterface: true, Arity: 1, ContainingType: null } &&
IsContainedInNamespace(type, "System", "Numerics");
}

private static bool IsWellKnownDiagnosticsCodeAnalysisTopLevelType(this TypeSymbol typeSymbol)
=> typeSymbol.ContainingType is null && IsContainedInNamespace(typeSymbol, "System", "Diagnostics", "CodeAnalysis");

private static bool IsContainedInNamespace(this TypeSymbol typeSymbol, string outerNS, string midNS, string innerNS)
private static bool IsContainedInNamespace(this TypeSymbol typeSymbol, string outerNS, string midNS, string? innerNS = null)
{
var innerNamespace = typeSymbol.ContainingNamespace;
if (innerNamespace?.Name != innerNS)
NamespaceSymbol? midNamespace;

if (innerNS != null)
{
return false;
var innerNamespace = typeSymbol.ContainingNamespace;
if (innerNamespace?.Name != innerNS)
{
return false;
}
midNamespace = innerNamespace.ContainingNamespace;
}
else
{
midNamespace = typeSymbol.ContainingNamespace;
}

var midNamespace = innerNamespace.ContainingNamespace;
if (midNamespace?.Name != midNS)
{
return false;
Expand Down
Loading

0 comments on commit 17d61ef

Please sign in to comment.