diff --git a/compiler/forget/src/HIR/InferReactiveScopes.ts b/compiler/forget/src/HIR/InferReactiveScopes.ts new file mode 100644 index 0000000000..27af18aff5 --- /dev/null +++ b/compiler/forget/src/HIR/InferReactiveScopes.ts @@ -0,0 +1,99 @@ +/** + * 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 { HIRFunction } from "./HIR"; + +/** + * This is a second (final) stage of constructing reactive scopes. Prior to this pass, + * InferReactiveScopeVariables infers the sets of identifiers that "construct together", + * assigning each identifier in each scope the same ScopeId and same MutableRange which + * describes that span. + * + * Note that at this point reactive scopes describe ranges based on specific instructions + * at arbitrary points in the control flow graph. However, reactive scopes must align + * with control-flow boundaries — we can't memoize half of a loop! + * + * This pass refines the reactive scopes as follows: + * + * ## Expanding each reactive scope to align with control-flow boundaries + * + * This corresponds with the shape of the AST: a scope that extends into an if consequent + * would expand across the alternate branch, A scope that extends partway into an if + * would expand to cover the full loop body, etc. + * + * ```javascript + * function foo(cond, a) { + * ⌵ original scope + * ⌵ expanded scope + * const x = []; ⌝ ⌝ + * if (cond) { ⎮ ⎮ + * ... ⎮ ⎮ + * x.push(a); ⌟ ⎮ + * ... ⎮ + * } ⌟ + * } + * ``` + * + * ## Merging (some) overlapping reactive scopes + * + * Two scopes overlap if there is one or more instruction that is inside the range + * of both scopes. In general, overlapping scopes are merged togther. The only + * exception to this is when one scope *shadows* another scope. For example: + * + * ```javascript + * function foo(cond, a) { + * ⌵ scope for x + * let x = []; ⌝ + * if (cond) { ⎮ + * ⌵ scope for y ⎮ + * let y = []; ⌝ ⎮ + * if (b) { ⎮ ⎮ + * y.push(b); ⌟ ⎮ + * } ⎮ + * x.push(