Pull Request Overview
- Opened on September 11, 2026
- Status Open
- Commit count 4 with first commit September 11, 2026
Total Delta
Open Days
Test Delta
How long has this pull request spent in each phase of its lifecycle?
Data pending calculation for pull request
fix(compiler): preserve -0/0 distinction through phi constant propagation and codegen
Summary
Fixes #37447. Two paths in the React Compiler collapsed JavaScript's observable distinction between 0 and -0:
-
Constant propagation (Optimization/ConstantPropagation.ts):evaluatePhicompared phi operand constant values with!==. Since0 !== -0evaluates tofalsein JS, a phi merging0on one branch and-0on another was incorrectly folded into a single "constant" value, silently discarding whichever branch didn't "win", regardless of which branch actually executed at runtime. -
Codegen (ReactiveScopes/CodegenReactiveFunction.ts):codegenValueonly emitted a unary negation (-0) whenvalue < 0. Since-0 < 0isfalse, a literal-0was re-emitted as plain0, losing its sign.
Fix
- Use
Object.is()instead of!==when comparing phi constant candidates inevaluatePhi, so operands with different sign but "equal" primitive values (i.e.0/-0) are correctly treated as non-constant (and thus preserved as a genuine runtime phi instead of being folded to one arbitrary branch's value). - Emit a unary negation in codegen when
Object.is(value, -0)is true, in addition to the existingvalue < 0check, so-0literals round-trip correctly.
Tests
- Added
negative-zero-phi-constant-propagation.js/.expect.md: a component whose phi alternates between0and-0across renders.1 / xis used to observe the sign of zero (Infinityvs-Infinity), and the fixture harness compares compiled vs. uncompiled eval output, verifyingObject.isparity is preserved pre/post compile. - Updated the pre-existing
constant-propagation-unary-numbersnapshot: it already contained a-0literal that was silently being emitted as0in codegen prior to this fix β that regression is now fixed and visible in the updated snapshot (-2, -0, true, ...instead of-2, 0, true, ...). - Ran the full
babel-plugin-react-compilersnap test suite (1817 fixtures) β all pass with only the one expected snapshot update above. -
yarn workspace babel-plugin-react-compiler lintpasses.
Test plan
cd compiler/packages/babel-plugin-react-compiler
yarn build
yarn workspace snap run snap
yarn lint
Description
Two compiler paths collapse JavaScriptβs observable distinction between 0 and -0: constant propagation compares phi constants with !==, and reactive-function code generation only emits a unary negative expression when a number is < 0.
Reproduction
Compile a memoized component whose phi alternates between 0 and -0, then observe the value through 1 / value. Current output reports positive infinity for both paths instead of positive then negative infinity.
Expected behavior
The compiler should preserve signed zero through optimization and emitted code.
No comments have been left on this PR.