Skip to content

Commit aa09304

Browse files
committed
compiler: Represent pruned scopes instead of inlining
There are a few places where we want to check whether a value actually got memoized, and we currently have to infer this based on values that "should" have a scope and whether a corresponding scope actually exists. This PR adds a new ReactiveStatement variant to model a reactive scope block that was pruned for some reason, and updates all the passes that prune scopes to instead produce this new variant. ghstack-source-id: aea6dab Pull Request resolved: #29781
1 parent a0e99f7 commit aa09304

12 files changed

+113
-6
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,19 @@ export type ReactiveScopeBlock = {
6565
instructions: ReactiveBlock;
6666
};
6767

68+
export type PrunedReactiveScopeBlock = {
69+
kind: "pruned-scope";
70+
scope: ReactiveScope;
71+
instructions: ReactiveBlock;
72+
};
73+
6874
export type ReactiveBlock = Array<ReactiveStatement>;
6975

7076
export type ReactiveStatement =
7177
| ReactiveInstructionStatement
7278
| ReactiveTerminalStatement
73-
| ReactiveScopeBlock;
79+
| ReactiveScopeBlock
80+
| PrunedReactiveScopeBlock;
7481

7582
export type ReactiveInstructionStatement = {
7683
kind: "instruction";

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveBlocks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ function visitBlock(context: Context, block: ReactiveBlock): void {
183183
context.append(stmt, stmt.label);
184184
break;
185185
}
186+
case "pruned-scope":
186187
case "scope": {
187188
CompilerError.invariant(false, {
188189
reason: "Expected the function to not have scopes already assigned",

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,11 @@ function codegenBlockNoReset(
400400
}
401401
break;
402402
}
403+
case "pruned-scope": {
404+
const scopeBlock = codegenBlockNoReset(cx, item.instructions);
405+
statements.push(...scopeBlock.body);
406+
break;
407+
}
403408
case "scope": {
404409
const temp = new Map(cx.temp);
405410
codegenReactiveScope(cx, statements, item.scope, item.instructions);

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenReactiveLoops.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ class Transform extends ReactiveFunctionTransform<boolean> {
3434
): Transformed<ReactiveStatement> {
3535
this.visitScope(scope, isWithinLoop);
3636
if (isWithinLoop) {
37-
return { kind: "replace-many", value: scope.instructions };
37+
return {
38+
kind: "replace",
39+
value: {
40+
kind: "pruned-scope",
41+
scope: scope.scope,
42+
instructions: scope.instructions,
43+
},
44+
};
3845
} else {
3946
return { kind: "keep" };
4047
}

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUse.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,14 @@ class Transform extends ReactiveFunctionTransform<State> {
6666
this.visitScope(scope, innerState);
6767
outerState.hasHook ||= innerState.hasHook;
6868
if (innerState.hasHook) {
69-
return { kind: "replace-many", value: scope.instructions };
69+
return {
70+
kind: "replace",
71+
value: {
72+
kind: "pruned-scope",
73+
scope: scope.scope,
74+
instructions: scope.instructions,
75+
},
76+
};
7077
} else {
7178
return { kind: "keep" };
7279
}

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,16 @@ class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | nu
174174
}
175175
break;
176176
}
177+
case "pruned-scope": {
178+
// For now we don't merge across pruned scopes
179+
if (current !== null) {
180+
log(
181+
`Reset scope @${current.block.scope.id} from pruned scope @${instr.scope.id}`
182+
);
183+
reset();
184+
}
185+
break;
186+
}
177187
case "instruction": {
178188
switch (instr.instruction.value.kind) {
179189
case "ComputedLoad":

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import { CompilerError } from "../CompilerError";
99
import {
10+
PrunedReactiveScopeBlock,
1011
ReactiveFunction,
1112
ReactiveScope,
1213
ReactiveScopeBlock,
@@ -83,6 +84,15 @@ export function writeReactiveBlock(
8384
writer.writeLine("}");
8485
}
8586

87+
export function writePrunedScope(
88+
writer: Writer,
89+
block: PrunedReactiveScopeBlock
90+
): void {
91+
writer.writeLine(`<pruned> ${printReactiveScopeSummary(block.scope)} {`);
92+
writeReactiveInstructions(writer, block.instructions);
93+
writer.writeLine("}");
94+
}
95+
8696
export function printDependency(dependency: ReactiveScopeDependency): string {
8797
const identifier =
8898
printIdentifier(dependency.identifier) +
@@ -133,6 +143,10 @@ function writeReactiveInstruction(
133143
writeReactiveBlock(writer, instr);
134144
break;
135145
}
146+
case "pruned-scope": {
147+
writePrunedScope(writer, instr);
148+
break;
149+
}
136150
case "terminal": {
137151
if (instr.label !== null) {
138152
writer.write(`bb${instr.label.id}: `);

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneAlwaysInvalidatingScopes.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,14 @@ class Transform extends ReactiveFunctionTransform<boolean> {
107107
this.unmemoizedValues.add(identifier);
108108
}
109109
}
110-
return { kind: "replace-many", value: scopeBlock.instructions };
110+
return {
111+
kind: "replace",
112+
value: {
113+
kind: "pruned-scope",
114+
scope: scopeBlock.scope,
115+
instructions: scopeBlock.instructions,
116+
},
117+
};
111118
}
112119
}
113120
return { kind: "keep" };

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,14 @@ class PruneScopesTransform extends ReactiveFunctionTransform<
951951
return { kind: "keep" };
952952
} else {
953953
this.prunedScopes.add(scopeBlock.scope.id);
954-
return { kind: "replace-many", value: scopeBlock.instructions };
954+
return {
955+
kind: "replace",
956+
value: {
957+
kind: "pruned-scope",
958+
scope: scopeBlock.scope,
959+
instructions: scopeBlock.instructions,
960+
},
961+
};
955962
}
956963
}
957964

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneUnusedScopes.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,14 @@ class Transform extends ReactiveFunctionTransform<State> {
5151
*/
5252
!hasOwnDeclaration(scopeBlock))
5353
) {
54-
return { kind: "replace-many", value: scopeBlock.instructions };
54+
return {
55+
kind: "replace",
56+
value: {
57+
kind: "pruned-scope",
58+
scope: scopeBlock.scope,
59+
instructions: scopeBlock.instructions,
60+
},
61+
};
5562
} else {
5663
return { kind: "keep" };
5764
}

0 commit comments

Comments
 (0)