mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Summary:
The fact that phis are identifiers rather than places is unfortunate in a few cases. In some later analyses, we might wish to know whether a phi is reactive, but we don't have an easy way to do that currently.
Most of the changes here is just replacing phi.id with phi.place.identifier and such. Interesting bits are EnterSSA (several functions now take places rather than identifiers, and InferReactivePlaces now needs to mark places as reactive explicitly.
ghstack-source-id: 5f4fb396cd
Pull Request resolved: https://github.com/facebook/react/pull/31171
85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import {CompilerError} from '../CompilerError';
|
|
import {
|
|
GeneratedSource,
|
|
HIRFunction,
|
|
Identifier,
|
|
IdentifierId,
|
|
SourceLocation,
|
|
} from './HIR';
|
|
import {printPlace} from './PrintHIR';
|
|
import {
|
|
eachInstructionLValue,
|
|
eachInstructionValueOperand,
|
|
eachTerminalOperand,
|
|
} from './visitors';
|
|
|
|
/*
|
|
* Validation pass to check that there is a 1:1 mapping between Identifier objects and IdentifierIds,
|
|
* ie there can only be one Identifier instance per IdentifierId.
|
|
*/
|
|
export function assertConsistentIdentifiers(fn: HIRFunction): void {
|
|
const identifiers: Identifiers = new Map();
|
|
const assignments: Set<IdentifierId> = new Set();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
validate(identifiers, phi.place.identifier);
|
|
for (const [, operand] of phi.operands) {
|
|
validate(identifiers, operand.identifier);
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
CompilerError.invariant(instr.lvalue.identifier.name === null, {
|
|
reason: `Expected all lvalues to be temporaries`,
|
|
description: `Found named lvalue \`${instr.lvalue.identifier.name}\``,
|
|
loc: instr.lvalue.loc,
|
|
suggestions: null,
|
|
});
|
|
CompilerError.invariant(!assignments.has(instr.lvalue.identifier.id), {
|
|
reason: `Expected lvalues to be assigned exactly once`,
|
|
description: `Found duplicate assignment of '${printPlace(
|
|
instr.lvalue,
|
|
)}'`,
|
|
loc: instr.lvalue.loc,
|
|
suggestions: null,
|
|
});
|
|
assignments.add(instr.lvalue.identifier.id);
|
|
for (const operand of eachInstructionLValue(instr)) {
|
|
validate(identifiers, operand.identifier, operand.loc);
|
|
}
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validate(identifiers, operand.identifier, operand.loc);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
validate(identifiers, operand.identifier, operand.loc);
|
|
}
|
|
}
|
|
}
|
|
|
|
type Identifiers = Map<IdentifierId, Identifier>;
|
|
|
|
function validate(
|
|
identifiers: Identifiers,
|
|
identifier: Identifier,
|
|
loc: SourceLocation | null = null,
|
|
): void {
|
|
const previous = identifiers.get(identifier.id);
|
|
if (previous === undefined) {
|
|
identifiers.set(identifier.id, identifier);
|
|
} else {
|
|
CompilerError.invariant(identifier === previous, {
|
|
reason: `Duplicate identifier object`,
|
|
description: `Found duplicate identifier object for id ${identifier.id}`,
|
|
loc: loc ?? GeneratedSource,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|