[compiler] Add Identifier.declarationId
Adds `Identifier.declarationId` and the new `DeclarationId` (simulated) opaque type. DeclarationId allows uniquely identifying a variable in the original source, ie regardless of reassignments. This allows us to stay in SSA form throughout compilation (see next diff) while still being able to distinguish SSA versions (via IdentifierId) and non-SSA versions (DeclarationId). ghstack-source-id: f2547a58aa7b30cea29fcfe23d5cb45583858a4e Pull Request resolved: https://github.com/facebook/react/pull/30569
Joe Savona committed
Aug 6, 2024 at 11:24 UTC
22360089b5e40ccfa5df26f1ec491b5c46e7ad61
4 files changed
+39
-40
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
+29
-3
@@ -1174,11 +1174,19 @@ export type NonLocalBinding =
1174
1175
// Represents a user-defined variable (has a name) or a temporary variable (no name).
1176
export type Identifier = {
1177
- /*
1178
- * unique value to distinguish a variable, since name is not guaranteed to
1179
- * exist or be unique
1177
+ /**
1178
+ * After EnterSSA, `id` uniquely identifies an SSA instance of a variable.
1179
+ * Before EnterSSA, `id` matches `declarationId`.
1180
*/
1181
id: IdentifierId;
1182
+
1183
+ /**
1184
+ * Uniquely identifies a given variable in the original program. If a value is
1185
+ * reassigned in the original program each reassigned value will have a distinct
1186
+ * `id` (after EnterSSA), but they will still have the same `declarationId`.
1187
+ */
1188
+ declarationId: DeclarationId;
1189
+
1190
// null for temporaries. name is primarily used for debugging.
1191
name: IdentifierName | null;
1192
// The range for which this variable is mutable
@@ -1212,6 +1220,7 @@ export function makeTemporaryIdentifier(
1220
return {
1221
id,
1222
name: null,
1223
+ declarationId: makeDeclarationId(id),
1224
mutableRange: {start: makeInstructionId(0), end: makeInstructionId(0)},
1225
scope: null,
1226
type: makeType(),
@@ -1508,6 +1517,23 @@ export function makeIdentifierId(id: number): IdentifierId {
1517
return id as IdentifierId;
1518
}
1519
1520
+/*
1521
+ * Simulated opaque type for IdentifierId to prevent using normal numbers as ids
1522
+ * accidentally.
1523
+ */
1524
+const opageDeclarationId = Symbol();
1525
+export type DeclarationId = number & {[opageDeclarationId]: 'DeclarationId'};
1526
+
1527
+export function makeDeclarationId(id: number): DeclarationId {
1528
+ CompilerError.invariant(id >= 0 && Number.isInteger(id), {
1529
+ reason: 'Expected declaration id to be a non-negative integer',
1530
+ description: null,
1531
+ loc: null,
1532
+ suggestions: null,
1533
+ });
1534
+ return id as DeclarationId;
1535
+}
1536
+
1537
/*
1538
* Simulated opaque type for InstructionId to prevent using normal numbers as ids
1539
* accidentally.
compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts
+2
@@ -25,6 +25,7 @@ import {
25
Terminal,
26
VariableBinding,
27
makeBlockId,
28
+ makeDeclarationId,
29
makeIdentifierName,
30
makeInstructionId,
31
makeTemporaryIdentifier,
@@ -320,6 +321,7 @@ export default class HIRBuilder {
321
const id = this.nextIdentifierId;
322
const identifier: Identifier = {
323
id,
324
+ declarationId: makeDeclarationId(id),
325
name: makeIdentifierName(name),
326
mutableRange: {
327
start: makeInstructionId(0),
compiler/packages/babel-plugin-react-compiler/src/Inference/InlineImmediatelyInvokedFunctionExpressions.ts
+7
-37
@@ -8,7 +8,6 @@
8
import {
9
BasicBlock,
10
BlockId,
11
- Effect,
11
Environment,
12
FunctionExpression,
13
GeneratedSource,
@@ -19,11 +18,14 @@ import {
18
LabelTerminal,
19
Place,
20
makeInstructionId,
22
- makeType,
21
promoteTemporary,
22
reversePostorderBlocks,
23
} from '../HIR';
26
-import {markInstructionIds, markPredecessors} from '../HIR/HIRBuilder';
24
+import {
25
+ createTemporaryPlace,
26
+ markInstructionIds,
27
+ markPredecessors,
28
+} from '../HIR/HIRBuilder';
29
import {eachInstructionValueOperand} from '../HIR/visitors';
30
import {retainWhere} from '../Utils/utils';
31
@@ -225,23 +227,7 @@ function rewriteBlock(
227
block.instructions.push({
228
id: makeInstructionId(0),
229
loc: terminal.loc,
228
- lvalue: {
229
- effect: Effect.Unknown,
230
- identifier: {
231
- id: env.nextIdentifierId,
232
- mutableRange: {
233
- start: makeInstructionId(0),
234
- end: makeInstructionId(0),
235
- },
236
- name: null,
237
- scope: null,
238
- type: makeType(),
239
- loc: terminal.loc,
240
- },
241
- kind: 'Identifier',
242
- reactive: false,
243
- loc: terminal.loc,
244
- },
230
+ lvalue: createTemporaryPlace(env, terminal.loc),
231
value: {
232
kind: 'StoreLocal',
233
lvalue: {kind: InstructionKind.Reassign, place: {...returnValue}},
@@ -267,23 +253,7 @@ function declareTemporary(
253
block.instructions.push({
254
id: makeInstructionId(0),
255
loc: GeneratedSource,
270
- lvalue: {
271
- effect: Effect.Unknown,
272
- identifier: {
273
- id: env.nextIdentifierId,
274
- mutableRange: {
275
- start: makeInstructionId(0),
276
- end: makeInstructionId(0),
277
- },
278
- name: null,
279
- scope: null,
280
- type: makeType(),
281
- loc: result.loc,
282
- },
283
- kind: 'Identifier',
284
- reactive: false,
285
- loc: GeneratedSource,
286
- },
256
+ lvalue: createTemporaryPlace(env, result.loc),
257
value: {
258
kind: 'DeclareLocal',
259
lvalue: {
compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts
+1
@@ -79,6 +79,7 @@ class SSABuilder {
79
makeId(oldId: Identifier): Identifier {
80
return {
81
id: this.nextSsaId,
82
+ declarationId: oldId.declarationId,
83
name: oldId.name,
84
mutableRange: {
85
start: makeInstructionId(0),