Skip to content

Commit fa3de49

Browse files
committed
[compiler][donotcommit] show differences between identifier + scope ranges
ghstack-source-id: f9abcf8 Pull Request resolved: #30409
1 parent 7789b60 commit fa3de49

File tree

8 files changed

+100
-7
lines changed

8 files changed

+100
-7
lines changed

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import {
9898
} from "../Validation";
9999
import { validateLocalsNotReassignedAfterRender } from "../Validation/ValidateLocalsNotReassignedAfterRender";
100100
import { outlineFunctions } from "../Optimization/OutlineFunctions";
101+
import { assertMutableRangesAreAlwaysScopes } from "../HIR/BuildReactiveScopeTerminalsHIR";
101102

102103
export type CompilerPipelineValue =
103104
| { kind: "ast"; name: string; value: CodegenFunction }
@@ -299,6 +300,8 @@ function* runWithEnvironment(
299300
value: hir,
300301
});
301302

303+
assertMutableRangesAreAlwaysScopes(hir);
304+
302305
assertValidBlockNesting(hir);
303306

304307
flattenReactiveLoopsHIR(hir);

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,74 @@ import {
99
GotoVariant,
1010
HIRFunction,
1111
InstructionId,
12+
MutableRange,
13+
Place,
1214
ReactiveScope,
1315
ReactiveScopeTerminal,
1416
ScopeId,
1517
} from "./HIR";
18+
import { printPlace } from "./PrintHIR";
19+
import {
20+
eachInstructionLValue,
21+
eachInstructionOperand,
22+
eachTerminalOperand,
23+
} from "./visitors";
24+
25+
export function assertMutableRangesAreAlwaysScopes(fn: HIRFunction): void {
26+
const scopeRanges: Set<MutableRange> = new Set();
27+
28+
for (const [_, block] of fn.body.blocks) {
29+
if (
30+
block.terminal.kind === "scope" ||
31+
block.terminal.kind === "pruned-scope"
32+
) {
33+
scopeRanges.add(block.terminal.scope.range);
34+
}
35+
}
36+
37+
const validate = (place: Place): void => {
38+
if (
39+
place.identifier.mutableRange.end >
40+
place.identifier.mutableRange.start + 1
41+
) {
42+
if (scopeRanges.size !== 0) {
43+
CompilerError.invariant(
44+
scopeRanges.has(place.identifier.mutableRange),
45+
{
46+
reason: "Mutable range not found in scope ranges!",
47+
description: `${printPlace(place)}`,
48+
loc: place.loc,
49+
}
50+
);
51+
}
52+
if (place.identifier.scope != null) {
53+
// Useful for debugging before we build reactive scope terminals
54+
CompilerError.invariant(
55+
place.identifier.scope.range === place.identifier.mutableRange,
56+
{
57+
reason: "Mutable range inconsistent with range of attached scope",
58+
description: `${printPlace(place)}`,
59+
loc: place.loc,
60+
}
61+
);
62+
}
63+
}
64+
};
65+
66+
for (const [_, block] of fn.body.blocks) {
67+
for (const instr of block.instructions) {
68+
for (const place of eachInstructionLValue(instr)) {
69+
validate(place);
70+
}
71+
for (const place of eachInstructionOperand(instr)) {
72+
validate(place);
73+
}
74+
}
75+
for (const place of eachTerminalOperand(block.terminal)) {
76+
validate(place);
77+
}
78+
}
79+
}
1680

1781
/**
1882
* This pass assumes that all program blocks are properly nested with respect to fallthroughs

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,10 @@ export type AbstractValue = {
12701270
context: ReadonlySet<Place>;
12711271
};
12721272

1273+
export function isRangeMutable(range: MutableRange): boolean {
1274+
return range.end > range.start + 1;
1275+
}
1276+
12731277
/**
12741278
* The reason for the kind of a value.
12751279
*/

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
InstructionId,
44
Place,
55
ReactiveScope,
6+
isRangeMutable,
67
makeInstructionId,
78
} from ".";
89
import { getPlaceScope } from "../ReactiveScopes/BuildReactiveBlocks";
@@ -124,6 +125,9 @@ export function mergeOverlappingReactiveScopesHIR(fn: HIRFunction): void {
124125
const nextScope = joinedScopes.find(originalScope);
125126
if (nextScope !== null && nextScope !== originalScope) {
126127
place.identifier.scope = nextScope;
128+
if (isRangeMutable(place.identifier.mutableRange)) {
129+
place.identifier.mutableRange = nextScope.range;
130+
}
127131
}
128132
}
129133
}

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import type {
3535
Terminal,
3636
Type,
3737
} from "./HIR";
38-
import { GotoVariant, InstructionKind } from "./HIR";
38+
import { GotoVariant, InstructionKind, isRangeMutable } from "./HIR";
3939

