main
ts 79 lines 2.07 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {
9 ReactiveFunction,
10 ReactiveScopeBlock,
11 ReactiveStatement,
12 ReactiveTerminalStatement,
13 } from '../HIR/HIR';
14 import {
15 ReactiveFunctionTransform,
16 Transformed,
17 visitReactiveFunction,
18 } from './visitors';
19
20 // Converts scopes without outputs into regular blocks.
21 export function pruneUnusedScopes(fn: ReactiveFunction): void {
22 visitReactiveFunction(fn, new Transform(), {
23 hasReturnStatement: false,
24 } as State);
25 }
26
27 type State = {
28 hasReturnStatement: boolean;
29 };
30
31 class Transform extends ReactiveFunctionTransform<State> {
32 override visitTerminal(stmt: ReactiveTerminalStatement, state: State): void {
33 this.traverseTerminal(stmt, state);
34 if (stmt.terminal.kind === 'return') {
35 state.hasReturnStatement = true;
36 }
37 }
38 override transformScope(
39 scopeBlock: ReactiveScopeBlock,
40 _state: State,
41 ): Transformed<ReactiveStatement> {
42 const scopeState: State = {hasReturnStatement: false};
43 this.visitScope(scopeBlock, scopeState);
44 if (
45 !scopeState.hasReturnStatement &&
46 scopeBlock.scope.reassignments.size === 0 &&
47 (scopeBlock.scope.declarations.size === 0 ||
48 /*
49 * Can prune scopes where all declarations bubbled up from inner
50 * scopes
51 */
52 !hasOwnDeclaration(scopeBlock))
53 ) {
54 return {
55 kind: 'replace',
56 value: {
57 kind: 'pruned-scope',
58 scope: scopeBlock.scope,
59 instructions: scopeBlock.instructions,
60 },
61 };
62 } else {
63 return {kind: 'keep'};
64 }
65 }
66 }
67
68 /*
69 * Does the scope block declare any values of its own? This can return
70 * false if all the block's declarations are propagated from nested scopes.
71 */
72 function hasOwnDeclaration(block: ReactiveScopeBlock): boolean {
73 for (const declaration of block.scope.declarations.values()) {
74 if (declaration.scope.id === block.scope.id) {
75 return true;
76 }
77 }
78 return false;
79 }