Skip to content

Preserve short-circuiting in downlevel private logical assignments - #65335

Open
Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 3 commits into
mainfrom
copilot/downlevel-private-accessor-issue
Open

Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 3 commits into
mainfrom
copilot/downlevel-private-accessor-issue

Conversation

Copilot AI commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #65333

Analysis

Below ES2022, private logical assignments use arithmetic compound-assignment lowering: set(get() && value). This invokes the setter even when the assignment should short-circuit.

Fix

  • Lowering: Emit get() && set(value)—likewise for || and ??—while preserving single receiver evaluation and expression results.
  • Coverage: Add ES2015–ES2022 emit cases for instance/static accessors, wrapped targets, complex receivers, and non-writable members.

Copilot Checklist

I successfully ran the applicable command at the end of my session, and it completed without error:

  • npx hereby validate
  • npx hereby validate --api (for TypeScript API changes)

Copilot AI and others added 2 commits November 5, 2026 16:43
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix downlevel logical assignment on private accessors Preserve short-circuiting in downlevel private logical assignments Nov 5, 2026

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.

🟢 Approval recommended

No active review issues block approval of the private logical-assignment lowering change.

No open issues 🎉

What changed in this PR

Fixes #65333 by preserving short-circuit behavior when the native TypeScript compiler lowers private logical assignments below ES2022, preventing setter calls when no assignment should occur.

Changes:

  • Emits conditional private writes for &&=, ||=, and ??=, preserving single receiver evaluation and expression results.
  • Adds emit coverage for instance/static accessors, wrapped targets, complex receivers, and non-writable members.
  • Updates baselines for downlevel output while retaining native ES2022 syntax.
File Description
tsc/​testdata/​tests/​cases/​compiler/​privateAccessorLogicalAssignment.ts Adds regression cases across four targets.
tsc/​testdata/​baselines/​reference/​conformance/​nullishCoalescingAssignmentVsPrivateFieldsJsEmit1.js Updates expected conditional private-field writes.
tsc/​testdata/​baselines/​reference/​compiler/​privateAccessorLogicalAssignment(target=es2022).js Records preserved native logical assignments.
tsc/​testdata/​baselines/​reference/​compiler/​privateAccessorLogicalAssignment(target=es2021).js Records short-circuiting private helper calls.
tsc/​testdata/​baselines/​reference/​compiler/​privateAccessorLogicalAssignment(target=es2020).js Records lowered assignments with native nullish coalescing.
tsc/​testdata/​baselines/​reference/​compiler/​privateAccessorLogicalAssignment(target=es2015).js Records fully lowered assignments and nullish checks.
tsc/​internal/​transformers/​estransforms/​classfields.go Separates logical-assignment lowering from arithmetic compound assignments.

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Downlevel this.#x &&= v / ||= / ??= on a private accessor always calls the setter

3 participants