Skip to content

Commit ea0c17b

Browse files
authored
[compiler] loosen computed key restriction for compiler (facebook#34902)
We have a whole ton of compiler errors due to us using a helper to return breakpoints for CSS-in-js, which results in code like: ``` const styles = { [responsive.up('xl')]: { ... } } ``` this results in TONS of bailouts due to `(BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression`. I was looking into what it would take to fix it and why we don't allow it, and following the paper trail is seems like the gotchas have been fixed with the new mutability aliasing model that is fully rolled out. It looks like this is the same pattern/issue that was fixed (see https://github.com/facebook/react/blob/main/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.js and the old bug in https://github.com/facebook/react/blob/d58c07b563a79bd706531278cb4afec6292b84a8/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md). @josephsavona can you confirm if that's the case and if we're able to drop this restriction now? (or alternatively, is there another case we can ignore?)
1 parent 031595d commit ea0c17b

13 files changed

+235
-179
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,20 +1568,6 @@ function lowerObjectPropertyKey(
15681568
name: key.node.value,
15691569
};
15701570
} else if (property.node.computed && key.isExpression()) {
1571-
if (!key.isIdentifier() && !key.isMemberExpression()) {
1572-
/*
1573-
* NOTE: allowing complex key expressions can trigger a bug where a mutation is made conditional
1574-
* see fixture
1575-
* error.object-expression-computed-key-modified-during-after-construction.js
1576-
*/
1577-
builder.errors.push({
1578-
reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
1579-
category: ErrorCategory.Todo,
1580-
loc: key.node.loc ?? null,
1581-
suggestions: null,
1582-
});
1583-
return null;
1584-
}
15851571
const place = lowerExpressionToTemporary(builder, key);
15861572
return {
15871573
kind: 'computed',

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.expect.md

Lines changed: 0 additions & 41 deletions
This file was deleted.

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction.expect.md

Lines changed: 0 additions & 41 deletions
This file was deleted.

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-mutate-key-while-constructing-object.expect.md

Lines changed: 0 additions & 40 deletions
This file was deleted.

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {identity, mutate, mutateAndReturn} from 'shared-runtime';
6+
7+
function Component(props) {
8+
const key = {};
9+
const context = {
10+
[(mutate(key), key)]: identity([props.value]),
11+
};
12+
mutate(key);
13+
return [context, key];
14+
}
15+
16+
export const FIXTURE_ENTRYPOINT = {
17+
fn: Component,
18+
params: [{value: 42}],
19+
sequentialRenders: [{value: 42}, {value: 42}],
20+
};
21+
22+
```
23+
24+
## Code
25+
26+
```javascript
27+
import { c as _c } from "react/compiler-runtime";
28+
import { identity, mutate, mutateAndReturn } from "shared-runtime";
29+
30+
function Component(props) {
31+
const $ = _c(2);
32+
let t0;
33+
if ($[0] !== props.value) {
34+
const key = {};
35+
const context = { [(mutate(key), key)]: identity([props.value]) };
36+
mutate(key);
37+
t0 = [context, key];
38+
$[0] = props.value;
39+
$[1] = t0;
40+
} else {
41+
t0 = $[1];
42+
}
43+
return t0;
44+
}
45+
46+
export const FIXTURE_ENTRYPOINT = {
47+
fn: Component,
48+
params: [{ value: 42 }],
49+
sequentialRenders: [{ value: 42 }, { value: 42 }],
50+
};
51+
52+
```
53+
54+
### Eval output
55+
(kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
56+
[{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ function Component(props) {
66
[(mutate(key), key)]: identity([props.value]),
77
};
88
mutate(key);
9-
return context;
9+
return [context, key];
1010
}
1111

1212
export const FIXTURE_ENTRYPOINT = {
1313
fn: Component,
1414
params: [{value: 42}],
15+
sequentialRenders: [{value: 42}, {value: 42}],
1516
};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {identity, mutate, mutateAndReturn} from 'shared-runtime';
6+
7+
function Component(props) {
8+
const key = {};
9+
const context = {
10+
[mutateAndReturn(key)]: identity([props.value]),
11+
};
12+
mutate(key);
13+
return context;
14+
}
15+
16+
export const FIXTURE_ENTRYPOINT = {
17+
fn: Component,
18+
params: [{value: 42}],
19+
sequentialRenders: [{value: 42}, {value: 42}],
20+
};
21+
22+
```
23+
24+
## Code
25+
26+
```javascript
27+
import { c as _c } from "react/compiler-runtime";
28+
import { identity, mutate, mutateAndReturn } from "shared-runtime";
29+
30+
function Component(props) {
31+
const $ = _c(2);
32+
let context;
33+
if ($[0] !== props.value) {
34+
const key = {};
35+
context = { [mutateAndReturn(key)]: identity([props.value]) };
36+
mutate(key);
37+
$[0] = props.value;
38+
$[1] = context;
39+
} else {
40+
context = $[1];
41+
}
42+
return context;
43+
}
44+
45+
export const FIXTURE_ENTRYPOINT = {
46+
fn: Component,
47+
params: [{ value: 42 }],
48+
sequentialRenders: [{ value: 42 }, { value: 42 }],
49+
};
50+
51+
```
52+
53+
### Eval output
54+
(kind: ok) {"[object Object]":[42]}
55+
{"[object Object]":[42]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ function Component(props) {
1212
export const FIXTURE_ENTRYPOINT = {
1313
fn: Component,
1414
params: [{value: 42}],
15+
sequentialRenders: [{value: 42}, {value: 42}],
1516
};
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {identity, mutate, mutateAndReturn} from 'shared-runtime';
6+
7+
function Component(props) {
8+
const key = {};
9+
const context = {
10+
[mutateAndReturn(key)]: identity([props.value]),
11+
};
12+
return context;
13+
}
14+
15+
export const FIXTURE_ENTRYPOINT = {
16+
fn: Component,
17+
params: [{value: 42}],
18+
};
19+
20+
```
21+
22+
## Code
23+
24+
```javascript
25+
import { c as _c } from "react/compiler-runtime";
26+
import { identity, mutate, mutateAndReturn } from "shared-runtime";
27+
28+
function Component(props) {
29+
const $ = _c(5);
30+
let t0;
31+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
32+
const key = {};
33+
34+
t0 = mutateAndReturn(key);
35+
$[0] = t0;
36+
} else {
37+
t0 = $[0];
38+
}
39+
let t1;
40+
if ($[1] !== props.value) {
41+
t1 = identity([props.value]);
42+
$[1] = props.value;
43+
$[2] = t1;
44+
} else {
45+
t1 = $[2];
46+
}
47+
let t2;
48+
if ($[3] !== t1) {
49+
t2 = { [t0]: t1 };
50+
$[3] = t1;
51+
$[4] = t2;
52+
} else {
53+
t2 = $[4];
54+
}
55+
const context = t2;
56+
return context;
57+
}
58+
59+
export const FIXTURE_ENTRYPOINT = {
60+
fn: Component,
61+
params: [{ value: 42 }],
62+
};
63+
64+
```
65+
66+
### Eval output
67+
(kind: ok) {"[object Object]":[42]}

0 commit comments

Comments
 (0)