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
This commit is contained in:
Niklas Mollenhauer
2025-05-07 10:15:11 -07:00
committed by GitHub
parent 037f5bd3fb
commit cb9469fdda
4 changed files with 117 additions and 1 deletions
@@ -327,6 +327,23 @@ function evaluateInstruction(
}
return null;
}
case '-': {
const operand = read(constants, value.value);
if (
operand !== null &&
operand.kind === 'Primitive' &&
typeof operand.value === 'number'
) {
const result: Primitive = {
kind: 'Primitive',
value: operand.value * -1,
loc: value.loc,
};
instr.value = result;
return result;
}
return null;
}
default:
return null;
}
@@ -0,0 +1,74 @@
## Input
```javascript
import {Stringify} from 'shared-runtime';
function foo() {
const a = -1;
return (
<Stringify
value={[
2 * a,
-0,
0 === -0,
-Infinity,
-NaN,
a * NaN,
a * Infinity,
a * -Infinity,
]}
/>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: foo,
params: [],
isComponent: false,
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { Stringify } from "shared-runtime";
function foo() {
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<Stringify
value={[
-2,
0,
true,
-Infinity,
-NaN,
-1 * NaN,
-1 * Infinity,
-1 * -Infinity,
]}
/>
);
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: foo,
params: [],
isComponent: false,
};
```
### Eval output
(kind: ok) <div>{"value":[-2,0,true,null,null,null,null,null]}</div>
@@ -0,0 +1,25 @@
import {Stringify} from 'shared-runtime';
function foo() {
const a = -1;
return (
<Stringify
value={[
2 * a,
-0,
0 === -0,
-Infinity,
-NaN,
a * NaN,
a * Infinity,
a * -Infinity,
]}
/>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: foo,
params: [],
isComponent: false,
};
@@ -58,7 +58,7 @@ function foo() {
n0: true,
n1: false,
n2: false,
n3: !-1,
n3: false,
s0: true,
s1: false,
s2: false,