Skip to content

Conversation

@jjonescz
Copy link
Member

@jjonescz jjonescz commented May 5, 2025

Fixes #78386.

@ghost ghost added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels May 5, 2025
@jjonescz jjonescz marked this pull request as ready for review May 5, 2025 13:17
@jjonescz jjonescz requested a review from a team as a code owner May 5, 2025 13:17

// 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);
Copy link
Contributor

@AlekseyTs AlekseyTs May 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UnsplitIfNeeded(resultType);

Do we understand why we are left in a conditional state? Could you explain why do you think this is the right place for the fix? #Closed

Copy link
Member Author

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.

@RikkiGibson RikkiGibson self-assigned this May 5, 2025
Copy link
Contributor

@AlekseyTs AlekseyTs left a 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);
Copy link
Member

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)?

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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!

Copy link
Member Author

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.

Copy link
Member

@RikkiGibson RikkiGibson left a 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.

@jjonescz jjonescz requested a review from RikkiGibson May 7, 2025 12:19
@jjonescz jjonescz merged commit d35aabd into dotnet:main May 8, 2025
24 checks passed
@jjonescz jjonescz deleted the 78386-NullableConditionalAssert branch May 8, 2025 09:53
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone May 8, 2025
333fred added a commit to 333fred/roslyn that referenced this pull request May 8, 2025
* 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
  ...
@RikkiGibson RikkiGibson modified the milestones: Next, 18.0 P1 Aug 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Assert in nullable state tracking

3 participants