@samitouri / QOS-React / commits / fcb4e0f137

[compiler] remove invariant to account for backedges (#32417)

Fixes https://github.com/facebook/react/issues/32269, see comments for details. Added test fixture for repro

mofeiZ committed Feb 19, 2025 at 14:22 UTC fcb4e0f137db6efa6e180ad12dcfaabd0c590219
3 files changed +101 -11
compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts
+7 -11
@@ -1598,18 +1598,14 @@ function inferBlock(
1598 break;
1599 }
1600 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 + */
1608 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 - );
1609 state.referenceAndRecordEffects(
1610 freezeActions,
1611 instrValue.place,
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-backedge-reference-effect.expect.md new
+71
@@ -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>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-backedge-reference-effect.js new
+23
@@ -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 +};