Distinguish internal invariant passes from user code validation

Distinguishes between two types of "validation" passes: 

- Passes which assert the validity of the HIR. These remain in HIR/ but are 
renamed "assertFoo". 

- Passes which validate that the user code is correct. These move to 
Validation/.
This commit is contained in:
Joe Savona
2023-06-20 15:16:57 -07:00
parent bbb5840e73
commit fa913b423e
10 changed files with 52 additions and 34 deletions
@@ -9,15 +9,11 @@ import { NodePath } from "@babel/traverse";
import * as t from "@babel/types";
import {
HIRFunction,
ReactiveFunction,
assertConsistentIdentifiers,
assertTerminalSuccessorsExist,
lower,
mergeConsecutiveBlocks,
ReactiveFunction,
validateConsistentIdentifiers,
validateFrozenLambdas,
validateHooksUsage,
validateNoRefAccessInRender,
validateTerminalSuccessors,
validateUnconditionalHooks,
} from "../HIR";
import { Environment, EnvironmentConfig } from "../HIR/Environment";
import { findContextIdentifiers } from "../HIR/FindContextIdentifiers";
@@ -45,8 +41,8 @@ import {
pruneAllReactiveScopes,
pruneNonEscapingScopes,
pruneNonReactiveDependencies,
pruneUnusedLabels,
pruneUnusedLValues,
pruneUnusedLabels,
pruneUnusedScopes,
renameVariables,
} from "../ReactiveScopes";
@@ -54,6 +50,12 @@ import { eliminateRedundantPhi, enterSSA, leaveSSA } from "../SSA";
import { inferTypes } from "../TypeInference";
import { logHIRFunction, logReactiveFunction } from "../Utils/logger";
import { assertExhaustive } from "../Utils/utils";
import {
validateFrozenLambdas,
validateHooksUsage,
validateNoRefAccessInRender,
validateUnconditionalHooks,
} from "../Validation";
export type CompilerPipelineValue =
| { kind: "ast"; name: string; value: t.FunctionDeclaration }
@@ -78,8 +80,8 @@ export function* run(
mergeConsecutiveBlocks(hir);
yield log({ kind: "hir", name: "MergeConsecutiveBlocks", value: hir });
validateConsistentIdentifiers(hir);
validateTerminalSuccessors(hir);
assertConsistentIdentifiers(hir);
assertTerminalSuccessorsExist(hir);
enterSSA(hir);
yield log({ kind: "hir", name: "SSA", value: hir });
@@ -87,7 +89,7 @@ export function* run(
eliminateRedundantPhi(hir);
yield log({ kind: "hir", name: "EliminateRedundantPhi", value: hir });
validateConsistentIdentifiers(hir);
assertConsistentIdentifiers(hir);
constantPropagation(hir);
yield log({ kind: "hir", name: "ConstantPropagation", value: hir });
@@ -24,7 +24,7 @@ import {
* 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 validateConsistentIdentifiers(fn: HIRFunction): void {
export function assertConsistentIdentifiers(fn: HIRFunction): void {
const identifiers: Identifiers = new Map();
const assignments: Set<IdentifierId> = new Set();
for (const [, block] of fn.body.blocks) {
@@ -10,7 +10,7 @@ import { GeneratedSource, HIRFunction } from "./HIR";
import { printTerminal } from "./PrintHIR";
import { mapTerminalSuccessors } from "./visitors";
export function validateTerminalSuccessors(fn: HIRFunction): void {
export function assertTerminalSuccessorsExist(fn: HIRFunction): void {
for (const [, block] of fn.body.blocks) {
mapTerminalSuccessors(block.terminal, (successor) => {
if (!fn.body.blocks.has(successor)) {
@@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/
export { assertConsistentIdentifiers } from "./AssertConsistentIdentifiers";
export { assertTerminalSuccessorsExist } from "./AssertTerminalSuccessorsExist";
export { lower } from "./BuildHIR";
export { computeDominatorTree, computePostDominatorTree } from "./Dominator";
export { Environment, Hook } from "./Environment";
@@ -17,9 +19,3 @@ export {
} from "./HIRBuilder";
export { mergeConsecutiveBlocks } from "./MergeConsecutiveBlocks";
export { printFunction, printHIR } from "./PrintHIR";
export { validateConsistentIdentifiers } from "./ValidateConsistentIdentifiers";
export { validateFrozenLambdas } from "./ValidateFrozenLambdas";
export { validateHooksUsage } from "./ValidateHooksUsage";
export { validateNoRefAccessInRender } from "./ValidateNoRefAccesInRender";
export { validateTerminalSuccessors } from "./ValidateTerminalSuccessors";
export { validateUnconditionalHooks } from "./ValidateUnconditionalHooks";
@@ -14,15 +14,15 @@ import {
Instruction,
InstructionValue,
LoadGlobal,
Place,
Primitive,
assertConsistentIdentifiers,
assertTerminalSuccessorsExist,
markInstructionIds,
markPredecessors,
mergeConsecutiveBlocks,
Place,
Primitive,
removeUnreachableFallthroughs,
reversePostorderBlocks,
validateConsistentIdentifiers,
validateTerminalSuccessors,
} from "../HIR";
import {
removeDeadDoWhileStatements,
@@ -81,8 +81,8 @@ function constantPropagationImpl(fn: HIRFunction, constants: Constants): void {
// consecutively
mergeConsecutiveBlocks(fn);
validateConsistentIdentifiers(fn);
validateTerminalSuccessors(fn);
assertConsistentIdentifiers(fn);
assertTerminalSuccessorsExist(fn);
}
}
@@ -18,8 +18,11 @@ import {
Place,
isRefValueType,
isUseRefType,
} from "./HIR";
import { eachInstructionValueOperand, eachTerminalOperand } from "./visitors";
} from "../HIR/HIR";
import {
eachInstructionValueOperand,
eachTerminalOperand,
} from "../HIR/visitors";
/**
* Various APIs in React take ownership of the values passed to them, such that it is invalid
@@ -10,9 +10,12 @@ import {
CompilerErrorDetail,
ErrorSeverity,
} from "../CompilerError";
import { HIRFunction, IdentifierId, Place, getHookKind } from "../HIR/HIR";
import {
eachInstructionValueOperand,
eachTerminalOperand,
} from "../HIR/visitors";
import { hasBackEdge } from "../Optimization/DeadCodeElimination";
import { HIRFunction, IdentifierId, Place, getHookKind } from "./HIR";
import { eachInstructionValueOperand, eachTerminalOperand } from "./visitors";
/**
* Validates that the function honors the [Rules of Hooks](https://react.dev/warnings/invalid-hook-call-warning)
@@ -10,9 +10,12 @@ import {
CompilerErrorDetail,
ErrorSeverity,
} from "../CompilerError";
import { HIRFunction, Place, isRefValueType, isUseRefType } from "./HIR";
import { printPlace } from "./PrintHIR";
import { eachInstructionValueOperand, eachTerminalOperand } from "./visitors";
import { HIRFunction, Place, isRefValueType, isUseRefType } from "../HIR/HIR";
import { printPlace } from "../HIR/PrintHIR";
import {
eachInstructionValueOperand,
eachTerminalOperand,
} from "../HIR/visitors";
/**
* Validates that ref values (the `current` property) are not accessed during render.
@@ -10,10 +10,10 @@ import {
CompilerErrorDetail,
ErrorSeverity,
} from "../CompilerError";
import { PostDominator, computePostDominatorTree } from "../HIR/Dominator";
import { BlockId, HIRFunction, getHookKind } from "../HIR/HIR";
import { findBlocksWithBackEdges } from "../Optimization/DeadCodeElimination";
import { Err, Ok, Result } from "../Utils/Result";
import { PostDominator, computePostDominatorTree } from "./Dominator";
import { BlockId, HIRFunction, getHookKind } from "./HIR";
/**
* Validates that the function honors the [Rules of Hooks](https://react.dev/warnings/invalid-hook-call-warning)
@@ -0,0 +1,11 @@
/**
* 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.
*/
export { validateFrozenLambdas } from "./ValidateFrozenLambdas";
export { validateHooksUsage } from "./ValidateHooksUsage";
export { validateNoRefAccessInRender } from "./ValidateNoRefAccesInRender";
export { validateUnconditionalHooks } from "./ValidateUnconditionalHooks";