Compare commits

...

1 Commits

Author SHA1 Message Date
Mofei Zhang
1d4cbaffb5 [compiler][patch] Emit unary expressions instead of negative numbers
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.

As a followup, we could change our test infra parse babel options (e.g. a babel transform options pragma) which could let us track regressions. We may add an "exhaustive" mode to the compiler test runner to test (1) different babel options and (2) commonly used versions.
2025-06-02 11:31:52 -04:00
4 changed files with 83 additions and 2 deletions

View File

@@ -1726,7 +1726,7 @@ function codegenInstructionValue(
}
case 'UnaryExpression': {
value = t.unaryExpression(
instrValue.operator as 'throw', // todo
instrValue.operator,
codegenPlaceToExpression(cx, instrValue.value),
);
break;
@@ -2582,7 +2582,16 @@ function codegenValue(
value: boolean | number | string | null | undefined,
): t.Expression {
if (typeof value === 'number') {
return t.numericLiteral(value);
if (value < 0) {
/**
* Babel's code generator produces invalid JS for negative numbers when
* run with { compact: true }.
* See repro https://codesandbox.io/p/devbox/5d47fr
*/
return t.unaryExpression('-', t.numericLiteral(-value), false);
} else {
return t.numericLiteral(value);
}
} else if (typeof value === 'boolean') {
return t.booleanLiteral(value);
} else if (typeof value === 'string') {

View File

@@ -0,0 +1,56 @@
## Input
```javascript
import {Stringify} from 'shared-runtime';
function Repro(props) {
const MY_CONST = -2;
return <Stringify>{props.arg - MY_CONST}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Repro,
params: [
{
arg: 3,
},
],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { Stringify } from "shared-runtime";
function Repro(props) {
const $ = _c(2);
const t0 = props.arg - -2;
let t1;
if ($[0] !== t0) {
t1 = <Stringify>{t0}</Stringify>;
$[0] = t0;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: Repro,
params: [
{
arg: 3,
},
],
};
```
### Eval output
(kind: ok) <div>{"children":5}</div>

View File

@@ -0,0 +1,15 @@
import {Stringify} from 'shared-runtime';
function Repro(props) {
const MY_CONST = -2;
return <Stringify>{props.arg - MY_CONST}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Repro,
params: [
{
arg: 3,
},
],
};

View File

@@ -242,6 +242,7 @@ export async function transformFixtureInput(
filename: virtualFilepath,
highlightCode: false,
retainLines: true,
compact: true,
plugins: [
[plugin, options],
'babel-plugin-fbt',