FlattenScopesWithHooksOrUseHIR.ts — react Source File
Architecture documentation for FlattenScopesWithHooksOrUseHIR.ts, a typescript file in the react codebase. 4 imports, 1 dependents.
Entity Profile
Dependency Diagram
graph LR 65735af7_dc59_7bd9_83bb_e14ac6df06ed["FlattenScopesWithHooksOrUseHIR.ts"] 0423f759_97e0_9101_4634_ed555abc5ca9["index.ts"] 65735af7_dc59_7bd9_83bb_e14ac6df06ed --> 0423f759_97e0_9101_4634_ed555abc5ca9 eb9d33f9_42c1_205c_93e6_8e1365a31839["utils.ts"] 65735af7_dc59_7bd9_83bb_e14ac6df06ed --> eb9d33f9_42c1_205c_93e6_8e1365a31839 c447b97e_0b8e_b187_e3a8_4be412d6f495["retainWhere"] 65735af7_dc59_7bd9_83bb_e14ac6df06ed --> c447b97e_0b8e_b187_e3a8_4be412d6f495 2ed45bcd_6c82_3ccd_0e20_fa96b5111055[".."] 65735af7_dc59_7bd9_83bb_e14ac6df06ed --> 2ed45bcd_6c82_3ccd_0e20_fa96b5111055 e3cfc07a_10c8_5dcd_e270_e8e14c29309b["Pipeline.ts"] e3cfc07a_10c8_5dcd_e270_e8e14c29309b --> 65735af7_dc59_7bd9_83bb_e14ac6df06ed style 65735af7_dc59_7bd9_83bb_e14ac6df06ed fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
/**
* 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 '..';
import {
BlockId,
HIRFunction,
LabelTerminal,
PrunedScopeTerminal,
getHookKind,
isUseOperator,
} from '../HIR';
import {retainWhere} from '../Utils/utils';
/**
* For simplicity the majority of compiler passes do not treat hooks specially. However, hooks are different
* from regular functions in two key ways:
* - They can introduce reactivity even when their arguments are non-reactive (accounted for in InferReactivePlaces)
* - They cannot be called conditionally
*
* The `use` operator is similar:
* - It can access context, and therefore introduce reactivity
* - It can be called conditionally, but _it must be called if the component needs the return value_. This is because
* React uses the fact that use was called to remember that the component needs the value, and that changes to the
* input should invalidate the component itself.
*
* This pass accounts for the "can't call conditionally" aspect of both hooks and use. Though the reasoning is slightly
* different for reach, the result is that we can't memoize scopes that call hooks or use since this would make them
* called conditionally in the output.
*
* The pass finds and removes any scopes that transitively contain a hook or use call. By running all
* the reactive scope inference first, agnostic of hooks, we know that the reactive scopes accurately
* describe the set of values which "construct together", and remove _all_ that memoization in order
* to ensure the hook call does not inadvertently become conditional.
*/
export function flattenScopesWithHooksOrUseHIR(fn: HIRFunction): void {
const activeScopes: Array<{block: BlockId; fallthrough: BlockId}> = [];
const prune: Array<BlockId> = [];
for (const [, block] of fn.body.blocks) {
retainWhere(activeScopes, current => current.fallthrough !== block.id);
for (const instr of block.instructions) {
const {value} = instr;
switch (value.kind) {
case 'MethodCall':
case 'CallExpression': {
const callee =
value.kind === 'MethodCall' ? value.property : value.callee;
if (
getHookKind(fn.env, callee.identifier) != null ||
isUseOperator(callee.identifier)
) {
prune.push(...activeScopes.map(entry => entry.block));
activeScopes.length = 0;
}
}
}
}
if (block.terminal.kind === 'scope') {
activeScopes.push({
block: block.id,
fallthrough: block.terminal.fallthrough,
});
}
}
for (const id of prune) {
const block = fn.body.blocks.get(id)!;
const terminal = block.terminal;
CompilerError.invariant(terminal.kind === 'scope', {
reason: `Expected block to have a scope terminal`,
description: `Expected block bb${block.id} to end in a scope terminal`,
loc: terminal.loc,
});
const body = fn.body.blocks.get(terminal.block)!;
if (
body.instructions.length === 1 &&
body.terminal.kind === 'goto' &&
body.terminal.block === terminal.fallthrough
) {
/*
* This was a scope just for a hook call, which doesn't need memoization.
* flatten it away. We rely on the PrunedUnusedLabel step to do the actual
* flattening
*/
block.terminal = {
kind: 'label',
block: terminal.block,
fallthrough: terminal.fallthrough,
id: terminal.id,
loc: terminal.loc,
} as LabelTerminal;
continue;
}
block.terminal = {
kind: 'pruned-scope',
block: terminal.block,
fallthrough: terminal.fallthrough,
id: terminal.id,
loc: terminal.loc,
scope: terminal.scope,
} as PrunedScopeTerminal;
}
}
Domain
Subdomains
Functions
Dependencies
Source
Frequently Asked Questions
What does FlattenScopesWithHooksOrUseHIR.ts do?
FlattenScopesWithHooksOrUseHIR.ts is a source file in the react codebase, written in typescript. It belongs to the BabelCompiler domain, Validation subdomain.
What functions are defined in FlattenScopesWithHooksOrUseHIR.ts?
FlattenScopesWithHooksOrUseHIR.ts defines 1 function(s): flattenScopesWithHooksOrUseHIR.
What does FlattenScopesWithHooksOrUseHIR.ts depend on?
FlattenScopesWithHooksOrUseHIR.ts imports 4 module(s): .., index.ts, retainWhere, utils.ts.
What files import FlattenScopesWithHooksOrUseHIR.ts?
FlattenScopesWithHooksOrUseHIR.ts is imported by 1 file(s): Pipeline.ts.
Where is FlattenScopesWithHooksOrUseHIR.ts in the architecture?
FlattenScopesWithHooksOrUseHIR.ts is located at compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts (domain: BabelCompiler, subdomain: Validation, directory: compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes).
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free