Skip to content

Commit f17d508

Browse files
committed
[compiler] Stop relying on identifier mutable ranges after constructing scopes
Addresses discussion at #30399 (comment). Once we've constructed scopes it's invalid to use identifier mutable ranges. The only places we can do this which i can find are ValidateMemoizedEffectDeps (which is already flawed and disabled by default) and ValidatePreservedManualMemoization. I added a todo to the former, and fixed up the latter. The idea of the fix is that for StartMemo dependencies, if they needed to be memoized (identifier.scope != null) then that scope should exist and should have already completed. If they didn't need a scope or can't have one created (eg their range spans a hook), then their scope would be pruned. So if the scope is set, not pruned, and not completed, then it's an error. For declarations (FinishMemo) the existing logic applies unchanged. [ghstack-poisoned]
1 parent 9983ccf commit f17d508

File tree

3 files changed

+16
-19
lines changed

3 files changed

+16
-19
lines changed

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

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,24 +179,6 @@ export function buildReactiveScopeTerminalsHIR(fn: HIRFunction): void {
179179
* Fix scope and identifier ranges to account for renumbered instructions
180180
*/
181181
for (const [, block] of fn.body.blocks) {
182-
for (const instruction of block.instructions) {
183-
for (const lvalue of eachInstructionLValue(instruction)) {
184-
/*
185-
* Any lvalues whose mutable range was a single instruction must have
186-
* started at the current instruction, so update the range to match
187-
* the instruction's new id
188-
*/
189-
if (
190-
lvalue.identifier.mutableRange.end ===
191-
lvalue.identifier.mutableRange.start + 1
192-
) {
193-
lvalue.identifier.mutableRange.start = instruction.id;
194-
lvalue.identifier.mutableRange.end = makeInstructionId(
195-
instruction.id + 1,
196-
);
197-
}
198-
}
199-
}
200182
const terminal = block.terminal;
201183
if (terminal.kind === 'scope' || terminal.kind === 'pruned-scope') {
202184
/*

compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ class Visitor extends ReactiveFunctionVisitor<CompilerError> {
9999
const deps = instruction.value.args[1]!;
100100
if (
101101
deps.kind === 'Identifier' &&
102+
// TODO: isMutable is not safe to call here as it relies on identifier mutableRange which is no longer valid at this point
103+
// in the pipeline
102104
(isMutable(instruction as Instruction, deps) ||
103105
isUnmemoized(deps.identifier, this.scopes))
104106
) {

compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
InstructionValue,
1515
ManualMemoDependency,
1616
Place,
17+
PrunedReactiveScopeBlock,
1718
ReactiveFunction,
1819
ReactiveInstruction,
1920
ReactiveScopeBlock,
@@ -277,6 +278,7 @@ function validateInferredDep(
277278

278279
class Visitor extends ReactiveFunctionVisitor<VisitorState> {
279280
scopes: Set<ScopeId> = new Set();
281+
prunedScopes: Set<ScopeId> = new Set();
280282
scopeMapping = new Map();
281283
temporaries: Map<IdentifierId, ManualMemoDependency> = new Map();
282284

@@ -414,6 +416,14 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
414416
}
415417
}
416418

419+
override visitPrunedScope(
420+
scopeBlock: PrunedReactiveScopeBlock,
421+
state: VisitorState,
422+
): void {
423+
this.traversePrunedScope(scopeBlock, state);
424+
this.prunedScopes.add(scopeBlock.scope.id);
425+
}
426+
417427
override visitInstruction(
418428
instruction: ReactiveInstruction,
419429
state: VisitorState,
@@ -464,7 +474,10 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
464474
instruction.value as InstructionValue,
465475
)) {
466476
if (
467-
isMutable(instruction as Instruction, value) ||
477+
(isDep &&
478+
value.identifier.scope != null &&
479+
!this.scopes.has(value.identifier.scope.id) &&
480+
!this.prunedScopes.has(value.identifier.scope.id)) ||
468481
(isDecl && isUnmemoized(value.identifier, this.scopes))
469482
) {
470483
state.errors.push({

0 commit comments

Comments
 (0)