mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fix scope merging in MergeOverlappingReactiveScopes
When `MergeOverlappingReactiveScopes` identified scopes to be merged, it was currently (oops, my bad) updating the _existing_ scope's id and range. Later, PropagateScopeDependencies marks outputs of a scope by updating that identifier's scope instance — so if that scope instance isn't shared, then the output is lost. This PR fixes MergeOverlappingReactiveScopes to correctly update all operands for a scope to have the same scope instance.
This commit is contained in:
@@ -106,6 +106,7 @@ export function mergeOverlappingReactiveScopes(fn: ReactiveFunction): void {
|
||||
context.enter(() => {
|
||||
visitBlock(context, fn.body);
|
||||
});
|
||||
context.complete();
|
||||
}
|
||||
|
||||
function visitBlock(context: Context, block: ReactiveBlock): void {
|
||||
@@ -205,6 +206,7 @@ class Context {
|
||||
scopes: Array<BlockScope> = [];
|
||||
seenScopes: Set<ScopeId> = new Set();
|
||||
joinedScopes: DisjointSet<ReactiveScope> = new DisjointSet();
|
||||
operandScopes: Map<Place, ReactiveScope> = new Map();
|
||||
|
||||
visitId(id: InstructionId): void {
|
||||
const currentBlock = this.scopes[this.scopes.length - 1]!;
|
||||
@@ -223,6 +225,7 @@ class Context {
|
||||
if (scope === null) {
|
||||
return;
|
||||
}
|
||||
this.operandScopes.set(place, scope);
|
||||
const currentBlock = this.scopes[this.scopes.length - 1]!;
|
||||
// Fast-path for the first time we see a new scope
|
||||
if (!this.seenScopes.has(scope.id)) {
|
||||
@@ -290,19 +293,24 @@ class Context {
|
||||
this.scopes.push(new BlockScope());
|
||||
fn();
|
||||
this.scopes.pop();
|
||||
if (this.scopes.length === 0) {
|
||||
this.joinedScopes.forEach((scope, groupScope) => {
|
||||
if (scope !== groupScope) {
|
||||
groupScope.range.start = makeInstructionId(
|
||||
Math.min(groupScope.range.start, scope.range.start)
|
||||
);
|
||||
groupScope.range.end = makeInstructionId(
|
||||
Math.max(groupScope.range.end, scope.range.end)
|
||||
);
|
||||
scope.range = groupScope.range;
|
||||
scope.id = groupScope.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
complete(): void {
|
||||
this.joinedScopes.forEach((scope, groupScope) => {
|
||||
if (scope !== groupScope) {
|
||||
groupScope.range.start = makeInstructionId(
|
||||
Math.min(groupScope.range.start, scope.range.start)
|
||||
);
|
||||
groupScope.range.end = makeInstructionId(
|
||||
Math.max(groupScope.range.end, scope.range.end)
|
||||
);
|
||||
}
|
||||
});
|
||||
for (const [operand, originalScope] of this.operandScopes) {
|
||||
const mergedScope = this.joinedScopes.find(originalScope);
|
||||
if (mergedScope !== null) {
|
||||
operand.identifier.scope = mergedScope;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
@@ -17,11 +17,18 @@ function foo() {
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
const x = { x: 0 };
|
||||
const y = { z: 0 };
|
||||
const z = { z: 0 };
|
||||
x.x = x.x + (y.y = y.y * 1);
|
||||
z.z = z.z + (y.y = y.y * (x.x = x.x & 3));
|
||||
const $ = React.useMemoCache();
|
||||
let z;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const x = { x: 0 };
|
||||
const y = { z: 0 };
|
||||
z = { z: 0 };
|
||||
x.x = x.x + (y.y = y.y * 1);
|
||||
z.z = z.z + (y.y = y.y * (x.x = x.x & 3));
|
||||
$[0] = z;
|
||||
} else {
|
||||
z = $[0];
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,10 @@ function Component(props) {
|
||||
const c_1 = $[1] !== props.p1;
|
||||
const c_2 = $[2] !== props.p2;
|
||||
let a;
|
||||
let b;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
a = [];
|
||||
const b = [];
|
||||
b = [];
|
||||
if (b) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
@@ -53,21 +54,23 @@ function Component(props) {
|
||||
$[1] = props.p1;
|
||||
$[2] = props.p2;
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
} else {
|
||||
a = $[3];
|
||||
b = $[4];
|
||||
}
|
||||
const c_4 = $[4] !== a;
|
||||
const c_5 = $[5] !== b;
|
||||
let t6;
|
||||
if (c_4 || c_5) {
|
||||
t6 = <Foo a={a} b={b}></Foo>;
|
||||
$[4] = a;
|
||||
$[5] = b;
|
||||
$[6] = t6;
|
||||
const c_5 = $[5] !== a;
|
||||
const c_6 = $[6] !== b;
|
||||
let t7;
|
||||
if (c_5 || c_6) {
|
||||
t7 = <Foo a={a} b={b}></Foo>;
|
||||
$[5] = a;
|
||||
$[6] = b;
|
||||
$[7] = t7;
|
||||
} else {
|
||||
t6 = $[6];
|
||||
t7 = $[7];
|
||||
}
|
||||
return t6;
|
||||
return t7;
|
||||
}
|
||||
|
||||
function Component(props) {
|
||||
@@ -76,9 +79,10 @@ function Component(props) {
|
||||
const c_1 = $[1] !== props.p1;
|
||||
const c_2 = $[2] !== props.p2;
|
||||
let a;
|
||||
let b;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
a = [];
|
||||
const b = [];
|
||||
b = [];
|
||||
if (mayMutate(b)) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
@@ -89,21 +93,23 @@ function Component(props) {
|
||||
$[1] = props.p1;
|
||||
$[2] = props.p2;
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
} else {
|
||||
a = $[3];
|
||||
b = $[4];
|
||||
}
|
||||
const c_4 = $[4] !== a;
|
||||
const c_5 = $[5] !== b;
|
||||
let t6;
|
||||
if (c_4 || c_5) {
|
||||
t6 = <Foo a={a} b={b}></Foo>;
|
||||
$[4] = a;
|
||||
$[5] = b;
|
||||
$[6] = t6;
|
||||
const c_5 = $[5] !== a;
|
||||
const c_6 = $[6] !== b;
|
||||
let t7;
|
||||
if (c_5 || c_6) {
|
||||
t7 = <Foo a={a} b={b}></Foo>;
|
||||
$[5] = a;
|
||||
$[6] = b;
|
||||
$[7] = t7;
|
||||
} else {
|
||||
t6 = $[6];
|
||||
t7 = $[7];
|
||||
}
|
||||
return t6;
|
||||
return t7;
|
||||
}
|
||||
|
||||
function Foo() {}
|
||||
|
||||
@@ -61,9 +61,10 @@ function Component(props) {
|
||||
const c_1 = $[1] !== props.b;
|
||||
const c_2 = $[2] !== props.c;
|
||||
let a;
|
||||
let b;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
a = compute(props.a);
|
||||
const b = compute(props.b);
|
||||
b = compute(props.b);
|
||||
if (props.c) {
|
||||
mutate(a);
|
||||
mutate(b);
|
||||
@@ -72,21 +73,23 @@ function Component(props) {
|
||||
$[1] = props.b;
|
||||
$[2] = props.c;
|
||||
$[3] = a;
|
||||
$[4] = b;
|
||||
} else {
|
||||
a = $[3];
|
||||
b = $[4];
|
||||
}
|
||||
const c_4 = $[4] !== a;
|
||||
const c_5 = $[5] !== b;
|
||||
let t6;
|
||||
if (c_4 || c_5) {
|
||||
t6 = <Foo a={a} b={b}></Foo>;
|
||||
$[4] = a;
|
||||
$[5] = b;
|
||||
$[6] = t6;
|
||||
const c_5 = $[5] !== a;
|
||||
const c_6 = $[6] !== b;
|
||||
let t7;
|
||||
if (c_5 || c_6) {
|
||||
t7 = <Foo a={a} b={b}></Foo>;
|
||||
$[5] = a;
|
||||
$[6] = b;
|
||||
$[7] = t7;
|
||||
} else {
|
||||
t6 = $[6];
|
||||
t7 = $[7];
|
||||
}
|
||||
return t6;
|
||||
return t7;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -36,10 +36,11 @@ function Component(props) {
|
||||
const c_0 = $[0] !== props.p0;
|
||||
const c_1 = $[1] !== props.p2;
|
||||
let x;
|
||||
let y$0;
|
||||
if (c_0 || c_1) {
|
||||
x = [];
|
||||
const y = undefined;
|
||||
let y$0 = y;
|
||||
y$0 = y;
|
||||
bb1: switch (props.p0) {
|
||||
case 1: {
|
||||
break bb1;
|
||||
@@ -47,11 +48,11 @@ function Component(props) {
|
||||
case true: {
|
||||
x.push(props.p2);
|
||||
let y$1;
|
||||
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
y$1 = [];
|
||||
$[3] = y$1;
|
||||
$[4] = y$1;
|
||||
} else {
|
||||
y$1 = $[3];
|
||||
y$1 = $[4];
|
||||
}
|
||||
y$0 = y$1;
|
||||
break bb1;
|
||||
@@ -67,31 +68,33 @@ function Component(props) {
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p2;
|
||||
$[2] = x;
|
||||
$[3] = y$0;
|
||||
} else {
|
||||
x = $[2];
|
||||
y$0 = $[3];
|
||||
}
|
||||
const c_4 = $[4] !== x;
|
||||
const c_5 = $[5] !== x;
|
||||
let child;
|
||||
if (c_4) {
|
||||
if (c_5) {
|
||||
child = <Component data={x}></Component>;
|
||||
$[4] = x;
|
||||
$[5] = child;
|
||||
$[5] = x;
|
||||
$[6] = child;
|
||||
} else {
|
||||
child = $[5];
|
||||
child = $[6];
|
||||
}
|
||||
y$0.push(props.p4);
|
||||
const c_6 = $[6] !== y$0;
|
||||
const c_7 = $[7] !== child;
|
||||
let t8;
|
||||
if (c_6 || c_7) {
|
||||
t8 = <Component data={y$0}>{child}</Component>;
|
||||
$[6] = y$0;
|
||||
$[7] = child;
|
||||
$[8] = t8;
|
||||
const c_7 = $[7] !== y$0;
|
||||
const c_8 = $[8] !== child;
|
||||
let t9;
|
||||
if (c_7 || c_8) {
|
||||
t9 = <Component data={y$0}>{child}</Component>;
|
||||
$[7] = y$0;
|
||||
$[8] = child;
|
||||
$[9] = t9;
|
||||
} else {
|
||||
t8 = $[8];
|
||||
t9 = $[9];
|
||||
}
|
||||
return t8;
|
||||
return t9;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -32,10 +32,11 @@ function Component(props) {
|
||||
const c_1 = $[1] !== props.p2;
|
||||
const c_2 = $[2] !== props.p3;
|
||||
let x;
|
||||
let y$0;
|
||||
if (c_0 || c_1 || c_2) {
|
||||
x = [];
|
||||
const y = undefined;
|
||||
let y$0 = y;
|
||||
y$0 = y;
|
||||
switch (props.p0) {
|
||||
case true: {
|
||||
x.push(props.p2);
|
||||
@@ -51,31 +52,33 @@ function Component(props) {
|
||||
$[1] = props.p2;
|
||||
$[2] = props.p3;
|
||||
$[3] = x;
|
||||
$[4] = y$0;
|
||||
} else {
|
||||
x = $[3];
|
||||
y$0 = $[4];
|
||||
}
|
||||
const c_4 = $[4] !== x;
|
||||
const c_5 = $[5] !== x;
|
||||
let child;
|
||||
if (c_4) {
|
||||
if (c_5) {
|
||||
child = <Component data={x}></Component>;
|
||||
$[4] = x;
|
||||
$[5] = child;
|
||||
$[5] = x;
|
||||
$[6] = child;
|
||||
} else {
|
||||
child = $[5];
|
||||
child = $[6];
|
||||
}
|
||||
y$0.push(props.p4);
|
||||
const c_6 = $[6] !== y$0;
|
||||
const c_7 = $[7] !== child;
|
||||
let t8;
|
||||
if (c_6 || c_7) {
|
||||
t8 = <Component data={y$0}>{child}</Component>;
|
||||
$[6] = y$0;
|
||||
$[7] = child;
|
||||
$[8] = t8;
|
||||
const c_7 = $[7] !== y$0;
|
||||
const c_8 = $[8] !== child;
|
||||
let t9;
|
||||
if (c_7 || c_8) {
|
||||
t9 = <Component data={y$0}>{child}</Component>;
|
||||
$[7] = y$0;
|
||||
$[8] = child;
|
||||
$[9] = t9;
|
||||
} else {
|
||||
t8 = $[8];
|
||||
t9 = $[9];
|
||||
}
|
||||
return t8;
|
||||
return t9;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user