Skip to content

react_compiler: preserve E::UnaryFlags through codegen (delete/typeof Reference semantics) - #36741

Merged
Jarred-Sumner merged 6 commits into
mainfrom
farm/32740203/react-compiler-delete-flag
Aug 2, 2026
Merged

react_compiler: preserve E::UnaryFlags through codegen (delete/typeof Reference semantics)#36741
Jarred-Sumner merged 6 commits into
mainfrom
farm/32740203/react-compiler-delete-flag

react_compiler: preserve delete Reference semantics in codegen

438c5e0
Select commit
Loading
Failed to load commit list.
Claude / Claude Code Review completed Aug 1, 2026 in 20m 36s

Code review found 1 important issue

Found 3 candidates, confirmed 2. See review comments for details.

Details

Severity Count
🔴 Important 1
🟡 Nit 1
🟣 Pre-existing 0
Severity File:Line Issue
🔴 Important src/react_compiler/codegen.rs:1998-2003 Sibling bug class unfixed: typeof also loses UnaryFlags in react_compiler codegen
🟡 Nit src/react_compiler/codegen.rs:1998-2003 Comment premise is false; unconditional flag regresses delete-of-folded-conditional

Annotations

Check failure on line 2003 in src/react_compiler/codegen.rs

See this annotation in the file changed.

@claude claude / Claude Code Review

Sibling bug class unfixed: typeof <unbound> also loses UnaryFlags in react_compiler codegen

The immediate sibling of this fix is still broken: `InstructionValue::UnaryExpression` at codegen.rs:1855-1867 emits `flags: E::UnaryFlags::empty()`, so `typeof <unbound-ident>` round-trips without `WAS_ORIGINALLY_TYPEOF_IDENTIFIER` and the printer guard on the line directly above the one this PR cites (js_printer/lib.rs:4003) rewrites it to `typeof (0, window)` — which throws `ReferenceError` instead of returning `"undefined"`, breaking the canonical `typeof window !== "undefined"` SSR check in

Check warning on line 2003 in src/react_compiler/codegen.rs

See this annotation in the file changed.

@claude claude / Claude Code Review

Comment premise is false; unconditional flag regresses delete-of-folded-conditional

The comment's premise — "the source form always had it set" — is not quite true: the react compiler runs on the *visited* body, and the visitor folds `delete (true ? o.a : o.b)` → `delete <EDot(o.a)>` with `flags: empty()` before `lower_unary` sees it (the `e_if` fold at `visit_expr.rs:1503` is gated only on `dead_code_elimination`, default true). With this change that input now prints `delete o.a` (actually deletes) instead of the spec-correct no-op `delete (0, o.a)`. The trigger is implausible