Skip to content

Commit 526dd34

Browse files
authored
[compiler][patch] Emit unary expressions instead of negative numbers (facebook#33383)
This is a babel bug + edge case. Babel compact mode produces invalid JavaScript (i.e. parse error) when given a `NumericLiteral` with a negative value. See https://codesandbox.io/p/devbox/5d47fr for repro.
1 parent ee76351 commit 526dd34

File tree

4 files changed

+83
-2
lines changed

4 files changed

+83
-2
lines changed

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,7 +1726,7 @@ function codegenInstructionValue(
17261726
}
17271727
case 'UnaryExpression': {
17281728
value = t.unaryExpression(
1729-
instrValue.operator as 'throw', // todo
1729+
instrValue.operator,
17301730
codegenPlaceToExpression(cx, instrValue.value),
17311731
);
17321732
break;
@@ -2582,7 +2582,16 @@ function codegenValue(
25822582
value: boolean | number | string | null | undefined,
25832583
): t.Expression {
25842584
if (typeof value === 'number') {
2585-
return t.numericLiteral(value);
2585+
if (value < 0) {
2586+
/**
2587+
* Babel's code generator produces invalid JS for negative numbers when
2588+
* run with { compact: true }.
2589+
* See repro https://codesandbox.io/p/devbox/5d47fr
2590+
*/
2591+
return t.unaryExpression('-', t.numericLiteral(-value), false);
2592+
} else {
2593+
return t.numericLiteral(value);
2594+
}
25862595
} else if (typeof value === 'boolean') {
25872596
return t.booleanLiteral(value);
25882597
} else if (typeof value === 'string') {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {Stringify} from 'shared-runtime';
6+
7+
function Repro(props) {
8+
const MY_CONST = -2;
9+
return <Stringify>{props.arg - MY_CONST}</Stringify>;
10+
}
11+
12+
export const FIXTURE_ENTRYPOINT = {
13+
fn: Repro,
14+
params: [
15+
{
16+
arg: 3,
17+
},
18+
],
19+
};
20+
21+
```
22+
23+
## Code
24+
25+
```javascript
26+
import { c as _c } from "react/compiler-runtime";
27+
import { Stringify } from "shared-runtime";
28+
29+
function Repro(props) {
30+
const $ = _c(2);
31+
32+
const t0 = props.arg - -2;
33+
let t1;
34+
if ($[0] !== t0) {
35+
t1 = <Stringify>{t0}</Stringify>;
36+
$[0] = t0;
37+
$[1] = t1;
38+
} else {
39+
t1 = $[1];
40+
}
41+
return t1;
42+
}
43+
44+
export const FIXTURE_ENTRYPOINT = {
45+
fn: Repro,
46+
params: [
47+
{
48+
arg: 3,
49+
},
50+
],
51+
};
52+
53+
```
54+
55+
### Eval output
56+
(kind: ok) <div>{"children":5}</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {Stringify} from 'shared-runtime';
2+
3+
function Repro(props) {
4+
const MY_CONST = -2;
5+
return <Stringify>{props.arg - MY_CONST}</Stringify>;
6+
}
7+
8+
export const FIXTURE_ENTRYPOINT = {
9+
fn: Repro,
10+
params: [
11+
{
12+
arg: 3,
13+
},
14+
],
15+
};

compiler/packages/snap/src/compiler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ export async function transformFixtureInput(
242242
filename: virtualFilepath,
243243
highlightCode: false,
244244
retainLines: true,
245+
compact: true,
245246
plugins: [
246247
[plugin, options],
247248
'babel-plugin-fbt',

0 commit comments

Comments
 (0)