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

Simplify equivalence comparers #74932

Merged
merged 1 commit into from
Aug 28, 2024
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 @@ -13,37 +13,33 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities;

internal partial class SymbolEquivalenceComparer
{
private class EquivalenceVisitor(
private sealed class EquivalenceVisitor(
SymbolEquivalenceComparer symbolEquivalenceComparer,
bool compareMethodTypeParametersByIndex,
bool objectAndDynamicCompareEqually)
bool compareMethodTypeParametersByIndex)
{

public bool AreEquivalent(ISymbol? x, ISymbol? y, Dictionary<INamedTypeSymbol, INamedTypeSymbol>? equivalentTypesWithDifferingAssemblies)
{
if (ReferenceEquals(x, y))
{
return true;
}

if (x == null || y == null)
{
return false;
}

var xKind = GetKindAndUnwrapAlias(ref x);
var yKind = GetKindAndUnwrapAlias(ref y);

// Normally, if they're different types, then they're not the same.
if (xKind != yKind)
{
// Special case. If we're comparing signatures then we want to compare 'object'
// and 'dynamic' as the same. However, since they're different types, we don't
// want to bail out using the above check.
if (objectAndDynamicCompareEqually)
// Special case. If we're comparing signatures then we want to compare 'object' and 'dynamic' as the
// same. However, since they're different types, we don't want to bail out using the above check.
if (symbolEquivalenceComparer._objectAndDynamicCompareEqually)
{
return (xKind == SymbolKind.DynamicType && IsObjectType(y)) ||
(yKind == SymbolKind.DynamicType && IsObjectType(x));
if ((xKind == SymbolKind.DynamicType && IsObjectType(y)) ||
(yKind == SymbolKind.DynamicType && IsObjectType(x)))
{
return true;
}
}

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,19 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities;

internal partial class SymbolEquivalenceComparer
{
private class GetHashCodeVisitor
private sealed class GetHashCodeVisitor
{
private readonly SymbolEquivalenceComparer _symbolEquivalenceComparer;
private readonly bool _compareMethodTypeParametersByIndex;
private readonly bool _objectAndDynamicCompareEqually;
private readonly Func<int, IParameterSymbol, int> _parameterAggregator;
private readonly Func<int, ISymbol, int> _symbolAggregator;

public GetHashCodeVisitor(
SymbolEquivalenceComparer symbolEquivalenceComparer,
bool compareMethodTypeParametersByIndex,
bool objectAndDynamicCompareEqually)
bool compareMethodTypeParametersByIndex)
{
_symbolEquivalenceComparer = symbolEquivalenceComparer;
_compareMethodTypeParametersByIndex = compareMethodTypeParametersByIndex;
_objectAndDynamicCompareEqually = objectAndDynamicCompareEqually;
_parameterAggregator = (acc, sym) => Hash.Combine(symbolEquivalenceComparer.ParameterEquivalenceComparer.GetHashCode(sym), acc);
_symbolAggregator = (acc, sym) => GetHashCode(sym, acc);
}
Expand All @@ -45,7 +42,7 @@ public int GetHashCode(ISymbol? x, int currentHash)
// want to bail out using the above check.

if (x.Kind == SymbolKind.DynamicType ||
(_objectAndDynamicCompareEqually && IsObjectType(x)))
(_symbolEquivalenceComparer._objectAndDynamicCompareEqually && IsObjectType(x)))
{
return Hash.Combine(GetNullableAnnotationsHashCode((ITypeSymbol)x), Hash.Combine(typeof(IDynamicTypeSymbol), currentHash));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities;

internal partial class SymbolEquivalenceComparer
{
internal class SignatureTypeSymbolEquivalenceComparer(SymbolEquivalenceComparer symbolEquivalenceComparer) : IEqualityComparer<ITypeSymbol?>
internal sealed class SignatureTypeSymbolEquivalenceComparer(SymbolEquivalenceComparer symbolEquivalenceComparer) : IEqualityComparer<ITypeSymbol?>
{
public bool Equals(ITypeSymbol? x, ITypeSymbol? y)
=> this.Equals(x, y, null);

public bool Equals(ITypeSymbol? x, ITypeSymbol? y, Dictionary<INamedTypeSymbol, INamedTypeSymbol>? equivalentTypesWithDifferingAssemblies)
=> symbolEquivalenceComparer.GetEquivalenceVisitor(compareMethodTypeParametersByIndex: true, symbolEquivalenceComparer._objectAndDynamicCompareEqually).AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);
=> symbolEquivalenceComparer.GetEquivalenceVisitor(compareMethodTypeParametersByIndex: true).AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);

public int GetHashCode(ITypeSymbol? x)
=> symbolEquivalenceComparer.GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: true, symbolEquivalenceComparer._objectAndDynamicCompareEqually).GetHashCode(x, currentHash: 0);
=> symbolEquivalenceComparer.GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: true).GetHashCode(x, currentHash: 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,18 @@ public SymbolEquivalenceComparer(
using var equivalenceVisitors = TemporaryArray<EquivalenceVisitor>.Empty;
using var getHashCodeVisitors = TemporaryArray<GetHashCodeVisitor>.Empty;

AddVisitors(compareMethodTypeParametersByIndex: true, objectAndDynamicCompareEqually: true);
AddVisitors(compareMethodTypeParametersByIndex: true, objectAndDynamicCompareEqually: false);
AddVisitors(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: true);
AddVisitors(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: false);
AddVisitors(compareMethodTypeParametersByIndex: true);
AddVisitors(compareMethodTypeParametersByIndex: false);

_equivalenceVisitors = equivalenceVisitors.ToImmutableAndClear();
_getHashCodeVisitors = getHashCodeVisitors.ToImmutableAndClear();

return;

void AddVisitors(bool compareMethodTypeParametersByIndex, bool objectAndDynamicCompareEqually)
void AddVisitors(bool compareMethodTypeParametersByIndex)
{
equivalenceVisitors.Add(new(this, compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually));
getHashCodeVisitors.Add(new(this, compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually));
equivalenceVisitors.Add(new(this, compareMethodTypeParametersByIndex));
getHashCodeVisitors.Add(new(this, compareMethodTypeParametersByIndex));
}
}

Expand All @@ -107,27 +105,21 @@ public static SymbolEquivalenceComparer Create(
// here. So, instead, when asking if parameters are equal, we pass an appropriate flag so
// that method type parameters are just compared by index and nothing else.
private EquivalenceVisitor GetEquivalenceVisitor(
bool compareMethodTypeParametersByIndex = false, bool objectAndDynamicCompareEqually = false)
bool compareMethodTypeParametersByIndex = false)
{
var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually);
var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex);
return _equivalenceVisitors[visitorIndex];
}

private GetHashCodeVisitor GetGetHashCodeVisitor(
bool compareMethodTypeParametersByIndex, bool objectAndDynamicCompareEqually)
bool compareMethodTypeParametersByIndex)
{
var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually);
var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex);
return _getHashCodeVisitors[visitorIndex];
}

private static int GetVisitorIndex(bool compareMethodTypeParametersByIndex, bool objectAndDynamicCompareEqually)
=> (compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually) switch
{
(true, true) => 0,
(true, false) => 1,
(false, true) => 2,
(false, false) => 3,
};
private static int GetVisitorIndex(bool compareMethodTypeParametersByIndex)
=> compareMethodTypeParametersByIndex ? 0 : 1;

public bool ReturnTypeEquals(IMethodSymbol x, IMethodSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol>? equivalentTypesWithDifferingAssemblies = null)
=> GetEquivalenceVisitor().ReturnTypesAreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);
Expand All @@ -154,7 +146,7 @@ private bool EqualsCore(ISymbol? x, ISymbol? y, Dictionary<INamedTypeSymbol, INa
=> GetEquivalenceVisitor().AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies);

public int GetHashCode(ISymbol? x)
=> GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: false).GetHashCode(x, currentHash: 0);
=> GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: false).GetHashCode(x, currentHash: 0);

private static ISymbol UnwrapAlias(ISymbol symbol)
=> symbol.IsKind(SymbolKind.Alias, out IAliasSymbol? alias) ? alias.Target : symbol;
Expand Down
Loading