4040
export type Options = {
4141
indent: number;
@@ -716,10 +716,6 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
716716
return value;
717717
}
718718

719-
function isMutable(range: MutableRange): boolean {
720-
return range.end > range.start + 1;
721-
}
722-
723719
const DEBUG_MUTABLE_RANGES = false;
724720
function printMutableRange(identifier: Identifier): string {
725721
if (DEBUG_MUTABLE_RANGES) {
@@ -732,11 +728,11 @@ function printMutableRange(identifier: Identifier): string {
732728
) {
733729
return `[${range.start}:${range.end}] scope=[${scopeRange.start}:${scopeRange.end}]`;
734730
}
735-
return isMutable(range) ? `[${range.start}:${range.end}]` : "";
731+
return isRangeMutable(range) ? `[${range.start}:${range.end}]` : "";
736732
}
737733
// in non-debug mode, prefer the scope range if it exists
738734
const range = identifier.scope?.range ?? identifier.mutableRange;
739-
return isMutable(range) ? `[${range.start}:${range.end}]` : "";
735+
return isRangeMutable(range) ? `[${range.start}:${range.end}]` : "";
740736
}
741737

742738
export function printLValue(lval: LValue): string {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
HIRFunction,
1010
IdentifierId,
1111
ReactiveScope,
12+
isRangeMutable,
1213
makeInstructionId,
1314
} from "../HIR";
1415
import DisjointSet from "../Utils/DisjointSet";
@@ -69,10 +70,19 @@ export function alignMethodCallScopes(fn: HIRFunction): void {
6970
const mappedScope = scopeMapping.get(instr.lvalue.identifier.id);
7071
if (mappedScope !== undefined) {
7172
instr.lvalue.identifier.scope = mappedScope;
73+
if (
74+
mappedScope != null &&
75+
isRangeMutable(instr.lvalue.identifier.mutableRange)
76+
) {
77+
instr.lvalue.identifier.mutableRange = mappedScope.range;
78+
}
7279
} else if (instr.lvalue.identifier.scope !== null) {
7380
const mergedScope = mergedScopes.find(instr.lvalue.identifier.scope);
7481
if (mergedScope != null) {
7582
instr.lvalue.identifier.scope = mergedScope;
83+
if (isRangeMutable(instr.lvalue.identifier.mutableRange)) {
84+
instr.lvalue.identifier.mutableRange = mergedScope.range;
85+
}
7686
}
7787
}
7888
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
HIRFunction,
1212
Identifier,
1313
ReactiveScope,
14+
isRangeMutable,
1415
makeInstructionId,
1516
} from "../HIR";
1617
import { eachInstructionValueOperand } from "../HIR/visitors";
@@ -93,6 +94,9 @@ export function alignObjectMethodScopes(fn: HIRFunction): void {
9394
const root = scopeGroupsMap.get(identifier.scope);
9495
if (root != null) {
9596
identifier.scope = root;
97+
if (isRangeMutable(identifier.mutableRange)) {
98+
identifier.mutableRange = root.range;
99+
}
96100
}
97101
// otherwise, this identifier's scope was not affected by this pass
98102
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77

88
import {
99
HIRFunction,
10+
Identifier,
1011
IdentifierId,
1112
makeInstructionId,
1213
Place,
1314
ReactiveValue,
15+
isRangeMutable,
1416
} from "../HIR";
1517
import { eachReactiveValueOperand } from "./visitors";
1618

@@ -134,6 +136,9 @@ function visit(
134136
*/
135137
for (const operand of eachReactiveValueOperand(value)) {
136138
operand.identifier.scope = fbtScope;
139+
if (isRangeMutable(operand.identifier.mutableRange)) {
140+
operand.identifier.mutableRange = fbtScope.range;
141+
}
137142

138143
// Expand the jsx element's range to account for its operands
139144
fbtScope.range.start = makeInstructionId(
@@ -167,6 +172,9 @@ function visit(
167172
continue;
168173
}
169174
operand.identifier.scope = fbtScope;
175+
if (isRangeMutable(operand.identifier.mutableRange)) {
176+
operand.identifier.mutableRange = fbtScope.range;
177+
}
170178

171179
// Expand the jsx element's range to account for its operands
172180
fbtScope.range.start = makeInstructionId(

0 commit comments

Comments
 (0)