main
ts 71 lines 2.09 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 {BlockId, HIRFunction, PrunedScopeTerminal} from '../HIR';
9 import {assertExhaustive, retainWhere} from '../Utils/utils';
10
11 /**
12 * Prunes any reactive scopes that are within a loop (for, while, etc). We don't yet
13 * support memoization within loops because this would require an extra layer of reconciliation
14 * (plus a way to identify values across runs, similar to how we use `key` in JSX for lists).
15 * Eventually we may integrate more deeply into the runtime so that we can do a single level
16 * of reconciliation, but for now we've found it's sufficient to memoize *around* the loop.
17 */
18 export function flattenReactiveLoopsHIR(fn: HIRFunction): void {
19 const activeLoops = Array<BlockId>();
20 for (const [, block] of fn.body.blocks) {
21 retainWhere(activeLoops, id => id !== block.id);
22 const {terminal} = block;
23 switch (terminal.kind) {
24 case 'do-while':
25 case 'for':
26 case 'for-in':
27 case 'for-of':
28 case 'while': {
29 activeLoops.push(terminal.fallthrough);
30 break;
31 }
32 case 'scope': {
33 if (activeLoops.length !== 0) {
34 block.terminal = {
35 kind: 'pruned-scope',
36 block: terminal.block,
37 fallthrough: terminal.fallthrough,
38 id: terminal.id,
39 loc: terminal.loc,
40 scope: terminal.scope,
41 } as PrunedScopeTerminal;
42 }
43 break;
44 }
45 case 'branch':
46 case 'goto':
47 case 'if':
48 case 'label':
49 case 'logical':
50 case 'maybe-throw':
51 case 'optional':
52 case 'pruned-scope':
53 case 'return':
54 case 'sequence':
55 case 'switch':
56 case 'ternary':
57 case 'throw':
58 case 'try':
59 case 'unreachable':
60 case 'unsupported': {
61 break;
62 }
63 default: {
64 assertExhaustive(
65 terminal,
66 `Unexpected terminal kind \`${(terminal as any).kind}\``,
67 );
68 }
69 }
70 }
71 }