Skip to content

Preserve nullable typing for ignored null-conditional access in coalesce expressions#212

Merged
PhenX merged 3 commits into
masterfrom
copilot/fix-null-coalesce-issue
May 31, 2026
Merged

Preserve nullable typing for ignored null-conditional access in coalesce expressions#212
PhenX merged 3 commits into
masterfrom
copilot/fix-null-coalesce-issue

Conversation

Copilot AI commented May 28, 2026

Copy link
Copy Markdown
Contributor

NullConditionalRewriteSupport.Ignore currently strips ?. to direct member access, which breaks ?? when the left side was originally nullable (e.g. Price?.Amount ?? 0m becoming Price.Amount ?? 0m). This causes invalid generated code (decimal ?? decimal).

  • Generator fix: typed rewrite for ?? left operand

    • Updated ExpressionSyntaxRewriter null-conditional ignore path to detect when a conditional access is the left operand of a coalesce.
    • If the original converted type is Nullable<T> and the rewritten member/index access is T, the generator now emits an explicit cast to Nullable<T>.
  • Scope control

    • The nullable cast is applied only in coalesce-left contexts to avoid changing existing ignore semantics in non-coalesce expressions.
  • Regression coverage

    • Added NullConditionalNullCoalesceTypeConversion_WithIgnoreSupport in NullableTests.
    • Added corresponding snapshot to assert nullable cast emission in generated expression code.
// source
[Projectable(AllowBlockBody = true, NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)]
public decimal GetCost() => Price?.Amount ?? 0m;

// generated (relevant part)
return (global::Product @this) => (decimal? )(@this.Price.Amount) ?? 0m;

Copilot AI linked an issue May 28, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix null coalesce operator in GetCost method Preserve nullable typing for ignored null-conditional access in coalesce expressions May 28, 2026
Copilot finished work on behalf of PhenX May 28, 2026 15:30
Copilot AI requested a review from PhenX May 28, 2026 15:30
@PhenX
PhenX marked this pull request as ready for review May 28, 2026 16:09
@PhenX
PhenX requested a review from Copilot May 28, 2026 16:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the generator’s null-conditional ignore rewrite so nullable value typing is preserved for simple ?? left operands, preventing invalid generated expressions like decimal ?? decimal.

Changes:

  • Adds nullable cast emission when an ignored conditional access feeds directly into a coalesce expression.
  • Adds a regression generator test and verified snapshot for Price?.Amount ?? 0m.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/EntityFrameworkCore.Projectables.Generator/SyntaxRewriters/ExpressionSyntaxRewriter.NullConditionalRewrite.cs Adds coalesce-left detection and nullable cast generation for ignored null-conditional access.
tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.cs Adds regression coverage for ignored null-conditional access with ??.
tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullConditionalNullCoalesceTypeConversion_WithIgnoreSupport.verified.txt Adds the expected generated expression snapshot.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@PhenX
PhenX merged commit a23efdf into master May 31, 2026
4 checks passed
github-merge-queue Bot pushed a commit to DFE-Digital/teaching-record-system that referenced this pull request Jul 22, 2026
Updated
[EntityFrameworkCore.Projectables](https://github.com/EFNext/EntityFrameworkCore.Projectables)
from 6.0.4 to 6.0.6.

<details>
<summary>Release notes</summary>

_Sourced from [EntityFrameworkCore.Projectables's
releases](https://github.com/EFNext/EntityFrameworkCore.Projectables/releases)._

## 6.0.6

## What's Changed
* Preserve nullable typing for ignored null-conditional access in
coalesce expressions by @​PhenX with @​Copilot in
EFNext/EntityFrameworkCore.Projectables#212
* Fix duplicate joins when materializing writable projectables with
includes by @​PhenX in
EFNext/EntityFrameworkCore.Projectables#218


**Full Changelog**:
EFNext/EntityFrameworkCore.Projectables@v6.0.5...v6.0.6

## 6.0.5

## What's Changed
* Fix source generator crash when parameter type uses verbatim @ keyword
prefix by @​Copilot in
EFNext/EntityFrameworkCore.Projectables#208


**Full Changelog**:
EFNext/EntityFrameworkCore.Projectables@v6.0.4...v6.0.5

Commits viewable in [compare
view](EFNext/EntityFrameworkCore.Projectables@v6.0.4...v6.0.6).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=EntityFrameworkCore.Projectables&package-manager=nuget&previous-version=6.0.4&new-version=6.0.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Gunn <james@gunn.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Null coalesce not working

3 participants