-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix unexpected conditional state in nullable analysis of conditional access #78439
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 unexpected conditional state in nullable analysis of conditional access #78439
Conversation
|
|
||
| // Per LDM 2019-02-13 decision, the result of a conditional access "may be null" even if | ||
| // both the receiver and right-hand-side are believed not to be null. | ||
| UnsplitIfNeeded(resultType); |
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.
Do we understand why we are left in a conditional state?
We analyze the call ""?.M1(x) and since M1 has post-condition on the argument, it leaves us in conditional state.
Could you explain why do you think this is the right place for the fix?
VisitConditionalAccess needs to set a result type to maybe-null. The assert in SetResultType says we can call it in conditional state only for bools (which makes sense, other types cannot be conditional). So calling UnsplitIfNeeded beforehand ensures we are not in conditional state when the type is not bool.
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 1)
|
|
||
| // Per LDM 2019-02-13 decision, the result of a conditional access "may be null" even if | ||
| // both the receiver and right-hand-side are believed not to be null. | ||
| UnsplitIfNeeded(resultType); |
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 thought if we are analyzing "a"?.M1(x), and M1 returns bool, then resultType is bool? here. So why would we ever keep in a split state at this point? Would we achieve the correct behavior more simply if we just always called Unsplit() after the VisitPossibleConditionalAccess on L5928 (the non-null-const receiver case)?
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.
Sounds good, let me try that. Thanks.
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.
Turns out it is not easy to move UnsplitIfNeeded into the if above - we don't know the resultType there (the bool?) we only know LvalueResultType but that's bool. We would need to compute the resultType sooner, and in two places. Which seems unnecessary - we can just leave the UnsplitIfNeeded here where it is.
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 don’t think we should need or use the resultType with the normal Unsplit. But, if the suggestion didn’t work out, I’m ok with the current implementation. Thanks!
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.
Right, sorry, I misread your original suggestion, it makes sense, let me try that.
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.
Solution seems reasonable to me, but wanted to check if we could simplify a bit further.
* upstream/main: (415 commits) Use lazy initialization for members in CodeFixService (dotnet#78484) Targeted perf changes to CommandLineParser (dotnet#78446) Exclude VS.ExternalAPIs.Roslyn.Package from source-build Add syntax highlighting of ignored directives (dotnet#78458) Fix unexpected conditional state in nullable analysis of conditional access (dotnet#78439) Update RoslynAnalyzers to use Roslyns version Fix source-build by renaming Assets folder to assets Unlist M.CA.AnalyzerUtilities as an expected DevDivInsertion dependency Use a project reference for M.CA.AnalyzerUtilities Rectify status of dictionary expressions (dotnet#78497) Remove unused field Remove unused field Remove using Fix check Update eng/config/PublishData.json Make internal Remove now unused methods from IWorkspaceProjectContext (dotnet#78479) Reduce allocations during SourceGeneration (dotnet#78403) Update Roslyn.sln Merge EditorFeatures.Wpf entirely into EditorFeatures ...
Fixes #78386.