@samitouri / QOS-React / commits / 946da518eb

feat(compiler): implement constant folding for unary minus (#33140)

## Summary `-constant` is represented as a `UnaryExpression` node that is currently not part of constant folding. If the operand is a constant number, the node is folded to `constant * -1`. This also coerces `-0` to `0`, resulting in `0 === -0` being folded to `true`. ## How did you test this change? See attached tests

Niklas Mollenhauer committed May 7, 2025 at 19:15 UTC 946da518eb2d64d808f9204a72e05892d3005f3f
4 files changed +117 -1
compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts
+17
@@ -327,6 +327,23 @@ function evaluateInstruction(
327 }
328 return null;
329 }
330 + case '-': {
331 + const operand = read(constants, value.value);
332 + if (
333 + operand !== null &&
334 + operand.kind === 'Primitive' &&
335 + typeof operand.value === 'number'
336 + ) {
337 + const result: Primitive = {
338 + kind: 'Primitive',
339 + value: operand.value * -1,
340 + loc: value.loc,
341 + };
342 + instr.value = result;
343 + return result;
344 + }
345 + return null;
346 + }
347 default:
348 return null;
349 }
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-unary-number.expect.md new
+74
@@ -0,0 +1,74 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import {Stringify} from 'shared-runtime';
6 +
7 +function foo() {
8 + const a = -1;
9 + return (
10 + <Stringify
11 + value={[
12 + 2 * a,
13 + -0,
14 + 0 === -0,
15 + -Infinity,
16 + -NaN,
17 + a * NaN,
18 + a * Infinity,
19 + a * -Infinity,
20 + ]}
21 + />
22 + );
23 +}
24 +
25 +export const FIXTURE_ENTRYPOINT = {
26 + fn: foo,
27 + params: [],
28 + isComponent: false,
29 +};
30 +
31 +```
32 +
33 +## Code
34 +
35 +```javascript
36 +import { c as _c } from "react/compiler-runtime";
37 +import { Stringify } from "shared-runtime";
38 +
39 +function foo() {
40 + const $ = _c(1);
41 + let t0;
42 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
43 + t0 = (
44 + <Stringify
45 + value={[
46 + -2,
47 + 0,
48 + true,
49 + -Infinity,
50 + -NaN,
51 +
52 + -1 * NaN,
53 + -1 * Infinity,
54 + -1 * -Infinity,
55 + ]}
56 + />
57 + );
58 + $[0] = t0;
59 + } else {
60 + t0 = $[0];
61 + }
62 + return t0;
63 +}
64 +
65 +export const FIXTURE_ENTRYPOINT = {
66 + fn: foo,
67 + params: [],
68 + isComponent: false,
69 +};
70 +
71 +```
72 +
73 +### Eval output
74 +(kind: ok) <div>{"value":[-2,0,true,null,null,null,null,null]}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-unary-number.js new
+25
@@ -0,0 +1,25 @@
1 +import {Stringify} from 'shared-runtime';
2 +
3 +function foo() {
4 + const a = -1;
5 + return (
6 + <Stringify
7 + value={[
8 + 2 * a,
9 + -0,
10 + 0 === -0,
11 + -Infinity,
12 + -NaN,
13 + a * NaN,
14 + a * Infinity,
15 + a * -Infinity,
16 + ]}
17 + />
18 + );
19 +}
20 +
21 +export const FIXTURE_ENTRYPOINT = {
22 + fn: foo,
23 + params: [],
24 + isComponent: false,
25 +};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-unary.expect.md
+1 -1
@@ -58,7 +58,7 @@ function foo() {
58 n0: true,
59 n1: false,
60 n2: false,
61 - n3: !-1,
61 + n3: false,
62 s0: true,
63 s1: false,
64 s2: false,