Skip to content

Commit fcb4e0f

Browse files
authored
[compiler] remove invariant to account for backedges (facebook#32417)
Fixes facebook#32269, see comments for details. Added test fixture for repro
1 parent a84862d commit fcb4e0f

File tree

3 files changed

+101
-11
lines changed

3 files changed

+101
-11
lines changed

compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,18 +1598,14 @@ function inferBlock(
15981598
break;
15991599
}
16001600
case 'LoadLocal': {
1601+
/**
1602+
* Due to backedges in the CFG, we may revisit LoadLocal lvalues
1603+
* multiple times. Unlike StoreLocal which may reassign to existing
1604+
* identifiers, LoadLocal always evaluates to store a new temporary.
1605+
* This means that we should always model LoadLocal as a Capture effect
1606+
* on the rvalue.
1607+
*/
16011608
const lvalue = instr.lvalue;
1602-
CompilerError.invariant(
1603-
!(
1604-
state.isDefined(lvalue) &&
1605-
state.kind(lvalue).kind === ValueKind.Context
1606-
),
1607-
{
1608-
reason:
1609-
'[InferReferenceEffects] Unexpected LoadLocal with context kind',
1610-
loc: lvalue.loc,
1611-
},
1612-
);
16131609
state.referenceAndRecordEffects(
16141610
freezeActions,
16151611
instrValue.place,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {Stringify} from 'shared-runtime';
6+
7+
function Foo({userIds}) {
8+
return (
9+
<Stringify
10+
fn={() => {
11+
const arr = [];
12+
13+
for (const selectedUser of userIds) {
14+
arr.push(selectedUser);
15+
}
16+
return arr;
17+
}}
18+
shouldInvokeFns={true}
19+
/>
20+
);
21+
}
22+
23+
export const FIXTURE_ENTRYPOINT = {
24+
fn: Foo,
25+
params: [{userIds: [1, 2, 3]}],
26+
sequentialRenders: [{userIds: [1, 2, 4]}],
27+
};
28+
29+
```
30+
31+
## Code
32+
33+
```javascript
34+
import { c as _c } from "react/compiler-runtime";
35+
import { Stringify } from "shared-runtime";
36+
37+
function Foo(t0) {
38+
const $ = _c(2);
39+
const { userIds } = t0;
40+
let t1;
41+
if ($[0] !== userIds) {
42+
t1 = (
43+
<Stringify
44+
fn={() => {
45+
const arr = [];
46+
for (const selectedUser of userIds) {
47+
arr.push(selectedUser);
48+
}
49+
return arr;
50+
}}
51+
shouldInvokeFns={true}
52+
/>
53+
);
54+
$[0] = userIds;
55+
$[1] = t1;
56+
} else {
57+
t1 = $[1];
58+
}
59+
return t1;
60+
}
61+
62+
export const FIXTURE_ENTRYPOINT = {
63+
fn: Foo,
64+
params: [{ userIds: [1, 2, 3] }],
65+
sequentialRenders: [{ userIds: [1, 2, 4] }],
66+
};
67+
68+
```
69+
70+
### Eval output
71+
(kind: ok) <div>{"fn":{"kind":"Function","result":[1,2,4]},"shouldInvokeFns":true}</div>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {Stringify} from 'shared-runtime';
2+
3+
function Foo({userIds}) {
4+
return (
5+
<Stringify
6+
fn={() => {
7+
const arr = [];
8+
9+
for (const selectedUser of userIds) {
10+
arr.push(selectedUser);
11+
}
12+
return arr;
13+
}}
14+
shouldInvokeFns={true}
15+
/>
16+
);
17+
}
18+
19+
export const FIXTURE_ENTRYPOINT = {
20+
fn: Foo,
21+
params: [{userIds: [1, 2, 3]}],
22+
sequentialRenders: [{userIds: [1, 2, 4]}],
23+
};

0 commit comments

Comments
 (0)