diff --git a/compiler/forget/src/CompilerPipeline.ts b/compiler/forget/src/CompilerPipeline.ts index 39196724be..6aff1039f7 100644 --- a/compiler/forget/src/CompilerPipeline.ts +++ b/compiler/forget/src/CompilerPipeline.ts @@ -32,6 +32,7 @@ import { mergeOverlappingReactiveScopes, promoteUsedTemporaries, propagateScopeDependencies, + pruneNonEscapingScopes, pruneNonReactiveDependencies, pruneUnusedLabels, pruneUnusedLValues, @@ -145,6 +146,13 @@ export function* run( value: reactiveFunction, }); + pruneNonEscapingScopes(reactiveFunction); + yield log({ + kind: "reactive", + name: "PruneNonEscapingDependencies", + value: reactiveFunction, + }); + pruneNonReactiveDependencies(reactiveFunction); yield log({ kind: "reactive", diff --git a/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts index 74fad09b1e..a8efaa269a 100644 --- a/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts @@ -84,9 +84,7 @@ function printReactiveInstruction( const id = `[${instruction.id}]`; if (instruction.lvalue !== null) { - writer.write( - `${id} ${printIdentifier(instruction.lvalue.identifier)} = ` - ); + writer.write(`${id} ${printPlace(instruction.lvalue)} = `); printReactiveValue(writer, instruction.value); writer.newline(); } else { diff --git a/compiler/forget/src/ReactiveScopes/PruneNonEscapingScopes.ts b/compiler/forget/src/ReactiveScopes/PruneNonEscapingScopes.ts new file mode 100644 index 0000000000..0c6f8dd8ff --- /dev/null +++ b/compiler/forget/src/ReactiveScopes/PruneNonEscapingScopes.ts @@ -0,0 +1,581 @@ +/** + * 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 invariant from "invariant"; +import prettyFormat from "pretty-format"; +import { CompilerError } from "../CompilerError"; +import { + Effect, + IdentifierId, + InstructionId, + Place, + ReactiveFunction, + ReactiveInstruction, + ReactiveScopeBlock, + ReactiveStatement, + ReactiveTerminal, + ReactiveTerminalStatement, + ReactiveValue, + ScopeId, +} from "../HIR"; +import { eachInstructionLValue } from "../HIR/visitors"; +import { log } from "../Utils/logger"; +import { assertExhaustive } from "../Utils/utils"; +import { getPlaceScope } from "./BuildReactiveBlocks"; +import { printReactiveFunction } from "./PrintReactiveFunction"; +import { + eachReactiveValueOperand, + ReactiveFunctionTransform, + ReactiveFunctionVisitor, + Transformed, + visitReactiveFunction, +} from "./visitors"; + +/** + * This pass prunes reactive scopes that are not necessary to bound downstream computation. + * Specifically, the pass identifies the set of identifiers which are directly returned by + * the function and/or transitively aliased by a return value - ie, values that "escape". + * + * Example to build intuition: + * + * ```javascript + * function Component(props) { + * const a = {}; // not aliased or returned: *not* memoized + * const b = {}; // aliased by c, which is returned: memoized + * const c = [b]; // directly returned: memoized + * return c; + * } + * ``` + * + * However, this logic alone is insufficient for two reasons: + * - Statically memoizing JSX elements *may* be inefficient compared to using dynamic + * memoization with `React.memo()`. Static memoization may be JIT'd and can look at + * the precise props w/o dynamic iteration, but incurs potentially large code-size + * overhead. Dynamic memoization with `React.memo()` incurs potentially increased + * runtime overhead for smaller code size. We plan to experiment with both variants + * for JSX. + * - Because we merge values whose mutations _interleave_ into a single scope, there + * can be cases where a non-escaping value needs to be memoized anyway to avoid breaking + * a memoization input. As a rule, for any scope that has a memoized output, all of that + * scope's transitive dependencies must also be memoized _even if they don't escape_. + * Failing to memoize them would cause the scope to invalidate more often than necessary + * and break downstream memoization. + * + * Example of this second case: + * + * ```javascript + * function Component(props) { + * // a can be independently memoized but it doesn't escape, so naively we may think its + * // safe to not memoize. but not memoizing would break caching of b, which does + * // escape. + * const a = [props.a]; + * + * // b and c are interleaved and grouped into a single scope, + * // but they are independent values. c does not escape, but + * // we need to ensure that a is memoized or else b will invalidate + * // on every render since a is a dependency. + * const b = []; + * const c = {}; + * c.a = a; + * b.push(props.b); + * + * return b; + * } + * ``` + * + * ## Algorithm + * + * 1. First we build up a graph, a mapping of IdentifierId to a node describing all the + * scopes and inputs involved in creating that identifier. Individual nodes are marked + * as definitely aliased, conditionally aliased, or unaliased: + * a. Arrays, objects, function calls all produce a new value and are always marked as aliased + * b. Conditional and logical expressions (and a few others) are conditinally aliased, + * depending on whether their result value is aliased. + * c. JSX is always unaliased (though its props children may be) + * 2. The same pass which builds the graph also stores the set of returned identifiers. + * 3. We traverse the graph starting from the returned identifiers and mark reachable dependencies + * as escaping, based on the combination of the parent node's type and its children (eg a + * conditional node with an aliased dep promotes to aliased). + * 4. Finally we prune scopes whose outputs weren't marked. + */ +export function pruneNonEscapingScopes(fn: ReactiveFunction): void { + // First build up a map of which instructions are involved in creating which values, + // and which values are returned. + const state = new State(); + if (fn.id !== null) { + state.declare(fn.id.id); + } + for (const param of fn.params) { + state.declare(param.identifier.id); + } + visitReactiveFunction(fn, new CollectDependenciesVisitor(), state); + + log(() => prettyFormat(state)); + + // Then walk outward from the returned values and find all captured operands. + // This forms the set of identifiers which should be memoized. + const memoized = computeMemoizedIdentifiers(state); + + log(() => prettyFormat(memoized)); + + log(() => printReactiveFunction(fn)); + + // Prune scopes that do not declare/reassign any escaping values + visitReactiveFunction(fn, new PruneScopesTransform(), memoized); +} + +// Describes how to determine whether a value should be memoized, relative to dependees and dependencies +enum MemoizationLevel { + // The value should be memoized if it escapes + Memoized = "Memoized", + // Values that are memoized if their dependencies are memoized (used for logical/ternary and + // other expressions that propagate dependencies wo changing them) + Conditional = "Conditional", + // Values that cannot be compared with Object.is, but which by default don't need to be memoized + // unless forced + Unmemoized = "Unmemoized", + // The value will never be memoized: used for values that can be cheaply compared w Object.is + Never = "Never", +} + +// Given an identifier that appears as an lvalue multiple times with different memoization levels, +// determines the final memoization level. +function joinAliases( + kind1: MemoizationLevel, + kind2: MemoizationLevel +): MemoizationLevel { + if ( + kind1 === MemoizationLevel.Memoized || + kind2 === MemoizationLevel.Memoized + ) { + return MemoizationLevel.Memoized; + } else if ( + kind1 === MemoizationLevel.Conditional || + kind2 === MemoizationLevel.Conditional + ) { + return MemoizationLevel.Conditional; + } else if ( + kind1 === MemoizationLevel.Unmemoized || + kind2 === MemoizationLevel.Unmemoized + ) { + return MemoizationLevel.Unmemoized; + } else { + return MemoizationLevel.Never; + } +} + +// A node in the graph describing the memoization level of a given identifier as well as its dependencies and scopes. +type IdentifierNode = { + level: MemoizationLevel; + memoized: boolean; + dependencies: Set; + scopes: Set; + seen: boolean; +}; + +// A scope node describing its dependencies +type ScopeNode = { + dependencies: Array; + seen: boolean; +}; + +// Stores the identifier and scope graphs, set of returned identifiers, etc +class State { + // Maps lvalues for LoadLocal to the identifier being loaded, to resolve indirections + // in subsequent lvalues/rvalues + definitions: Map = new Map(); + + identifiers: Map = new Map(); + scopes: Map = new Map(); + returned: Set = new Set(); + + /** + * Declare a new identifier, used for function id and params + */ + declare(id: IdentifierId): void { + this.identifiers.set(id, { + level: MemoizationLevel.Never, + memoized: false, + dependencies: new Set(), + scopes: new Set(), + seen: false, + }); + } + + /** + * Associates the identifier with its scope, if there is one and it is active for the given instruction id: + * - Records the scope and its dependencies + * - Associates the identifier with this scope + */ + visitOperand( + id: InstructionId, + place: Place, + identifier: IdentifierId + ): void { + const scope = getPlaceScope(id, place); + if (scope !== null) { + let node = this.scopes.get(scope.id); + if (node === undefined) { + node = { + dependencies: [...scope.dependencies].map((dep) => dep.identifier.id), + seen: false, + }; + this.scopes.set(scope.id, node); + } + const identifierNode = this.identifiers.get(identifier); + invariant( + identifierNode !== undefined, + "Expected identifier to be initialized" + ); + identifierNode.scopes.add(scope.id); + } + } +} + +/** + * Given a state derived from visiting the function, walks the graph from the returned nodes + * to determine which other values should be memoized. Returns a set of all identifiers + * that should be memoized. + */ +function computeMemoizedIdentifiers(state: State): Set { + const memoized = new Set(); + + // Visit an identifier, optionally forcing it to be memoized + function visit(id: IdentifierId, forceMemoize: boolean = false): boolean { + const node = state.identifiers.get(id); + invariant(node !== undefined, "Expected a node for all identifiers"); + if (node.seen) { + return node.memoized; + } + node.seen = true; + + // Note: in case of cycles we temporarily mark the identifier as non-memoized, + // this is reset later after processing dependencies + node.memoized = false; + + // Visit dependencies, determine if any of them are memoized + let hasMemoizedDependency = false; + for (const dep of node.dependencies) { + const isDepMemoized = visit(dep); + hasMemoizedDependency ||= isDepMemoized; + } + + if ( + node.level === MemoizationLevel.Memoized || + (node.level === MemoizationLevel.Conditional && + (hasMemoizedDependency || forceMemoize)) || + (node.level === MemoizationLevel.Unmemoized && forceMemoize) + ) { + node.memoized = true; + memoized.add(id); + for (const scope of node.scopes) { + forceMemoizeScopeDependencies(scope); + } + } + return node.memoized; + } + + // Force all the scope's optionally-memoizeable dependencies (not "Never") to be memoized + function forceMemoizeScopeDependencies(id: ScopeId): void { + const node = state.scopes.get(id); + invariant(node !== undefined, "Expected a node for all scopes"); + if (node.seen) { + return; + } + node.seen = true; + + for (const dep of node.dependencies) { + visit(dep, true); + } + return; + } + + // Walk from the "roots" aka returned identifiers. + for (const returned of state.returned) { + visit(returned); + } + + return memoized; +} + +/** + * Given a value, returns a description of how it should be memoized: + * - lvalues: optional extra places that are lvalue-like in the sense of + * aliasing the rvalues + * - rvalues: places that are aliased by the instruction's lvalues. + * - level: the level of memoization to apply to this value + */ +function computeMemoizationInputs(value: ReactiveValue): { + // can optionally return a custom set of lvalues per instruction + lvalues: Array | null; + rvalues: Array; + level: MemoizationLevel; +} { + switch (value.kind) { + case "ConditionalExpression": { + return { + lvalues: null, + rvalues: [ + // Conditionals do not alias their test value. + ...computeMemoizationInputs(value.consequent).rvalues, + ...computeMemoizationInputs(value.alternate).rvalues, + ], + // Only need to memoize if the rvalues are memoized + level: MemoizationLevel.Conditional, + }; + } + case "LogicalExpression": { + return { + lvalues: null, + rvalues: [ + ...computeMemoizationInputs(value.left).rvalues, + ...computeMemoizationInputs(value.right).rvalues, + ], + // Only need to memoize if the rvalues are memoized + level: MemoizationLevel.Conditional, + }; + } + case "SequenceExpression": { + return { + lvalues: null, + // Only the final value of the sequence is a true rvalue: + // values from the sequence's instructions are evaluated + // as separate nodes + rvalues: computeMemoizationInputs(value.value).rvalues, + // Only memoize if the final value was memoized + level: MemoizationLevel.Conditional, + }; + } + case "JsxExpression": { + const operands: Array = []; + operands.push(value.tag); + for (const prop of value.props) { + if (prop.kind === "JsxAttribute") { + operands.push(prop.place); + } else { + operands.push(prop.argument); + } + } + if (value.children !== null) { + for (const child of value.children) { + operands.push(child); + } + } + return { + lvalues: null, + rvalues: operands, + // JSX elements themselves are not memoized unless forced to + // avoid breaking downstream memoization + level: MemoizationLevel.Unmemoized, + }; + } + case "JsxFragment": { + return { + lvalues: null, + rvalues: value.children, + // JSX elements themselves are not memoized unless forced to + // avoid breaking downstream memoization + level: MemoizationLevel.Unmemoized, + }; + } + case "ComputedDelete": + case "PropertyDelete": + case "LoadGlobal": + case "TemplateLiteral": + case "Primitive": + case "JSXText": + case "BinaryExpression": + case "UnaryExpression": { + return { + lvalues: null, + rvalues: [], + // All of these instructions return a primitive value and never need to be memoized + level: MemoizationLevel.Never, + }; + } + case "TypeCastExpression": { + return { + lvalues: null, + // Indirection for the inner value, memoized if the value is + rvalues: [value.value], + level: MemoizationLevel.Conditional, + }; + } + case "LoadLocal": { + return { + lvalues: null, + // Indirection for the inner value, memoized if the value is + rvalues: [value.place], + level: MemoizationLevel.Conditional, + }; + } + case "Destructure": + case "StoreLocal": { + return { + lvalues: null, + // Indirection for the inner value, memoized if the value is + rvalues: [value.value], + level: MemoizationLevel.Conditional, + }; + } + case "ComputedLoad": + case "PropertyLoad": { + return { + lvalues: null, + // Only the object is aliased to the result, and the result only needs to be + // memoized if the object is + rvalues: [value.object], + level: MemoizationLevel.Conditional, + }; + } + case "ComputedStore": { + // The object being stored to acts as an lvalue (it aliases the value), but + // the computed key is not aliased + return { + lvalues: [value.object], + rvalues: [value.value], + level: MemoizationLevel.Conditional, + }; + } + case "FunctionExpression": + case "TaggedTemplateExpression": + case "CallExpression": + case "ArrayExpression": + case "NewExpression": + case "ObjectExpression": + case "ComputedCall": + case "PropertyCall": + case "PropertyStore": { + // All of these instructions may produce new values which must be memoized if + // reachable from a return value. Any mutable rvalue may alias any other rvalue + const operands = [...eachReactiveValueOperand(value)]; + return { + lvalues: operands.filter((operand) => isMutableEffect(operand.effect)), + rvalues: operands, + level: MemoizationLevel.Memoized, + }; + } + case "UnsupportedNode": { + CompilerError.invariant(`Unexpected unsupported node`, value.loc); + } + default: { + assertExhaustive(value, `Unexpected value kind '${(value as any).kind}'`); + } + } +} + +/** + * Populates the input state with the set of returned identifiers and information about each + * identifier's and scope's dependencies. + */ +class CollectDependenciesVisitor extends ReactiveFunctionVisitor { + override visitInstruction( + instruction: ReactiveInstruction, + state: State + ): void { + this.traverseInstruction(instruction, state); + + // Determe the level of memoization for this value and the lvalues/rvalues + const aliasing = computeMemoizationInputs(instruction.value); + + // Associate all the rvalues with the instruction's scope if it has one + for (const operand of aliasing.rvalues) { + const operandId = + state.definitions.get(operand.identifier.id) ?? operand.identifier.id; + state.visitOperand(instruction.id, operand, operandId); + } + + // Add the operands as dependencies of all lvalues. + const lvalues = + aliasing.lvalues !== null + ? [...eachInstructionLValue(instruction), ...aliasing.lvalues] + : [...eachInstructionLValue(instruction)]; + for (const lvalue of lvalues) { + const lvalueId = + state.definitions.get(lvalue.identifier.id) ?? lvalue.identifier.id; + let node = state.identifiers.get(lvalueId); + if (node === undefined) { + node = { + level: MemoizationLevel.Never, + memoized: false, + dependencies: new Set(), + scopes: new Set(), + seen: false, + }; + state.identifiers.set(lvalueId, node); + } + node.level = joinAliases(node.level, aliasing.level); + // This looks like NxM iterations but in practice all instructions with multiple + // lvalues have only a single rvalue + for (const operand of aliasing.rvalues) { + const operandId = + state.definitions.get(operand.identifier.id) ?? operand.identifier.id; + if (operandId === lvalueId) { + continue; + } + node.dependencies.add(operandId); + } + + state.visitOperand(instruction.id, lvalue, lvalueId); + } + + if (instruction.value.kind === "LoadLocal" && instruction.lvalue !== null) { + state.definitions.set( + instruction.lvalue.identifier.id, + instruction.value.place.identifier.id + ); + } + } + + override visitTerminal( + stmt: ReactiveTerminalStatement, + state: State + ): void { + this.traverseTerminal(stmt, state); + + if (stmt.terminal.kind === "return" && stmt.terminal.value !== null) { + state.returned.add(stmt.terminal.value.identifier.id); + } + } +} + +/** + * Prune reactive scopes that do not have any memoized outputs + */ +class PruneScopesTransform extends ReactiveFunctionTransform< + Set +> { + override transformScope( + scope: ReactiveScopeBlock, + state: Set + ): Transformed { + this.visitScope(scope, state); + const hasMemoizedOutput = + Array.from(scope.scope.declarations.keys()).some((id) => state.has(id)) || + Array.from(scope.scope.reassignments).some((identifier) => + state.has(identifier.id) + ); + if (hasMemoizedOutput) { + return { kind: "keep" }; + } else { + return { kind: "replace-many", value: scope.instructions }; + } + } +} + +function isMutableEffect(effect: Effect): boolean { + switch (effect) { + case Effect.Capture: + case Effect.Mutate: + case Effect.Store: { + return true; + } + default: { + return false; + } + } +} diff --git a/compiler/forget/src/ReactiveScopes/index.ts b/compiler/forget/src/ReactiveScopes/index.ts index ba8ef4385b..ad5b55756c 100644 --- a/compiler/forget/src/ReactiveScopes/index.ts +++ b/compiler/forget/src/ReactiveScopes/index.ts @@ -16,6 +16,7 @@ export { mergeOverlappingReactiveScopes } from "./MergeOverlappingReactiveScopes export { printReactiveFunction } from "./PrintReactiveFunction"; export { promoteUsedTemporaries } from "./PromoteUsedTemporaries"; export { propagateScopeDependencies } from "./PropagateScopeDependencies"; +export { pruneNonEscapingScopes } from "./PruneNonEscapingScopes"; export { pruneNonReactiveDependencies } from "./PruneNonReactiveDependencies"; export { pruneTemporaryLValues as pruneUnusedLValues } from "./PruneTemporaryLValues"; export { pruneUnusedLabels } from "./PruneUnusedLabels"; diff --git a/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-function-renamed-ref.expect.md b/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-function-renamed-ref.expect.md index 736833c494..d2f4fdc4b9 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-function-renamed-ref.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-function-renamed-ref.expect.md @@ -19,7 +19,7 @@ function component(a, b) { ```javascript function component(a, b) { - const $ = React.unstable_useMemoCache(4); + const $ = React.unstable_useMemoCache(2); const c_0 = $[0] !== a; let t0; if (c_0) { @@ -30,16 +30,8 @@ function component(a, b) { t0 = $[1]; } const z = t0; - const c_2 = $[2] !== b; - let t1; - if (c_2) { - t1 = { b }; - $[2] = b; - $[3] = t1; - } else { - t1 = $[3]; - } - const z_0 = t1; + + const z_0 = { b }; (function () { mutate(z); })(); diff --git a/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep-nested-scope.expect.md b/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep-nested-scope.expect.md index 4dc4c0d670..1b9703f762 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep-nested-scope.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep-nested-scope.expect.md @@ -24,7 +24,7 @@ function AllocatingPrimitiveAsDepNested(props) { // Correctness: // - y depends on either bar(props.b) or bar(props.b) + 1 function AllocatingPrimitiveAsDepNested(props) { - const $ = React.unstable_useMemoCache(11); + const $ = React.unstable_useMemoCache(9); const c_0 = $[0] !== props.b; const c_1 = $[1] !== props.a; let x; @@ -32,26 +32,17 @@ function AllocatingPrimitiveAsDepNested(props) { if (c_0 || c_1) { x = {}; mutate(x); - const c_4 = $[4] !== props.b; - let t0; + const t0 = bar(props.b) + 1; + const c_4 = $[4] !== t0; + let t1; if (c_4) { - t0 = bar(props.b); - $[4] = props.b; - $[5] = t0; + t1 = foo(t0); + $[4] = t0; + $[5] = t1; } else { - t0 = $[5]; + t1 = $[5]; } - const t1 = t0 + 1; - const c_6 = $[6] !== t1; - let t2; - if (c_6) { - t2 = foo(t1); - $[6] = t1; - $[7] = t2; - } else { - t2 = $[7]; - } - y = t2; + y = t1; mutate(x, props.a); $[0] = props.b; $[1] = props.a; @@ -61,18 +52,18 @@ function AllocatingPrimitiveAsDepNested(props) { x = $[2]; y = $[3]; } - const c_8 = $[8] !== x; - const c_9 = $[9] !== y; - let t3; - if (c_8 || c_9) { - t3 = [x, y]; - $[8] = x; - $[9] = y; - $[10] = t3; + const c_6 = $[6] !== x; + const c_7 = $[7] !== y; + let t2; + if (c_6 || c_7) { + t2 = [x, y]; + $[6] = x; + $[7] = y; + $[8] = t2; } else { - t3 = $[10]; + t2 = $[8]; } - return t3; + return t2; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep.expect.md b/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep.expect.md index 7836f17a83..0e1a15a95d 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/allocating-primitive-as-dep.expect.md @@ -21,27 +21,18 @@ function AllocatingPrimitiveAsDep(props) { // Correctness: // - y depends on either bar(props.b) or bar(props.b) + 1 function AllocatingPrimitiveAsDep(props) { - const $ = React.unstable_useMemoCache(4); - const c_0 = $[0] !== props; - let t0; + const $ = React.unstable_useMemoCache(2); + const t0 = bar(props).b + 1; + const c_0 = $[0] !== t0; + let t1; if (c_0) { - t0 = bar(props); - $[0] = props; - $[1] = t0; + t1 = foo(t0); + $[0] = t0; + $[1] = t1; } else { - t0 = $[1]; + t1 = $[1]; } - const t1 = t0.b + 1; - const c_2 = $[2] !== t1; - let t2; - if (c_2) { - t2 = foo(t1); - $[2] = t1; - $[3] = t2; - } else { - t2 = $[3]; - } - const y = t2; + const y = t1; return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/call.expect.md b/compiler/forget/src/__tests__/fixtures/hir/call.expect.md index 7af3132878..60377a0666 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/call.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/call.expect.md @@ -21,7 +21,7 @@ function Component(props) { function foo() {} function Component(props) { - const $ = React.unstable_useMemoCache(3); + const $ = React.unstable_useMemoCache(2); let a; let b; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { @@ -36,14 +36,7 @@ function Component(props) { a = $[0]; b = $[1]; } - let t0; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t0 =
; - $[2] = t0; - } else { - t0 = $[2]; - } - return t0; + return
; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/capture-func-passed-to-jsx.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capture-func-passed-to-jsx.expect.md index acae2e4956..be0199a9b0 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/capture-func-passed-to-jsx.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/capture-func-passed-to-jsx.expect.md @@ -20,7 +20,7 @@ function component(a, b) { ```javascript function component(a, b) { - const $ = React.unstable_useMemoCache(9); + const $ = React.unstable_useMemoCache(7); const c_0 = $[0] !== b; let t0; if (c_0) { @@ -56,16 +56,7 @@ function component(a, b) { t2 = $[6]; } const x = t2; - const c_7 = $[7] !== x; - let t3; - if (c_7) { - t3 = ; - $[7] = x; - $[8] = t3; - } else { - t3 = $[8]; - } - const t = t3; + const t = ; mutate(x); return t; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-function-member-expr-call.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-function-member-expr-call.expect.md index 2dc57b8057..f727b5e205 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/capturing-function-member-expr-call.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-function-member-expr-call.expect.md @@ -20,7 +20,7 @@ function component({ mutator }) { ```javascript function component(t27) { - const $ = React.unstable_useMemoCache(7); + const $ = React.unstable_useMemoCache(4); const { mutator } = t27; const c_0 = $[0] !== mutator; let t0; @@ -46,18 +46,7 @@ function component(t27) { t1 = $[3]; } const hide = t1; - const c_4 = $[4] !== poke; - const c_5 = $[5] !== hide; - let t2; - if (c_4 || c_5) { - t2 = ; - $[4] = poke; - $[5] = hide; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/component.expect.md b/compiler/forget/src/__tests__/fixtures/hir/component.expect.md index 0acc2fedb3..2518ff4e3d 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/component.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/component.expect.md @@ -35,7 +35,7 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(10); + const $ = React.unstable_useMemoCache(3); const items = props.items; const maxItems = props.maxItems; const c_0 = $[0] !== maxItems; @@ -44,16 +44,7 @@ function Component(props) { if (c_0 || c_1) { renderedItems = []; const seen = new Set(); - const c_3 = $[3] !== maxItems; - let t0; - if (c_3) { - t0 = Math.max(0, maxItems); - $[3] = maxItems; - $[4] = t0; - } else { - t0 = $[4]; - } - const max = t0; + const max = Math.max(0, maxItems); for (let i = 0; i < items.length; i = i + 1, i) { const item = items.at(i); if (item == null || seen.has(item)) { @@ -74,32 +65,12 @@ function Component(props) { } const count = renderedItems.length; - const c_5 = $[5] !== count; - let t1; - if (c_5) { - t1 =

{count} Items

; - $[5] = count; - $[6] = t1; - } else { - t1 = $[6]; - } - const c_7 = $[7] !== t1; - const c_8 = $[8] !== renderedItems; - let t2; - if (c_7 || c_8) { - t2 = ( -
- {t1} - {renderedItems} -
- ); - $[7] = t1; - $[8] = renderedItems; - $[9] = t2; - } else { - t2 = $[9]; - } - return t2; + return ( +
+ {

{count} Items

} + {renderedItems} +
+ ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/concise-arrow-expr.expect.md b/compiler/forget/src/__tests__/fixtures/hir/concise-arrow-expr.expect.md index 517503efd5..006ec5f533 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/concise-arrow-expr.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/concise-arrow-expr.expect.md @@ -14,7 +14,7 @@ function component() { ```javascript function component() { - const $ = React.unstable_useMemoCache(4); + const $ = React.unstable_useMemoCache(2); const [x, setX] = useState(0); const c_0 = $[0] !== setX; let t0; @@ -26,16 +26,7 @@ function component() { t0 = $[1]; } const handler = t0; - const c_2 = $[2] !== handler; - let t1; - if (c_2) { - t1 = ; - $[2] = handler; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md b/compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md index f80aacf62e..990b07d7f5 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md @@ -35,7 +35,7 @@ function mayMutate() {} ```javascript function ComponentA(props) { - const $ = React.unstable_useMemoCache(6); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props; let a; let b; @@ -55,22 +55,11 @@ function ComponentA(props) { a = $[1]; b = $[2]; } - const c_3 = $[3] !== a; - const c_4 = $[4] !== b; - let t0; - if (c_3 || c_4) { - t0 = ; - $[3] = a; - $[4] = b; - $[5] = t0; - } else { - t0 = $[5]; - } - return t0; + return ; } function ComponentB(props) { - const $ = React.unstable_useMemoCache(6); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props; let a; let b; @@ -90,18 +79,7 @@ function ComponentB(props) { a = $[1]; b = $[2]; } - const c_3 = $[3] !== a; - const c_4 = $[4] !== b; - let t0; - if (c_3 || c_4) { - t0 = ; - $[3] = a; - $[4] = b; - $[5] = t0; - } else { - t0 = $[5]; - } - return t0; + return ; } function Foo() {} diff --git a/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-for.expect.md b/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-for.expect.md index 257f5ff027..8da0c3f1e8 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-for.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-for.expect.md @@ -16,16 +16,9 @@ function foo() { ```javascript function foo() { - const $ = React.unstable_useMemoCache(1); - let y; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - y = 0; - for (const x = 100; false; 100) { - y = y + 1; - } - $[0] = y; - } else { - y = $[0]; + let y = 0; + for (const x = 100; false; 100) { + y = y + 1; } return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-while.expect.md b/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-while.expect.md index 9aae7d26bf..38668aa3db 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-while.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/constant-propagation-while.expect.md @@ -17,16 +17,9 @@ function foo() { ```javascript function foo() { - const $ = React.unstable_useMemoCache(1); - let y; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - y = 0; - while (false) { - y = y + 1; - } - $[0] = y; - } else { - y = $[0]; + let y = 0; + while (false) { + y = y + 1; } return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/constructor.expect.md b/compiler/forget/src/__tests__/fixtures/hir/constructor.expect.md index 08b57f01d8..3c0d0d9f28 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/constructor.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/constructor.expect.md @@ -21,7 +21,7 @@ function Component(props) { function Foo() {} function Component(props) { - const $ = React.unstable_useMemoCache(3); + const $ = React.unstable_useMemoCache(2); let a; let b; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { @@ -35,14 +35,7 @@ function Component(props) { a = $[0]; b = $[1]; } - let t0; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t0 =
; - $[2] = t0; - } else { - t0 = $[2]; - } - return t0; + return
; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/controlled-input.expect.md b/compiler/forget/src/__tests__/fixtures/hir/controlled-input.expect.md index 417dcef789..dfdf8c1b09 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/controlled-input.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/controlled-input.expect.md @@ -14,7 +14,7 @@ function component() { ```javascript function component() { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(2); const [x, setX] = useState(0); const c_0 = $[0] !== setX; let t0; @@ -26,18 +26,7 @@ function component() { t0 = $[1]; } const handler = t0; - const c_2 = $[2] !== handler; - const c_3 = $[3] !== x; - let t1; - if (c_2 || c_3) { - t1 = ; - $[2] = handler; - $[3] = x; - $[4] = t1; - } else { - t1 = $[4]; - } - return t1; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/dce-loop.expect.md b/compiler/forget/src/__tests__/fixtures/hir/dce-loop.expect.md index 87ae30f017..2fec874a11 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/dce-loop.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/dce-loop.expect.md @@ -18,18 +18,9 @@ function foo(props) { ```javascript function foo(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.max; - let y; - if (c_0) { - y = 0; - while (y < props.max) { - y = y + 1; - } - $[0] = props.max; - $[1] = y; - } else { - y = $[1]; + let y = 0; + while (y < props.max) { + y = y + 1; } return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/destructure-direct-reassignment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/destructure-direct-reassignment.expect.md index 599a3be6d0..ec9c7e3bf8 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/destructure-direct-reassignment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/destructure-direct-reassignment.expect.md @@ -16,22 +16,8 @@ function foo(props) { ```javascript function foo(props) { - const $ = React.unstable_useMemoCache(4); - const c_0 = $[0] !== props.a; - const c_1 = $[1] !== props.b; - let x; - let y; - if (c_0 || c_1) { - ({ x, y } = { x: props.a, y: props.b }); - console.log(x); - $[0] = props.a; - $[1] = props.b; - $[2] = x; - $[3] = y; - } else { - x = $[2]; - y = $[3]; - } + let { x, y } = { x: props.a, y: props.b }; + console.log(x); x = props.c; return x + y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-jsx-child.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-jsx-child.expect.md new file mode 100644 index 0000000000..7f41bd83cd --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-jsx-child.expect.md @@ -0,0 +1,59 @@ + +## Input + +```javascript +function foo(a, b, c) { + const x = []; + if (a) { + const y = []; + if (b) { + y.push(c); + } + x.push(
{y}
); + } + return x; +} + +``` + +## Code + +```javascript +function foo(a, b, c) { + const $ = React.unstable_useMemoCache(7); + const c_0 = $[0] !== a; + const c_1 = $[1] !== b; + const c_2 = $[2] !== c; + let x; + if (c_0 || c_1 || c_2) { + x = []; + if (a) { + const c_4 = $[4] !== b; + const c_5 = $[5] !== c; + let y; + if (c_4 || c_5) { + y = []; + if (b) { + y.push(c); + } + $[4] = b; + $[5] = c; + $[6] = y; + } else { + y = $[6]; + } + + x.push(
{y}
); + } + $[0] = a; + $[1] = b; + $[2] = c; + $[3] = x; + } else { + x = $[3]; + } + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-jsx-child.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-jsx-child.js new file mode 100644 index 0000000000..7df580429c --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-jsx-child.js @@ -0,0 +1,11 @@ +function foo(a, b, c) { + const x = []; + if (a) { + const y = []; + if (b) { + y.push(c); + } + x.push(
{y}
); + } + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-logical.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-logical.expect.md new file mode 100644 index 0000000000..cb67370a9b --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-logical.expect.md @@ -0,0 +1,68 @@ + +## Input + +```javascript +function Component(props) { + const a = [props.a]; + const b = [props.b]; + const c = [props.c]; + // We don't do constant folding for non-primitive values (yet) so we consider + // that any of a, b, or c could return here + return (a && b) || c; +} + +``` + +## Code + +```javascript +function Component(props) { + const $ = React.unstable_useMemoCache(10); + const c_0 = $[0] !== props.a; + let t0; + if (c_0) { + t0 = [props.a]; + $[0] = props.a; + $[1] = t0; + } else { + t0 = $[1]; + } + const a = t0; + const c_2 = $[2] !== props.b; + let t1; + if (c_2) { + t1 = [props.b]; + $[2] = props.b; + $[3] = t1; + } else { + t1 = $[3]; + } + const b = t1; + const c_4 = $[4] !== props.c; + let t2; + if (c_4) { + t2 = [props.c]; + $[4] = props.c; + $[5] = t2; + } else { + t2 = $[5]; + } + const c = t2; + const c_6 = $[6] !== a; + const c_7 = $[7] !== b; + const c_8 = $[8] !== c; + let t3; + if (c_6 || c_7 || c_8) { + t3 = (a && b) || c; + $[6] = a; + $[7] = b; + $[8] = c; + $[9] = t3; + } else { + t3 = $[9]; + } + return t3; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-logical.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-logical.js new file mode 100644 index 0000000000..4582a56fa9 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-logical.js @@ -0,0 +1,8 @@ +function Component(props) { + const a = [props.a]; + const b = [props.b]; + const c = [props.c]; + // We don't do constant folding for non-primitive values (yet) so we consider + // that any of a, b, or c could return here + return (a && b) || c; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-allocating-dependency.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-allocating-dependency.expect.md new file mode 100644 index 0000000000..42b5bf284f --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-allocating-dependency.expect.md @@ -0,0 +1,57 @@ + +## Input + +```javascript +function Component(props) { + // a can be independently memoized, is not mutated later + const a = [props.a]; + + // b and c are interleaved and grouped into a single scope, + // but they are independent values. c does not escape, but + // we need to ensure that a is memoized or else b will invalidate + // on every render since a is a dependency. + const b = []; + const c = {}; + c.a = a; + b.push(props.b); + + return b; +} + +``` + +## Code + +```javascript +function Component(props) { + const $ = React.unstable_useMemoCache(5); + const c_0 = $[0] !== props.a; + let t0; + if (c_0) { + t0 = [props.a]; + $[0] = props.a; + $[1] = t0; + } else { + t0 = $[1]; + } + const a = t0; + const c_2 = $[2] !== a; + const c_3 = $[3] !== props.b; + let b; + if (c_2 || c_3) { + b = []; + const c = {}; + c.a = a; + + b.push(props.b); + $[2] = a; + $[3] = props.b; + $[4] = b; + } else { + b = $[4]; + } + return b; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-allocating-dependency.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-allocating-dependency.js new file mode 100644 index 0000000000..a7646fcc95 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-allocating-dependency.js @@ -0,0 +1,15 @@ +function Component(props) { + // a can be independently memoized, is not mutated later + const a = [props.a]; + + // b and c are interleaved and grouped into a single scope, + // but they are independent values. c does not escape, but + // we need to ensure that a is memoized or else b will invalidate + // on every render since a is a dependency. + const b = []; + const c = {}; + c.a = a; + b.push(props.b); + + return b; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-primitive-dependency.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-primitive-dependency.expect.md new file mode 100644 index 0000000000..66801c7447 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-primitive-dependency.expect.md @@ -0,0 +1,51 @@ + +## Input + +```javascript +function Component(props) { + // a does not need to be memoized ever, even though it's a + // dependency of c, which exists in a scope that has a memoized + // output. it doesn't need to be memoized bc the value is a primitive type. + const a = props.a + props.b; + + // b and c are interleaved and grouped into a single scope, + // but they are independent values. c does not escape, but + // we need to ensure that a is memoized or else b will invalidate + // on every render since a is a dependency. + const b = []; + const c = {}; + c.a = a; + b.push(props.c); + + return b; +} + +``` + +## Code + +```javascript +function Component(props) { + const $ = React.unstable_useMemoCache(3); + + const a = props.a + props.b; + const c_0 = $[0] !== a; + const c_1 = $[1] !== props.c; + let b; + if (c_0 || c_1) { + b = []; + const c = {}; + c.a = a; + + b.push(props.c); + $[0] = a; + $[1] = props.c; + $[2] = b; + } else { + b = $[2]; + } + return b; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-primitive-dependency.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-primitive-dependency.js new file mode 100644 index 0000000000..b8d3bd280c --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-non-escaping-interleaved-primitive-dependency.js @@ -0,0 +1,17 @@ +function Component(props) { + // a does not need to be memoized ever, even though it's a + // dependency of c, which exists in a scope that has a memoized + // output. it doesn't need to be memoized bc the value is a primitive type. + const a = props.a + props.b; + + // b and c are interleaved and grouped into a single scope, + // but they are independent values. c does not escape, but + // we need to ensure that a is memoized or else b will invalidate + // on every render since a is a dependency. + const b = []; + const c = {}; + c.a = a; + b.push(props.c); + + return b; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-conditional-test.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-conditional-test.expect.md new file mode 100644 index 0000000000..0b4d20a76a --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-conditional-test.expect.md @@ -0,0 +1,23 @@ + +## Input + +```javascript +function Component(props) { + const x = [props.a]; + const y = x ? props.b : props.c; + return y; +} + +``` + +## Code + +```javascript +function Component(props) { + const x = [props.a]; + const y = x ? props.b : props.c; + return y; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-conditional-test.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-conditional-test.js new file mode 100644 index 0000000000..d59b67810f --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-conditional-test.js @@ -0,0 +1,5 @@ +function Component(props) { + const x = [props.a]; + const y = x ? props.b : props.c; + return y; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-if-test.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-if-test.expect.md new file mode 100644 index 0000000000..ffd3f0dc09 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-if-test.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function Component(props) { + const x = [props.a]; + let y; + if (x) { + y = props.b; + } else { + y = props.c; + } + return y; +} + +``` + +## Code + +```javascript +function Component(props) { + const x = [props.a]; + let y = undefined; + if (x) { + y = props.b; + } else { + y = props.c; + } + return y; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-if-test.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-if-test.js new file mode 100644 index 0000000000..e999f4e143 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-if-test.js @@ -0,0 +1,10 @@ +function Component(props) { + const x = [props.a]; + let y; + if (x) { + y = props.b; + } else { + y = props.c; + } + return y; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-case.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-case.expect.md new file mode 100644 index 0000000000..ee3e6f944f --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-case.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function Component(props) { + const a = [props.a]; + let x = props.b; + switch (props.c) { + case a: { + x = props.d; + } + } + return x; +} + +``` + +## Code + +```javascript +function Component(props) { + const a = [props.a]; + let x = props.b; + switch (props.c) { + case a: { + x = props.d; + } + } + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-case.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-case.js new file mode 100644 index 0000000000..bf577624e4 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-case.js @@ -0,0 +1,10 @@ +function Component(props) { + const a = [props.a]; + let x = props.b; + switch (props.c) { + case a: { + x = props.d; + } + } + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-test.expect.md b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-test.expect.md new file mode 100644 index 0000000000..229f49f56c --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-test.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function Component(props) { + const a = [props.a]; + let x = props.b; + switch (a) { + case true: { + x = props.c; + } + } + return x; +} + +``` + +## Code + +```javascript +function Component(props) { + const a = [props.a]; + let x = props.b; + switch (a) { + case true: { + x = props.c; + } + } + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-test.js b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-test.js new file mode 100644 index 0000000000..58ceaff461 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/escape-analysis-not-switch-test.js @@ -0,0 +1,10 @@ +function Component(props) { + const a = [props.a]; + let x = props.b; + switch (a) { + case true: { + x = props.c; + } + } + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/for-logical.expect.md b/compiler/forget/src/__tests__/fixtures/hir/for-logical.expect.md index e465c701e6..afbc402bfc 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/for-logical.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/for-logical.expect.md @@ -21,23 +21,14 @@ function foo(props) { ```javascript function foo(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props; - let y; - if (c_0) { - y = 0; - for ( - let x = 0; - x > props.min && x < props.max; - x = x + (props.cond ? props.increment : 2), x - ) { - x = x * 2; - y = y + x; - } - $[0] = props; - $[1] = y; - } else { - y = $[1]; + let y = 0; + for ( + let x = 0; + x > props.min && x < props.max; + x = x + (props.cond ? props.increment : 2), x + ) { + x = x * 2; + y = y + x; } return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-default-function.expect.md b/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-default-function.expect.md index 8ce6c365f5..6518388ae8 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-default-function.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-default-function.expect.md @@ -28,17 +28,7 @@ function Bar_uncompiled(props) { return
{props.bar}
; } function Bar_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 =
{props.bar}
; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return
{props.bar}
; } const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled; export default Bar; @@ -52,17 +42,7 @@ function Foo_uncompiled(props) { return {props.bar}; } function Foo_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 = {props.bar}; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return {props.bar}; } const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled; diff --git a/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function-and-default.expect.md b/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function-and-default.expect.md index e4bfcfe42e..6c12dcde2c 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function-and-default.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function-and-default.expect.md @@ -28,17 +28,7 @@ function Bar_uncompiled(props) { return
{props.bar}
; } function Bar_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 =
{props.bar}
; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return
{props.bar}
; } const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled; export default Bar; @@ -52,17 +42,7 @@ function Foo_uncompiled(props) { return {props.bar}; } function Foo_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 = {props.bar}; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return {props.bar}; } export const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled; diff --git a/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function.expect.md b/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function.expect.md index 81b8dd9e8e..36363fb738 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function.expect.md @@ -28,17 +28,7 @@ function Bar_uncompiled(props) { return
{props.bar}
; } function Bar_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 =
{props.bar}
; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return
{props.bar}
; } export const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled; @@ -51,17 +41,7 @@ function Foo_uncompiled(props) { return {props.bar}; } function Foo_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 = {props.bar}; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return {props.bar}; } export const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled; diff --git a/compiler/forget/src/__tests__/fixtures/hir/gating-test.expect.md b/compiler/forget/src/__tests__/fixtures/hir/gating-test.expect.md index 19260edb97..624514d94e 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/gating-test.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/gating-test.expect.md @@ -28,17 +28,7 @@ function Bar_uncompiled(props) { return
{props.bar}
; } function Bar_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 =
{props.bar}
; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return
{props.bar}
; } const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled; @@ -51,17 +41,7 @@ function Foo_uncompiled(props) { return {props.bar}; } function Foo_forget(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props.bar; - let t0; - if (c_0) { - t0 = {props.bar}; - $[0] = props.bar; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; + return {props.bar}; } const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled; diff --git a/compiler/forget/src/__tests__/fixtures/hir/hook-call.expect.md b/compiler/forget/src/__tests__/fixtures/hir/hook-call.expect.md index 4ecc4cc7fa..b7a764d207 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/hook-call.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/hook-call.expect.md @@ -26,7 +26,7 @@ function useFreeze() {} function foo() {} function Component(props) { - const $ = React.unstable_useMemoCache(3); + const $ = React.unstable_useMemoCache(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = []; @@ -37,21 +37,12 @@ function Component(props) { const x = t0; const y = useFreeze(x); foo(y, x); - const c_1 = $[1] !== y; - let t1; - if (c_1) { - t1 = ( - - {x} - {y} - - ); - $[1] = y; - $[2] = t1; - } else { - t1 = $[2]; - } - return t1; + return ( + + {x} + {y} + + ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md b/compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md index 34633c17d8..68f656e264 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md @@ -56,7 +56,7 @@ function Foo() {} * return = */ function Component(props) { - const $ = React.unstable_useMemoCache(8); + const $ = React.unstable_useMemoCache(5); const c_0 = $[0] !== props.a; const c_1 = $[1] !== props.b; const c_2 = $[2] !== props.c; @@ -78,18 +78,7 @@ function Component(props) { a = $[3]; b = $[4]; } - const c_5 = $[5] !== a; - const c_6 = $[6] !== b; - let t0; - if (c_5 || c_6) { - t0 = ; - $[5] = a; - $[6] = b; - $[7] = t0; - } else { - t0 = $[7]; - } - return t0; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/independent.expect.md b/compiler/forget/src/__tests__/fixtures/hir/independent.expect.md index 9a344bd0d9..c9cc9692f4 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/independent.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/independent.expect.md @@ -38,7 +38,7 @@ function Foo() {} * return = */ function Component(props) { - const $ = React.unstable_useMemoCache(7); + const $ = React.unstable_useMemoCache(4); const c_0 = $[0] !== props.a; let t0; if (c_0) { @@ -59,18 +59,7 @@ function Component(props) { t1 = $[3]; } const b = t1; - const c_4 = $[4] !== a; - const c_5 = $[5] !== b; - let t2; - if (c_4 || c_5) { - t2 = ; - $[4] = a; - $[5] = b; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + return ; } function compute() {} diff --git a/compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md b/compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md index 0d0f6cab93..9339072294 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md @@ -45,7 +45,7 @@ function Foo() {} * return = */ function Component(props) { - const $ = React.unstable_useMemoCache(8); + const $ = React.unstable_useMemoCache(5); const c_0 = $[0] !== props.a; const c_1 = $[1] !== props.b; const c_2 = $[2] !== props.c; @@ -66,18 +66,7 @@ function Component(props) { a = $[3]; b = $[4]; } - const c_5 = $[5] !== a; - const c_6 = $[6] !== b; - let t0; - if (c_5 || c_6) { - t0 = ; - $[5] = a; - $[6] = b; - $[7] = t0; - } else { - t0 = $[7]; - } - return t0; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/interdependent.expect.md b/compiler/forget/src/__tests__/fixtures/hir/interdependent.expect.md index 9c7bc4c7c3..fa63c5ee4f 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/interdependent.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/interdependent.expect.md @@ -37,7 +37,7 @@ function Foo() {} * return = */ function Component(props) { - const $ = React.unstable_useMemoCache(7); + const $ = React.unstable_useMemoCache(4); const c_0 = $[0] !== props.a; const c_1 = $[1] !== props.b; let a; @@ -54,18 +54,7 @@ function Component(props) { a = $[2]; b = $[3]; } - const c_4 = $[4] !== a; - const c_5 = $[5] !== b; - let t0; - if (c_4 || c_5) { - t0 = ; - $[4] = a; - $[5] = b; - $[6] = t0; - } else { - t0 = $[6]; - } - return t0; + return ; } function compute() {} diff --git a/compiler/forget/src/__tests__/fixtures/hir/jsx-fragment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/jsx-fragment.expect.md index 09b15eefae..896216a662 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/jsx-fragment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/jsx-fragment.expect.md @@ -19,36 +19,12 @@ function Foo(props) { ```javascript function Foo(props) { - const $ = React.unstable_useMemoCache(4); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = <>Text; - $[0] = t0; - } else { - t0 = $[0]; - } - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 =
{t0}
; - $[1] = t1; - } else { - t1 = $[1]; - } - const c_2 = $[2] !== props.greeting; - let t2; - if (c_2) { - t2 = ( - <> - Hello {props.greeting} - {t1} - - ); - $[2] = props.greeting; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; + return ( + <> + Hello {props.greeting} + {
{<>Text}
} + + ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/jsx-spread.expect.md b/compiler/forget/src/__tests__/fixtures/hir/jsx-spread.expect.md index 525aaa437c..2dfe91d80a 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/jsx-spread.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/jsx-spread.expect.md @@ -14,37 +14,19 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(7); - const c_0 = $[0] !== props; - let t0; - if (c_0) { - t0 = props.cond ? props.foo : props.bar; - $[0] = props; - $[1] = t0; - } else { - t0 = $[1]; - } - const c_2 = $[2] !== t0; + const $ = React.unstable_useMemoCache(2); + + const t0 = props.cond ? props.foo : props.bar; + const c_0 = $[0] !== t0; let t1; - if (c_2) { + if (c_0) { t1 = { bar: t0 }; - $[2] = t0; - $[3] = t1; + $[0] = t0; + $[1] = t1; } else { - t1 = $[3]; + t1 = $[1]; } - const c_4 = $[4] !== props; - const c_5 = $[5] !== t1; - let t2; - if (c_4 || c_5) { - t2 = ; - $[4] = props; - $[5] = t1; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/logical-expression-object.expect.md b/compiler/forget/src/__tests__/fixtures/hir/logical-expression-object.expect.md index 95a3c75e61..f0f7daea29 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/logical-expression-object.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/logical-expression-object.expect.md @@ -19,39 +19,22 @@ function component(props) { ```javascript function component(props) { - const $ = React.unstable_useMemoCache(7); - const c_0 = $[0] !== props; + const $ = React.unstable_useMemoCache(3); + + const a = props.a || (props.b && props.c && props.d); + const b = (props.a && props.b && props.c) || props.d; + const c_0 = $[0] !== a; + const c_1 = $[1] !== b; let t0; - if (c_0) { - t0 = props.a || (props.b && props.c && props.d); - $[0] = props; - $[1] = t0; + if (c_0 || c_1) { + t0 = { a, b }; + $[0] = a; + $[1] = b; + $[2] = t0; } else { - t0 = $[1]; + t0 = $[2]; } - const a = t0; - const c_2 = $[2] !== props; - let t1; - if (c_2) { - t1 = (props.a && props.b && props.c) || props.d; - $[2] = props; - $[3] = t1; - } else { - t1 = $[3]; - } - const b = t1; - const c_4 = $[4] !== a; - const c_5 = $[5] !== b; - let t2; - if (c_4 || c_5) { - t2 = { a, b }; - $[4] = a; - $[5] = b; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + return t0; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/logical-expression.expect.md b/compiler/forget/src/__tests__/fixtures/hir/logical-expression.expect.md index 8c6244e68d..8dad2ec6ac 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/logical-expression.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/logical-expression.expect.md @@ -14,41 +14,9 @@ function component(props) { ```javascript function component(props) { - const $ = React.unstable_useMemoCache(8); - const c_0 = $[0] !== props; - let t0; - if (c_0) { - t0 = props.a || (props.b && props.c && props.d); - $[0] = props; - $[1] = t0; - } else { - t0 = $[1]; - } - const a = t0; - const c_2 = $[2] !== props; - let t1; - if (c_2) { - t1 = (props.a && props.b && props.c) || props.d; - $[2] = props; - $[3] = t1; - } else { - t1 = $[3]; - } - const b = t1; - const c_4 = $[4] !== a; - const c_5 = $[5] !== b; - const c_6 = $[6] !== props; - let t2; - if (c_4 || c_5 || c_6) { - t2 = a ? b : props.c; - $[4] = a; - $[5] = b; - $[6] = props; - $[7] = t2; - } else { - t2 = $[7]; - } - return t2; + const a = props.a || (props.b && props.c && props.d); + const b = (props.a && props.b && props.c) || props.d; + return a ? b : props.c; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md b/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md index 465e44b685..62501bfb6f 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md @@ -41,17 +41,9 @@ function mutate() {} function cond() {} function Component(props) { - const $ = React.unstable_useMemoCache(1); const a = {}; const b = {}; - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = {}; - $[0] = t0; - } else { - t0 = $[0]; - } - const c = t0; + const c = {}; const d = {}; while (true) { mutate(a, b); diff --git a/compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-shadowing-within-block.expect.md b/compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-shadowing-within-block.expect.md index d24c7ef2f9..8a4627755b 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-shadowing-within-block.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-shadowing-within-block.expect.md @@ -21,7 +21,7 @@ function foo(a, b, c) { ```javascript function foo(a, b, c) { - const $ = React.unstable_useMemoCache(9); + const $ = React.unstable_useMemoCache(7); const c_0 = $[0] !== a; const c_1 = $[1] !== b; const c_2 = $[2] !== c; @@ -43,16 +43,8 @@ function foo(a, b, c) { } else { y = $[6]; } - const c_7 = $[7] !== y; - let t0; - if (c_7) { - t0 =
{y}
; - $[7] = y; - $[8] = t0; - } else { - t0 = $[8]; - } - x.push(t0); + + x.push(
{y}
); } $[0] = a; $[1] = b; diff --git a/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md index 0589203765..643cbcac2e 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md @@ -17,7 +17,7 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(6); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props.p0; let x; let child; @@ -35,18 +35,7 @@ function Component(props) { x = $[1]; child = $[2]; } - const c_3 = $[3] !== x; - const c_4 = $[4] !== child; - let t0; - if (c_3 || c_4) { - t0 = {child}; - $[3] = x; - $[4] = child; - $[5] = t0; - } else { - t0 = $[5]; - } - return t0; + return {child}; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes-if.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes-if.expect.md index 3faf4cc51f..1ec13b7c14 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes-if.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes-if.expect.md @@ -20,7 +20,7 @@ function foo(a, b, c) { ```javascript function foo(a, b, c) { - const $ = React.unstable_useMemoCache(8); + const $ = React.unstable_useMemoCache(6); const c_0 = $[0] !== a; const c_1 = $[1] !== b; const c_2 = $[2] !== c; @@ -38,16 +38,7 @@ function foo(a, b, c) { } else { y = $[5]; } - const c_6 = $[6] !== y; - let t0; - if (c_6) { - t0 =
{y}
; - $[6] = y; - $[7] = t0; - } else { - t0 = $[7]; - } - x.push(t0); + x.push(
{y}
); } else { x.push(c); } diff --git a/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes.expect.md index 006beeecae..d70fbe3f80 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reactive-scopes.expect.md @@ -19,7 +19,7 @@ function f(a, b) { ```javascript function f(a, b) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== a.length; const c_1 = $[1] !== b; let x; @@ -36,16 +36,7 @@ function f(a, b) { } else { x = $[2]; } - const c_3 = $[3] !== x; - let t0; - if (c_3) { - t0 =
{x}
; - $[3] = x; - $[4] = t0; - } else { - t0 = $[4]; - } - return t0; + return
{x}
; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md index c7552085ba..3eaac56f77 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md @@ -23,7 +23,7 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(6); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props.p0; let x; if (c_0) { @@ -47,18 +47,7 @@ function Component(props) { } y.push(props.p2); - const c_3 = $[3] !== x; - const c_4 = $[4] !== y; - let t1; - if (c_3 || c_4) { - t1 = ; - $[3] = x; - $[4] = y; - $[5] = t1; - } else { - t1 = $[5]; - } - return t1; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/reassignment-separate-scopes.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reassignment-separate-scopes.expect.md index 79d36dd99e..315c9f16d1 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reassignment-separate-scopes.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reassignment-separate-scopes.expect.md @@ -34,7 +34,7 @@ function foo(a, b, c) { ```javascript function foo(a, b, c) { - const $ = React.unstable_useMemoCache(11); + const $ = React.unstable_useMemoCache(6); const c_0 = $[0] !== a; let x; if (c_0) { @@ -47,58 +47,39 @@ function foo(a, b, c) { } else { x = $[1]; } - const c_2 = $[2] !== x; - let t0; - if (c_2) { - t0 =
{x}
; - $[2] = x; - $[3] = t0; - } else { - t0 = $[3]; - } - const y = t0; + + const y =
{x}
; bb3: switch (b) { case 0: { - const c_4 = $[4] !== b; - if (c_4) { + const c_2 = $[2] !== b; + if (c_2) { x = []; x.push(b); - $[4] = b; - $[5] = x; + $[2] = b; + $[3] = x; } else { - x = $[5]; + x = $[3]; } break bb3; } default: { - const c_6 = $[6] !== c; - if (c_6) { + const c_4 = $[4] !== c; + if (c_4) { x = []; x.push(c); - $[6] = c; - $[7] = x; + $[4] = c; + $[5] = x; } else { - x = $[7]; + x = $[5]; } } } - const c_8 = $[8] !== y; - const c_9 = $[9] !== x; - let t1; - if (c_8 || c_9) { - t1 = ( -
- {y} - {x} -
- ); - $[8] = y; - $[9] = x; - $[10] = t1; - } else { - t1 = $[10]; - } - return t1; + return ( +
+ {y} + {x} +
+ ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md index 0b3212b74d..82cd2284a5 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md @@ -21,7 +21,7 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(8); + const $ = React.unstable_useMemoCache(5); const c_0 = $[0] !== props.p0; const c_1 = $[1] !== props.p1; let x; @@ -48,18 +48,7 @@ function Component(props) { x = $[2]; y = $[3]; } - const c_5 = $[5] !== x; - const c_6 = $[6] !== y; - let t1; - if (c_5 || c_6) { - t1 = ; - $[5] = x; - $[6] = y; - $[7] = t1; - } else { - t1 = $[7]; - } - return t1; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-ifelse.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-ifelse.expect.md index 0ced780c0b..53db1825ea 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-ifelse.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-ifelse.expect.md @@ -26,22 +26,13 @@ function TestCondDepInDirectIfElse(props, other) { // paths function TestCondDepInDirectIfElse(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props.a.b; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { + if (foo(other)) { x.b = props.a.b; } else { x.c = props.a.b; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse-missing.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse-missing.expect.md index df4ad11cf7..fcaafdcadd 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse-missing.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse-missing.expect.md @@ -26,30 +26,14 @@ function TestCondDepInNestedIfElse(props, other) { // scope that produces x if it is not accessed in every path function TestCondDepInNestedIfElse(props, other) { - const $ = React.unstable_useMemoCache(6); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { - let t1; - if ($[5] === Symbol.for("react.memo_cache_sentinel")) { - t1 = bar(); - $[5] = t1; - } else { - t1 = $[5]; - } - if (t1) { + if (foo(other)) { + if (bar()) { x.a = props.a.b; } } else { diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse.expect.md index 66d954e2e2..2cb8a10eae 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-nested-ifelse.expect.md @@ -32,45 +32,20 @@ function TestCondDepInNestedIfElse(props, other) { // paths function TestCondDepInNestedIfElse(props, other) { - const $ = React.unstable_useMemoCache(8); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props.a.b; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { - let t1; - if ($[5] === Symbol.for("react.memo_cache_sentinel")) { - t1 = bar(); - $[5] = t1; - } else { - t1 = $[5]; - } - if (t1) { + if (foo(other)) { + if (bar()) { x.a = props.a.b; } else { x.b = props.a.b; } } else { - const c_6 = $[6] !== other; - let t2; - if (c_6) { - t2 = baz(other); - $[6] = other; - $[7] = t2; - } else { - t2 = $[7]; - } - if (t2) { + if (baz(other)) { x.c = props.a.b; } else { x.d = props.a.b; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-case.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-case.expect.md index 8093fe3055..032817f562 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-case.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-case.expect.md @@ -30,22 +30,13 @@ function TestCondDepInSwitchMissingCase(props, other) { // scope that produces x if it is not accessed in every path function TestCondDepInSwitchMissingCase(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - bb1: switch (t0) { + bb1: switch (foo(other)) { case 1: { x.a = props.a.b; break bb1; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-default.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-default.expect.md index dca154ab40..7c854282cb 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-default.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch-missing-default.expect.md @@ -27,22 +27,13 @@ function TestCondDepInSwitchMissingDefault(props, other) { // scope that produces x if it is not accessed in the default case. function TestCondDepInSwitchMissingDefault(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - bb1: switch (t0) { + bb1: switch (foo(other)) { case 1: { x.a = props.a.b; break bb1; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch.expect.md index 3016700db5..8ad41ad70e 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-cfg-switch.expect.md @@ -31,22 +31,13 @@ function TestCondDepInSwitch(props, other) { // paths function TestCondDepInSwitch(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props.a.b; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - bb1: switch (t0) { + bb1: switch (foo(other)) { case 1: { x.a = props.a.b; break bb1; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-no-uncond.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-no-uncond.expect.md index 8b60cacc88..933fc1eac1 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-no-uncond.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-no-uncond.expect.md @@ -21,22 +21,13 @@ function TestOnlyConditionalDependencies(props, other) { // When an object's properties are only read conditionally, we should // track the base object as a dependency. function TestOnlyConditionalDependencies(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { + if (foo(other)) { x.b = props.a.b; x.c = props.a.b.c; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-promote-uncond.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-promote-uncond.expect.md index 0dc9bc311e..98235bb24e 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-promote-uncond.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-promote-uncond.expect.md @@ -23,23 +23,14 @@ function TestPromoteUnconditionalAccessToDependency(props, other) { // in its subpath or superpath, we should find the nearest unconditional access // and promote it to an unconditional dependency. function TestPromoteUnconditionalAccessToDependency(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props.a; const c_1 = $[1] !== other; let x; if (c_0 || c_1) { x = {}; x.a = props.a.a.a; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { + if (foo(other)) { x.c = props.a.b.c; } $[0] = props.a; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order1.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order1.expect.md index 6b15c1d174..b766b54e6c 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order1.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order1.expect.md @@ -27,23 +27,14 @@ function TestConditionalSubpath1(props, other) { // deps: {`props.a`, `props.a.b`} can further reduce to just `props.a` // ordering of accesses should not matter function TestConditionalSubpath1(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props.a; const c_1 = $[1] !== other; let x; if (c_0 || c_1) { x = {}; x.b = props.a.b; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { + if (foo(other)) { x.a = props.a; } $[0] = props.a; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order2.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order2.expect.md index e7a9a37f80..2a1925d1f2 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order2.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-subpath-order2.expect.md @@ -27,22 +27,13 @@ function TestConditionalSubpath2(props, other) { // deps: {`props.a`, `props.a.b`} can further reduce to just `props.a` // ordering of accesses should not matter function TestConditionalSubpath2(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props.a; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { + if (foo(other)) { x.a = props.a; } x.b = props.a.b; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order1.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order1.expect.md index ac67e5dd5e..0acc4dc3f1 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order1.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order1.expect.md @@ -25,23 +25,14 @@ function TestConditionalSuperpath1(props, other) { // as a dependency // ordering of accesses should not matter function TestConditionalSuperpath1(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props.a; const c_1 = $[1] !== other; let x; if (c_0 || c_1) { x = {}; x.a = props.a; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { + if (foo(other)) { x.b = props.a.b; } $[0] = props.a; diff --git a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order2.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order2.expect.md index 52fdceb006..fc32e61f3e 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order2.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reduce-reactive-cond-deps-superpath-order2.expect.md @@ -25,22 +25,13 @@ function TestConditionalSuperpath2(props, other) { // as a dependency // ordering of accesses should not matter function TestConditionalSuperpath2(props, other) { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== other; const c_1 = $[1] !== props.a; let x; if (c_0 || c_1) { x = {}; - const c_3 = $[3] !== other; - let t0; - if (c_3) { - t0 = foo(other); - $[3] = other; - $[4] = t0; - } else { - t0 = $[4]; - } - if (t0) { + if (foo(other)) { x.b = props.a.b; } x.a = props.a; diff --git a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md index c4f6052007..055923ee83 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md @@ -46,7 +46,7 @@ function foo(props) { // note: comments are for the ideal scopes, not what is currently // emitted function foo(props) { - const $ = React.unstable_useMemoCache(16); + const $ = React.unstable_useMemoCache(7); const c_0 = $[0] !== props.a; let x; if (c_0) { @@ -57,70 +57,39 @@ function foo(props) { } else { x = $[1]; } - const c_2 = $[2] !== props.showHeader; - const c_3 = $[3] !== x; - let t0; - if (c_2 || c_3) { - t0 = props.showHeader ?
{x}
: null; - $[2] = props.showHeader; - $[3] = x; - $[4] = t0; - } else { - t0 = $[4]; - } - const header = t0; - const c_5 = $[5] !== x; - const c_6 = $[6] !== props.b; - const c_7 = $[7] !== props.c; + + const header = props.showHeader ?
{x}
: null; + const c_2 = $[2] !== x; + const c_3 = $[3] !== props.b; + const c_4 = $[4] !== props.c; let y; - if (c_5 || c_6 || c_7) { + if (c_2 || c_3 || c_4) { y = [x]; x = []; y.push(props.b); x.push(props.c); - $[5] = x; - $[6] = props.b; - $[7] = props.c; - $[8] = y; - $[9] = x; + $[2] = x; + $[3] = props.b; + $[4] = props.c; + $[5] = y; + $[6] = x; } else { - y = $[8]; - x = $[9]; + y = $[5]; + x = $[6]; } - const c_10 = $[10] !== x; - const c_11 = $[11] !== y; - let t1; - if (c_10 || c_11) { - t1 = ( -
- {x} - {y} -
- ); - $[10] = x; - $[11] = y; - $[12] = t1; - } else { - t1 = $[12]; - } - const content = t1; - const c_13 = $[13] !== header; - const c_14 = $[14] !== content; - let t2; - if (c_13 || c_14) { - t2 = ( - <> - {header} - {content} - - ); - $[13] = header; - $[14] = content; - $[15] = t2; - } else { - t2 = $[15]; - } - return t2; + + const content = ( +
+ {x} + {y} +
+ ); + return ( + <> + {header} + {content} + + ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.expect.md b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.expect.md index dc4c090b37..fa6a6227b1 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/same-variable-as-dep-and-redeclare.expect.md @@ -46,7 +46,7 @@ function foo(props) { // note: comments are for the ideal scopes, not what is currently // emitted function foo(props) { - const $ = React.unstable_useMemoCache(15); + const $ = React.unstable_useMemoCache(7); const c_0 = $[0] !== props.a; let x; if (c_0) { @@ -57,68 +57,39 @@ function foo(props) { } else { x = $[1]; } + + const header =
{x}
; const c_2 = $[2] !== x; - let t0; - if (c_2) { - t0 =
{x}
; - $[2] = x; - $[3] = t0; - } else { - t0 = $[3]; - } - const header = t0; - const c_4 = $[4] !== x; - const c_5 = $[5] !== props.b; - const c_6 = $[6] !== props.c; + const c_3 = $[3] !== props.b; + const c_4 = $[4] !== props.c; let y; - if (c_4 || c_5 || c_6) { + if (c_2 || c_3 || c_4) { y = [x]; x = []; y.push(props.b); x.push(props.c); - $[4] = x; - $[5] = props.b; - $[6] = props.c; - $[7] = y; - $[8] = x; + $[2] = x; + $[3] = props.b; + $[4] = props.c; + $[5] = y; + $[6] = x; } else { - y = $[7]; - x = $[8]; + y = $[5]; + x = $[6]; } - const c_9 = $[9] !== x; - const c_10 = $[10] !== y; - let t1; - if (c_9 || c_10) { - t1 = ( -
- {x} - {y} -
- ); - $[9] = x; - $[10] = y; - $[11] = t1; - } else { - t1 = $[11]; - } - const content = t1; - const c_12 = $[12] !== header; - const c_13 = $[13] !== content; - let t2; - if (c_12 || c_13) { - t2 = ( - <> - {header} - {content} - - ); - $[12] = header; - $[13] = content; - $[14] = t2; - } else { - t2 = $[14]; - } - return t2; + + const content = ( +
+ {x} + {y} +
+ ); + return ( + <> + {header} + {content} + + ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx-2.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx-2.expect.md index 8326b7e3fd..8d33b08ebb 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx-2.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx-2.expect.md @@ -25,21 +25,14 @@ function Component(props) { function foo() {} function Component(props) { - const $ = React.unstable_useMemoCache(4); + const $ = React.unstable_useMemoCache(2); let a; let b; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { a = []; b = {}; foo(a, b); - let t0; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t0 = foo(); - $[2] = t0; - } else { - t0 = $[2]; - } - if (t0) { + if (foo()) { } foo(a, b); @@ -49,14 +42,7 @@ function Component(props) { a = $[0]; b = $[1]; } - let t1; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t1 =
; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return
; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx.expect.md index e786729615..8a59efbd00 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx.expect.md @@ -21,7 +21,7 @@ function Component(props) { function foo() {} function Component(props) { - const $ = React.unstable_useMemoCache(3); + const $ = React.unstable_useMemoCache(2); let a; let b; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { @@ -36,14 +36,7 @@ function Component(props) { a = $[0]; b = $[1]; } - let t0; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t0 =
; - $[2] = t0; - } else { - t0 = $[2]; - } - return t0; + return
; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-cascading-eliminated-phis.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-cascading-eliminated-phis.expect.md index 88538e4925..6451c8f766 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-cascading-eliminated-phis.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-cascading-eliminated-phis.expect.md @@ -24,22 +24,13 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(4); + const $ = React.unstable_useMemoCache(2); let x = 0; const c_0 = $[0] !== props; let values; if (c_0) { values = []; - const c_2 = $[2] !== props; - let t0; - if (c_2) { - t0 = props.a || props.b; - $[2] = props; - $[3] = t0; - } else { - t0 = $[3]; - } - const y = t0; + const y = props.a || props.b; values.push(y); if (props.c) { x = 1; diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-for-trivial-update.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-for-trivial-update.expect.md index 9ce7eb94ba..add2bb00dd 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-for-trivial-update.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-for-trivial-update.expect.md @@ -16,16 +16,9 @@ function foo() { ```javascript function foo() { - const $ = React.unstable_useMemoCache(1); - let x; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x = 1; - for (const i = 0; true; 0) { - x = x + 1; - } - $[0] = x; - } else { - x = $[0]; + let x = 1; + for (const i = 0; true; 0) { + x = x + 1; } return x; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-for.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-for.expect.md index 0504fe30d6..6ce00eed13 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-for.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-for.expect.md @@ -16,16 +16,9 @@ function foo() { ```javascript function foo() { - const $ = React.unstable_useMemoCache(1); - let x; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x = 1; - for (let i = 0; i < 10; i = i + 1, i) { - x = x + 1; - } - $[0] = x; - } else { - x = $[0]; + let x = 1; + for (let i = 0; i < 10; i = i + 1, i) { + x = x + 1; } return x; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-leave-case.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-leave-case.expect.md index 72c1e52d44..a9fe1e2ee3 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-leave-case.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-leave-case.expect.md @@ -23,7 +23,7 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(6); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props; let x; let y; @@ -41,23 +41,12 @@ function Component(props) { x = $[1]; y = $[2]; } - const c_3 = $[3] !== x; - const c_4 = $[4] !== y; - let t0; - if (c_3 || c_4) { - t0 = ( - - {x} - {y} - - ); - $[3] = x; - $[4] = y; - $[5] = t0; - } else { - t0 = $[5]; - } - return t0; + return ( + + {x} + {y} + + ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md index 21c3ed6f41..8b6a3ca0ed 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md @@ -17,16 +17,9 @@ function foo() { ```javascript function foo() { - const $ = React.unstable_useMemoCache(1); - let x; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x = 1; - while (x < 10) { - x = x + 1; - } - $[0] = x; - } else { - x = $[0]; + let x = 1; + while (x < 10) { + x = x + 1; } return x; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md b/compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md index 617fbc88fb..edf573ba87 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md @@ -32,7 +32,7 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(9); + const $ = React.unstable_useMemoCache(4); const c_0 = $[0] !== props; let x; let y; @@ -69,29 +69,10 @@ function Component(props) { x = $[1]; y = $[2]; } - const c_4 = $[4] !== x; - let t1; - if (c_4) { - t1 = ; - $[4] = x; - $[5] = t1; - } else { - t1 = $[5]; - } - const child = t1; + + const child = ; y.push(props.p4); - const c_6 = $[6] !== y; - const c_7 = $[7] !== child; - let t2; - if (c_6 || c_7) { - t2 = {child}; - $[6] = y; - $[7] = child; - $[8] = t2; - } else { - t2 = $[8]; - } - return t2; + return {child}; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/switch.expect.md b/compiler/forget/src/__tests__/fixtures/hir/switch.expect.md index 1ab3f13f01..beccdd160d 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/switch.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/switch.expect.md @@ -27,7 +27,7 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(8); + const $ = React.unstable_useMemoCache(3); const c_0 = $[0] !== props; let x; let y; @@ -50,29 +50,10 @@ function Component(props) { x = $[1]; y = $[2]; } - const c_3 = $[3] !== x; - let t0; - if (c_3) { - t0 = ; - $[3] = x; - $[4] = t0; - } else { - t0 = $[4]; - } - const child = t0; + + const child = ; y.push(props.p4); - const c_5 = $[5] !== y; - const c_6 = $[6] !== child; - let t1; - if (c_5 || c_6) { - t1 = {child}; - $[5] = y; - $[6] = child; - $[7] = t1; - } else { - t1 = $[7]; - } - return t1; + return {child}; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/temporary-at-start-of-value-block.expect.md b/compiler/forget/src/__tests__/fixtures/hir/temporary-at-start-of-value-block.expect.md index 29f79e4370..7aadfcb57b 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/temporary-at-start-of-value-block.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/temporary-at-start-of-value-block.expect.md @@ -14,17 +14,7 @@ function component(props) { ```javascript function component(props) { - const $ = React.unstable_useMemoCache(2); - const c_0 = $[0] !== props; - let t0; - if (c_0) { - t0 = isMenuShown ? {props.a ? props.b : props.c} : null; - $[0] = props; - $[1] = t0; - } else { - t0 = $[1]; - } - const x = t0; + const x = isMenuShown ? {props.a ? props.b : props.c} : null; return x; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md index 9ff10bb632..fb6e412c66 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md @@ -14,39 +14,9 @@ function ternary(props) { ```javascript function ternary(props) { - const $ = React.unstable_useMemoCache(7); - const c_0 = $[0] !== props; - let t0; - if (c_0) { - t0 = props.a && props.b ? props.c || props.d : props.e ?? props.f; - $[0] = props; - $[1] = t0; - } else { - t0 = $[1]; - } - const a = t0; - const c_2 = $[2] !== props; - let t1; - if (c_2) { - t1 = props.a ? (props.b && props.c ? props.d : props.e) : props.f; - $[2] = props; - $[3] = t1; - } else { - t1 = $[3]; - } - const b = t1; - const c_4 = $[4] !== a; - const c_5 = $[5] !== b; - let t2; - if (c_4 || c_5) { - t2 = a ? b : null; - $[4] = a; - $[5] = b; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + const a = props.a && props.b ? props.c || props.d : props.e ?? props.f; + const b = props.a ? (props.b && props.c ? props.d : props.e) : props.f; + return a ? b : null; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/timers.expect.md b/compiler/forget/src/__tests__/fixtures/hir/timers.expect.md index 414007af95..ff5ed5784f 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/timers.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/timers.expect.md @@ -19,43 +19,22 @@ function Component(props) { ```javascript function Component(props) { - const $ = React.unstable_useMemoCache(4); + const $ = React.unstable_useMemoCache(1); + const start = performance.now(); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = performance.now(); + t0 = Date.now(); $[0] = t0; } else { t0 = $[0]; } - const start = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = Date.now(); - $[1] = t1; - } else { - t1 = $[1]; - } - const now = t1; - let t2; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = performance.now(); - $[2] = t2; - } else { - t2 = $[2]; - } - const time = t2 - start; - let t3; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t3 = ( -
- rendering took {time} at {now} -
- ); - $[3] = t3; - } else { - t3 = $[3]; - } - return t3; + const now = t0; + const time = performance.now() - start; + return ( +
+ rendering took {time} at {now} +
+ ); } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/type-binary-operator.expect.md b/compiler/forget/src/__tests__/fixtures/hir/type-binary-operator.expect.md index 087ff35c9a..a3e5be659b 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/type-binary-operator.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/type-binary-operator.expect.md @@ -16,23 +16,8 @@ function component() { ```javascript function component() { - const $ = React.unstable_useMemoCache(2); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = some(); - $[0] = t0; - } else { - t0 = $[0]; - } - const a = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = someOther(); - $[1] = t1; - } else { - t1 = $[1]; - } - const b = t1; + const a = some(); + const b = someOther(); if (a > b) { } } diff --git a/compiler/forget/src/__tests__/fixtures/hir/type-test-return-type-inference.expect.md b/compiler/forget/src/__tests__/fixtures/hir/type-test-return-type-inference.expect.md index 0a4b769a0f..19f69faef0 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/type-test-return-type-inference.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/type-test-return-type-inference.expect.md @@ -19,7 +19,11 @@ function component() { ```javascript function component() { - const $ = React.unstable_useMemoCache(3); + const $ = React.unstable_useMemoCache(1); + const x = foo(); + const y = foo(); + if (x > y) { + } let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = foo(); @@ -27,25 +31,7 @@ function component() { } else { t0 = $[0]; } - const x = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = foo(); - $[1] = t1; - } else { - t1 = $[1]; - } - const y = t1; - if (x > y) { - } - let t2; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = foo(); - $[2] = t2; - } else { - t2 = $[2]; - } - const z_0 = t2; + const z_0 = t0; return z_0; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/unary-expr.expect.md b/compiler/forget/src/__tests__/fixtures/hir/unary-expr.expect.md index 868956d994..05638fcee1 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/unary-expr.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/unary-expr.expect.md @@ -20,58 +20,37 @@ function component(a) { ```javascript function component(a) { - const $ = React.unstable_useMemoCache(14); - const c_0 = $[0] !== a; - let t0; - let t; - let z; - let p; - let q; - if (c_0) { - t = { t: a }; - z = +t.t; - q = -t.t; - p = void t.t; - t0 = delete t.t; - $[0] = a; - $[1] = t0; - $[2] = t; - $[3] = z; - $[4] = p; - $[5] = q; - } else { - t0 = $[1]; - t = $[2]; - z = $[3]; - p = $[4]; - q = $[5]; - } - const n = t0; + const $ = React.unstable_useMemoCache(8); + const t = { t: a }; + const z = +t.t; + const q = -t.t; + const p = void t.t; + const n = delete t.t; const m = !t.t; const e = ~t.t; const f = typeof t.t; - const c_6 = $[6] !== z; - const c_7 = $[7] !== p; - const c_8 = $[8] !== q; - const c_9 = $[9] !== n; - const c_10 = $[10] !== m; - const c_11 = $[11] !== e; - const c_12 = $[12] !== f; - let t1; - if (c_6 || c_7 || c_8 || c_9 || c_10 || c_11 || c_12) { - t1 = { z, p, q, n, m, e, f }; - $[6] = z; - $[7] = p; - $[8] = q; - $[9] = n; - $[10] = m; - $[11] = e; - $[12] = f; - $[13] = t1; + const c_0 = $[0] !== z; + const c_1 = $[1] !== p; + const c_2 = $[2] !== q; + const c_3 = $[3] !== n; + const c_4 = $[4] !== m; + const c_5 = $[5] !== e; + const c_6 = $[6] !== f; + let t0; + if (c_0 || c_1 || c_2 || c_3 || c_4 || c_5 || c_6) { + t0 = { z, p, q, n, m, e, f }; + $[0] = z; + $[1] = p; + $[2] = q; + $[3] = n; + $[4] = m; + $[5] = e; + $[6] = f; + $[7] = t0; } else { - t1 = $[13]; + t0 = $[7]; } - return t1; + return t0; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/use-callback-simple.expect.md b/compiler/forget/src/__tests__/fixtures/hir/use-callback-simple.expect.md index 27e04507db..4228e8a584 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/use-callback-simple.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/use-callback-simple.expect.md @@ -15,7 +15,7 @@ function component() { ```javascript function component() { - const $ = React.unstable_useMemoCache(5); + const $ = React.unstable_useMemoCache(3); const [count, setCount] = useState(0); const c_0 = $[0] !== setCount; const c_1 = $[1] !== count; @@ -29,16 +29,7 @@ function component() { t0 = $[2]; } const increment = t0; - const c_3 = $[3] !== increment; - let t1; - if (c_3) { - t1 = ; - $[3] = increment; - $[4] = t1; - } else { - t1 = $[4]; - } - return t1; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/useMemo-simple.expect.md b/compiler/forget/src/__tests__/fixtures/hir/useMemo-simple.expect.md index ef1baed8c5..182a54a307 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/useMemo-simple.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/useMemo-simple.expect.md @@ -13,7 +13,7 @@ function component(a) { ```javascript function component(a) { - const $ = React.unstable_useMemoCache(4); + const $ = React.unstable_useMemoCache(2); const c_0 = $[0] !== a; let t0; if (c_0) { @@ -24,16 +24,7 @@ function component(a) { t0 = $[1]; } const x = t0; - const c_2 = $[2] !== x; - let t1; - if (c_2) { - t1 = ; - $[2] = x; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + return ; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/while-property.expect.md b/compiler/forget/src/__tests__/fixtures/hir/while-property.expect.md index b19dd0c1da..087dcd7cbe 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/while-property.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/while-property.expect.md @@ -16,20 +16,9 @@ function foo(a, b) { ```javascript function foo(a, b) { - const $ = React.unstable_useMemoCache(3); - const c_0 = $[0] !== a.b.c; - const c_1 = $[1] !== b; - let x; - if (c_0 || c_1) { - x = 0; - while (a.b.c) { - x = x + b; - } - $[0] = a.b.c; - $[1] = b; - $[2] = x; - } else { - x = $[2]; + let x = 0; + while (a.b.c) { + x = x + b; } return x; }