mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Invariant for use before definition of reactive values (#662)
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import type { CompilerContext } from "../CompilerContext";
|
||||
import { OutputKind } from "../CompilerOutputs";
|
||||
import * as LIR from "../LIR";
|
||||
import * as IR from "../IR";
|
||||
import { PassKind, PassName } from "../Pass";
|
||||
import { assertExhaustive } from "../Common/utils";
|
||||
import invariant from "invariant";
|
||||
import { isReactiveBlock, isRenderBlock } from "../LIR";
|
||||
|
||||
/**
|
||||
* An optional debug step when the output {@link OutputKind.IR} is enabled.
|
||||
* Records the output IR in the compiler context.
|
||||
*/
|
||||
export default {
|
||||
name: PassName.DumpIR,
|
||||
kind: PassKind.LIRFunc as const,
|
||||
run,
|
||||
};
|
||||
|
||||
export function run(
|
||||
lirFunc: LIR.Func,
|
||||
_func: NodePath<t.Function>,
|
||||
_context: CompilerContext
|
||||
) {
|
||||
const irFunc = lirFunc.ir;
|
||||
|
||||
const reactiveValues = new Set<string>();
|
||||
function defineReactiveVal(value: IR.ReactiveVal) {
|
||||
const name = value.binding.identifier.name;
|
||||
reactiveValues.add(name);
|
||||
}
|
||||
|
||||
function useReactiveValues(values: Set<IR.ReactiveVal>) {
|
||||
for (const reactiveValue of values) {
|
||||
const name = reactiveValue.binding.identifier.name;
|
||||
invariant(
|
||||
reactiveValues.has(name),
|
||||
`Reactive value "${name}" not yet defined.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const param of irFunc.params) {
|
||||
if (IR.isReactiveVal(param)) {
|
||||
defineReactiveVal(param);
|
||||
}
|
||||
}
|
||||
|
||||
function visitJSX(expr: IR.ExprVal) {
|
||||
if (IR.isJSXTagVal(expr)) {
|
||||
expr.children.forEach((child) => visitJSX(child));
|
||||
}
|
||||
if (!expr.stable) {
|
||||
const entry = lirFunc.memoCache.entries.get(expr);
|
||||
if (entry) {
|
||||
invariant(LIR.MemoCache.isExprEntry(entry), "");
|
||||
const { inputs } = irFunc.depGraph.getOrCreateVertex(entry.value);
|
||||
useReactiveValues(inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const block of lirFunc.blocks) {
|
||||
switch (block.kind) {
|
||||
case LIR.BlockKind.Render:
|
||||
invariant(isRenderBlock(block), "Expected render block");
|
||||
for (const instr of block.body) {
|
||||
for (const decl of instr.ir.decls) {
|
||||
if (IR.isReactiveVal(decl)) {
|
||||
defineReactiveVal(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LIR.BlockKind.Reactive:
|
||||
invariant(isReactiveBlock(block), "Expected reactive block");
|
||||
useReactiveValues(block.inputs);
|
||||
for (const instr of block.body) {
|
||||
instr.ir.jsxTreeRoots.forEach((root) => {
|
||||
visitJSX(root);
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assertExhaustive(block.kind, `Unhandled block ${block}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,3 +14,4 @@ export { default as DumpLIR } from "./DumpLIR";
|
||||
export { default as JSGen } from "./JSGen";
|
||||
export { default as LIRGen } from "./LIRGen";
|
||||
export { default as MemoCacheAlloc } from "./MemoCacheAlloc";
|
||||
export { default as SanityCheck } from "./SanityCheck";
|
||||
|
||||
@@ -53,6 +53,7 @@ export function createCompilerDriver(
|
||||
passManager.addPass(BE.LIRGen);
|
||||
passManager.addPass(BE.MemoCacheAlloc);
|
||||
passManager.addPass(BE.DumpLIR);
|
||||
passManager.addPass(BE.SanityCheck);
|
||||
|
||||
// JS Generation.
|
||||
passManager.addPass(BE.JSGen);
|
||||
|
||||
Reference in New Issue
Block a user