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

Implement IEquatable<T> in record types #44994

Merged
merged 9 commits into from
Jun 11, 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
1 change: 0 additions & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,6 @@ private static void LookupMembersInInterfaceOnly(
LookupMembersInInterfacesWithoutInheritance(current, GetBaseInterfaces(type, basesBeingResolved, ref useSiteDiagnostics),
name, arity, basesBeingResolved, options, originalBinder, accessThroughType, diagnose, ref useSiteDiagnostics);
}

}

private static ImmutableArray<NamedTypeSymbol> GetBaseInterfaces(NamedTypeSymbol type, ConsList<TypeSymbol> basesBeingResolved, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,11 @@ private ImmutableArray<SynthesizedExplicitImplementationForwardingMethod> Comput

if (useSiteDiagnostic != null && useSiteDiagnostic.DefaultSeverity == DiagnosticSeverity.Error)
{
diagnostics.Add(useSiteDiagnostic, GetImplementsLocation(@interface));
diagnostics.Add(useSiteDiagnostic, GetImplementsLocationOrFallback(@interface));
}
else
{
diagnostics.Add(ErrorCode.ERR_UnimplementedInterfaceMember, GetImplementsLocation(@interface) ?? this.Locations[0], this, interfaceMember);
diagnostics.Add(ErrorCode.ERR_UnimplementedInterfaceMember, GetImplementsLocationOrFallback(@interface), this, interfaceMember);
}
}
}
Expand All @@ -277,7 +277,7 @@ private ImmutableArray<SynthesizedExplicitImplementationForwardingMethod> Comput
break;

case HasBaseTypeDeclaringInterfaceResult.IgnoringNullableMatch:
diagnostics.Add(ErrorCode.WRN_NullabilityMismatchInInterfaceImplementedByBase, GetImplementsLocation(@interface) ?? this.Locations[0], this, interfaceMember);
diagnostics.Add(ErrorCode.WRN_NullabilityMismatchInInterfaceImplementedByBase, GetImplementsLocationOrFallback(@interface), this, interfaceMember);
break;

default:
Expand Down Expand Up @@ -324,7 +324,14 @@ private ImmutableArray<SynthesizedExplicitImplementationForwardingMethod> Comput

protected abstract Location GetCorrespondingBaseListLocation(NamedTypeSymbol @base);

internal Location GetImplementsLocation(NamedTypeSymbol implementedInterface)
#nullable enable
private Location GetImplementsLocationOrFallback(NamedTypeSymbol implementedInterface)
{
return GetImplementsLocation(implementedInterface) ?? this.Locations[0];
}

internal Location? GetImplementsLocation(NamedTypeSymbol implementedInterface)
#nullable restore
{
// We ideally want to identify the interface location in the base list with an exact match but
// will fall back and use the first derived interface if exact interface is not present.
Expand Down Expand Up @@ -1381,6 +1388,8 @@ private static bool OverrideHasCorrectAccessibility(Symbol overridden, Symbol ov
}
}

#nullable enable

/// <summary>
/// It is invalid for a type to directly (vs through a base class) implement two interfaces that
/// unify (i.e. are the same for some substitution of type parameters).
Expand Down Expand Up @@ -1423,7 +1432,7 @@ private void CheckInterfaceUnification(DiagnosticBag diagnostics)
TypeSymbol.Equals(interface1.OriginalDefinition, interface2.OriginalDefinition, TypeCompareKind.ConsiderEverything2) &&
interface1.CanUnifyWith(interface2))
{
if (GetImplementsLocation(interface1).SourceSpan.Start > GetImplementsLocation(interface2).SourceSpan.Start)
if (GetImplementsLocationOrFallback(interface1).SourceSpan.Start > GetImplementsLocationOrFallback(interface2).SourceSpan.Start)
{
// Mention interfaces in order of their appearance in the base list, for consistency.
var temp = interface1;
Expand All @@ -1437,6 +1446,8 @@ private void CheckInterfaceUnification(DiagnosticBag diagnostics)
}
}

#nullable restore

/// <summary>
/// Though there is a method that C# considers to be an implementation of the interface method, that
/// method may not be considered an implementation by the CLR. In particular, implicit implementation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,16 @@ private Tuple<NamedTypeSymbol, ImmutableArray<NamedTypeSymbol>> MakeDeclaredBase

HashSet<DiagnosticInfo> useSiteDiagnostics = null;

if (declaration.Kind == DeclarationKind.Record)
{
var type = DeclaringCompilation.GetWellKnownType(WellKnownType.System_IEquatable_T).Construct(this);
if (baseInterfaces.IndexOf(type, SymbolEqualityComparer.AllIgnoreOptions) < 0)
{
baseInterfaces.Add(type);
type.AddUseSiteDiagnostics(ref useSiteDiagnostics);
}
}

if ((object)baseType != null)
{
Debug.Assert(baseTypeLocation != null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ internal sealed class SymbolEqualityComparer : EqualityComparer<Symbol>

internal static readonly EqualityComparer<Symbol> ObliviousNullableModifierMatchesAny = new SymbolEqualityComparer(TypeCompareKind.ObliviousNullableModifierMatchesAny);

internal static readonly EqualityComparer<Symbol> AllIgnoreOptions = new SymbolEqualityComparer(TypeCompareKind.AllIgnoreOptions);

internal static readonly EqualityComparer<Symbol> AllIgnoreOptionsPlusNullableWithUnknownMatchesAny =
new SymbolEqualityComparer(TypeCompareKind.AllIgnoreOptions & ~(TypeCompareKind.IgnoreNullableModifiersForReferenceTypes));

Expand Down
Loading