-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Fix regression of LambdaSymbol.GetHashCode #58247
Conversation
@@ -384,7 +384,7 @@ static bool areEqual(SyntaxReference a, SyntaxReference b) | |||
|
|||
public override int GetHashCode() | |||
{ | |||
return syntaxReferenceOpt.GetHashCode(); | |||
return Syntax.GetHashCode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Youssef1313.
This looks distinct from Equals()
which is checking the fields of syntaxReferenceOpt
. Should Equals()
be reverted as well, to check lambda.Syntax == Syntax
instead of checking syntaxReferenceOpt
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cston I think both should work the same. I'll go with lambda.Syntax == Syntax
. It's more clear, and is the original behavior before the lambda improvements work.
&& lambda._syntax == _syntax |
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
return syntaxReferenceOpt.GetHashCode(); | ||
return Syntax.GetHashCode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is Syntax.GetHashCode()
guaranteed to return the same value each time given that Syntax
is implemented as syntaxReferenceOpt.GetSyntax()
?
If we want to use the Syntax
for GetHashCode()
and Equals()
, then LambdaSymbol
should probably hold onto the SyntaxNode
in a readonly
field instead. Otherwise GetHashCode()
and Equals()
should rely on the fields of syntaxReferenceOpt
rather than syntaxReferenceOpt.GetSyntax()
.
For the latter approach, perhaps:
public override int GetHashCode()
{
return Hash.Combine(
syntaxReferenceOpt.SyntaxTree.GetHashCode(),
syntaxReferenceOpt.Span.GetHashCode());
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cston From the unit test, it seems to be working as expected. But I'm okay with either holding Syntax
as a _syntax
field, or implementing it using SyntaxReference.SyntaxTree|Span
.
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
return syntaxReferenceOpt.GetHashCode(); | ||
return Syntax.GetHashCode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is where the root cause of the problem was. SyntaxReference uses reference equality, therefore distinct syntax references almost always have different hash code. If this is correct, then I think we should simply align this implementation with the original implementation of Equals
. I.e. combine hash codes of the tree and span and revert changes to the Equals
. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlekseyTs It was exactly my intention to keep the original implementation. The changes that used the tree and the span along the GetHashCode
change were all introduced in #52178. This simply reverts this small portion of #52178. I'm okay with any of the suggested approaches by you or @cston
I just wanted to point out to #52178 since this is what took me this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was exactly my intention to keep the original implementation.
When I said "original", I meant "original" in context of this PR. And the suggestion to revert Equals
is also in context of changes made in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify. I think that we shouldn't change Equals
in this PR and should simply align implementation of GetHashCode
with what Equals
is doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlekseyTs Thanks. Fixed.
My initial thought was to keep the implementation that has been working for years, but I can also see this is not necessarily correct (ie, it may have changed for a good reason).
Though for this PR, it's likely both implementations will work equivalently anyway, so keeping Equals
as-is and do minimal change in GetHashCode
does make more sense.
Thanks again :)
Done with review pass (commit 2) |
@@ -384,7 +384,7 @@ | |||
|
|||
public override int GetHashCode() | |||
{ | |||
return syntaxReferenceOpt.GetHashCode(); | |||
return HashCode.Combine(syntaxReferenceOpt.SyntaxTree, syntaxReferenceOpt.Span); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with review pass (commit 3). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Youssef1313!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (commit 4)
It looks like there are related test failures with distinct For instance, var q = from i in new int[] { 4, 5 } where /*pos*/ which results in LambdaSymbols for the The simplest solution may be to add back the |
I do not think going back to an extra field is necessary. The correctness problem in the |
Let's add back the @Youssef1313, please add back |
Can the Refers to: src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs:268 in a8122f7. [](commit_id = a8122f7, deletion_comment = False) |
var syntaxRefs = lambdas.SelectAsArray(l => l.SyntaxRef); | ||
Assert.Equal(syntaxRefs[0].Span, syntaxRefs[1].Span); | ||
Assert.NotEqual(lambdas[0], lambdas[1]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Youssef1313, it looks like a couple of namespaces are missing:
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Operations;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what happens when I edit via GitHub directly 😄
var lambdas = operation.Descendants().OfType<AnonymousFunctionOperation>(). | ||
Select(op => op.Symbol.GetSymbol<LambdaSymbol>()).ToImmutableArray(); | ||
Assert.Equal(2, lambdas.Length); | ||
var syntaxRefs = lambdas.SelectAsArray(l => l.SyntaxRef); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (commit 9)
@Youssef1313 Thank you for the contribution. |
…rations * upstream/main: (87 commits) Add support for nullable analysis in interpolated string handler constructors (dotnet#57780) Record list-patterns and newlines in interpolations as done (dotnet#58250) Swithc to acquiring the component model on a BG thread. Fix failure to propagate cancellation token [main] Update dependencies from dotnet/arcade (dotnet#58327) Change PROTOTYPE to issue reference (dotnet#58336) Resolve PROTOTYPE comments in param null checking (dotnet#58324) Address various minor param-nullchecking issues (dotnet#58321) Nullable enable GetTypeByMetadataName (dotnet#58317) Support CodeClass2.Parts returning parts in source generated files Allow the FileCodeModel.Parent to be null Ensure the CodeModel tests are using VisualStudioWorkspaceImpl Fix the bad words in TestDeepAlternation Fix regression in Equals/GetHashCode of LambdaSymbol. (dotnet#58247) Support "Enable nullable reference types" from disable keyword Support "Enable nullable reference types" from restore keyword Support "Enable nullable reference types" on the entire directive Add comment Remove descriptor Update src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs ...
Fixes #58226