-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Visit binary operators in ref safety analysis #73081
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
Conversation
e943f8f to
e7f5146
Compare
| } | ||
|
|
||
| #if DEBUG | ||
| private void VisitCore(BoundNode? node) |
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.
Given this method is only used for assertion purposes did you consider giving it an assert style named and making it conditional on DEBUG? For example:
[Conditional("DEBUG")]
private void AssertVisitCore(BoundNode? node)
``` #ResolvedThere 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.
Making it just Conditional would fail to compile as it uses _visited field which is only available #if DEBUG.
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.
Can use an #if DEBUG within the method too. Personally I find the code easier to process when minimize the number of directives, particularly for call sites. Will defer to others here.
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.
In this case, there are only a couple of call sites, so I think I prefer the explicit-ness of #if DEBUG at the declaration and at the call sites so it's clear at the callers that there is no impact on RELEASE builds.
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.
My first choice in a situation like this will be to rely on conditional compilation vs. the attribute. It completely eliminates the method (including in produced metadata) for release build. Whereas the attribute doesn't have this effect. In my opinion the attribute is useful when we deal with a public API, which is not the case here.
| } | ||
|
|
||
| #if DEBUG | ||
| private void VisitCore(BoundNode? node) |
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 think we should use a name that clearly indicates the purpose of this method. "VisitCore" doesn't tell to me that the purpose is to perform some debug time validation. Quite the opposite, it tells me the method performs some critical task and it is surprising to see that it not called in release build. #Closed
| { | ||
| this.Visit(op.Right); | ||
| #if DEBUG | ||
| this.VisitCore(op); |
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 looks like, If we were not overriding BoundTreeWalker.VisitBinaryOperator, we would be calling VisitCore for each parent, before visiting any child. It also looks like this is not what this method is doing. It looks like it visits children and then calls VisitCore for the parent. I think that manual stack management should preserve the regular order of operations. #Closed
| } | ||
|
|
||
| // Unlike the base implementation, we want to visit all the nodes, not just the operands. | ||
| public override BoundNode? VisitBinaryOperator(BoundBinaryOperator node) |
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 do not see any good reason to use drastically different algorithm in this method by comparison to BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator.VisitBinaryOperator implementation. This could be explained by desire to call VisitCore on the way "out" rather than on the way "in", but I think we actually want to do that the other way. #Closed
At the very least, I think we should call Refers to: src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs:708 in e7f5146. [](commit_id = e7f5146, deletion_comment = False) |
|
Done with review pass (commit 2) |
As a better alternative to overriding this method in derived type and duplicating the stack management process, I think we can add a protected virtual method called "BeforeVisitingSkippedBoundBinaryOperatorChildren" or something like that and do Refers to: src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs:117 in e7f5146. [](commit_id = e7f5146, deletion_comment = False) |
Similar to Refers to: src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs:150 in e7f5146. [](commit_id = e7f5146, deletion_comment = False) |
AlekseyTs
left a comment
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 3)
These tests verify that issue dotnet#63852 is fixed. It was very likely fixed as part of dotnet#73081 closes dotnet#63852
These tests verify that issue dotnet#63852 is fixed. It was very likely fixed as part of dotnet#73081 closes dotnet#63852
* Tests to verify ref safety bug fix These tests verify that issue #63852 is fixed. It was very likely fixed as part of #73081 closes #63852 * formatting issue * Apply suggestions from code review Co-authored-by: Jan Jones <[email protected]> --------- Co-authored-by: Jan Jones <[email protected]>
Alternative to #72935.
Fixes #72873.