From c8c0495dce0b44c07ce276e2c37b0f5bea33a8df Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 29 May 2024 16:26:32 -0700 Subject: [PATCH] compiler: super early exploration of instruction reordering See comments in InstructionReordering.ts. This needs substantial iteration before landing in some form, just putting up to share for discussion. ghstack-source-id: 765c47c3d6ce37af06de307b71af5a8c2f4a8fa5 Pull Request resolved: https://github.com/facebook/react/pull/29579 --- .../src/Entrypoint/Pipeline.ts | 4 + .../src/Inference/InferReferenceEffects.ts | 6 + .../src/Optimization/ConstantPropagation.ts | 2 +- .../src/Optimization/InstructionReordering.ts | 322 ++++++++++++++++++ .../InferReactiveScopeVariables.ts | 5 +- .../MemoizeFbtOperandsInSameScope.ts | 19 ++ ...rgeReactiveScopesThatInvalidateTogether.ts | 13 +- .../src/Utils/utils.ts | 4 +- ...n-in-effect-indirect-usecallback.expect.md | 9 +- ...obal-mutation-in-effect-indirect.expect.md | 55 ++- ...-reassignment-in-effect-indirect.expect.md | 55 ++- ...ow-global-reassignment-in-effect.expect.md | 9 +- ...mutate-global-in-effect-fixpoint.expect.md | 9 +- .../compiler/concise-arrow-expr.expect.md | 15 +- .../compiler/conditional-on-mutable.expect.md | 52 +-- ...gation-into-function-expressions.expect.md | 16 +- ...ble-reassigned-outside-of-lambda.expect.md | 16 +- ...variable-in-function-declaration.expect.md | 15 +- ...and-local-variables-with-default.expect.md | 71 ++-- ...ed-scope-declarations-and-locals.expect.md | 34 +- ...er-declaration-of-previous-scope.expect.md | 32 +- ...rycatch-nested-overlapping-range.expect.md | 2 +- ...rror.repro-bug-ref-mutable-range.expect.md | 2 +- ...todo-reactive-scope-overlaps-try.expect.md | 2 +- ...no-whitespace-btw-text-and-param.expect.md | 7 +- .../fbt/fbt-preserve-whitespace.expect.md | 7 +- ...-single-space-btw-param-and-text.expect.md | 7 +- ...bt-whitespace-around-param-value.expect.md | 7 +- .../fbt/fbt-whitespace-within-text.expect.md | 7 +- ...btparam-with-jsx-element-content.expect.md | 15 +- .../compiler/fbt/lambda-with-fbt.expect.md | 20 +- ...onmutating-loop-local-collection.expect.md | 32 +- ...sting-computed-member-expression.expect.md | 22 +- .../hoisting-member-expression.expect.md | 17 +- ...-promoted-to-outer-scope-dynamic.expect.md | 65 ++-- .../jsx-preserve-whitespace.expect.md | 32 +- ...merge-consecutive-scopes-objects.expect.md | 39 +-- .../merge-consecutive-scopes.expect.md | 46 ++- .../compiler/merge-scopes-callback.expect.md | 32 +- ...-expr-export-default-gating-test.expect.md | 19 +- ...ti-arrow-expr-export-gating-test.expect.md | 19 +- .../multi-arrow-expr-gating-test.expect.md | 19 +- .../compiler/property-assignment.expect.md | 25 +- .../reassignment-conditional.expect.md | 38 +-- .../fixtures/compiler/reassignment.expect.md | 38 +-- ...on-from-merge-consecutive-scopes.expect.md | 37 +- ...ion-part-of-already-closed-scope.expect.md | 83 +++-- .../repro-no-value-for-temporary.expect.md | 22 +- .../repro-separate-scopes-for-divs.expect.md | 24 +- .../fixtures/compiler/repro.expect.md | 26 +- .../compiler/ssa-leave-case.expect.md | 25 +- .../switch-non-final-default.expect.md | 44 ++- .../fixtures/compiler/switch.expect.md | 34 +- ...sion-captures-value-later-frozen.expect.md | 19 +- .../type-test-field-load-binary-op.expect.md | 13 +- .../compiler/useEffect-arg-memoized.expect.md | 44 +-- .../useEffect-nested-lambdas.expect.md | 57 ++-- ...tion-with-mutable-range-is-valid.expect.md | 2 +- compiler/packages/snap/src/runner.ts | 14 + 59 files changed, 926 insertions(+), 800 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 1fa755499ed62..91c4f2ef8ae11 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -41,6 +41,7 @@ import { deadCodeElimination, pruneMaybeThrows, } from "../Optimization"; +import { instructionReordering } from "../Optimization/InstructionReordering"; import { CodegenFunction, alignObjectMethodScopes, @@ -195,6 +196,9 @@ function* runWithEnvironment( deadCodeElimination(hir); yield log({ kind: "hir", name: "DeadCodeElimination", value: hir }); + instructionReordering(hir); + yield log({ kind: "hir", name: "InstructionReordering", value: hir }); + pruneMaybeThrows(hir); yield log({ kind: "hir", name: "PruneMaybeThrows", value: hir }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts index 520684c026bda..015bbb345b75f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts @@ -737,6 +737,12 @@ class InferenceState { * For debugging purposes, dumps the state to a plain * object so that it can printed as JSON. */ + inspect(): any { + return { + values: this.#values, + variables: this.#variables, + }; + } debug(): any { const result: any = { values: {}, variables: {} }; const objects: Map = new Map(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts index e2116c9d94fdc..91216d5880c28 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts @@ -441,7 +441,7 @@ function evaluateInstruction( } case "LoadLocal": { const placeValue = read(constants, value.place); - if (placeValue !== null) { + if (placeValue != null) { instr.value = placeValue; } return placeValue; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts new file mode 100644 index 0000000000000..bef9aba654f96 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts @@ -0,0 +1,322 @@ +import { + BasicBlock, + Environment, + HIRFunction, + IdentifierId, + Instruction, + markInstructionIds, +} from "../HIR"; +import { printFunction, printInstruction } from "../HIR/PrintHIR"; +import { + eachInstructionValueLValue, + eachInstructionValueOperand, + eachTerminalOperand, +} from "../HIR/visitors"; +import { mayAllocate } from "../ReactiveScopes/InferReactiveScopeVariables"; +import { getOrInsertDefault } from "../Utils/utils"; + +/** + * WIP early exploration of instruction reordering. This is a fairly aggressive form and has + * some issues. The idea of what's implemented: + * + * The high-level approach is to build a dependency graph where nodes generally correspond + * either to instructions OR to particular lvalue assignments of an expresssion. So + * `Destructure [x, y] = z` creates 3 nodes: one for the instruction, and one each for x and y. + * The lvalue nodes depend on the instruction node that assigns them. + * + * We add dependency edges for all the rvalues/lvalues of each instruction. In addition, we + * implicitly add dependencies btw non-reorderable instructions (more on that criteria) to + * serialize any instruction where order might be observable. + * + * We then distinguish two types of instructions that are reorderable: + * - Primitives, JSXText, JSX elements, and globals can be *globally* reordered, ie across blocks. + * We defer emitting them until they are first used globally. + * - Array and object expressions are reorderable within basic blocks. This could likely be relaxed to be global. + * - StoreLocal, LoadLocal, and Destructure are reorderable within basic blocks. However, we serialize all + * references to each named variable (reads and writes) to ensure that we aren't changing the order of evaluation + * of variable references. + * + * The variable reordering relies on the fact that any variables that could be reassigned via a function expression + * are promoted to "context" variables and use LoadContext/StoreContext, which are not reorderable. + * + * In theory it might even be safe to do this variable reordering globally, but i want to think through that more. + * + * With the above context, the algorithm is approximately: + * - For each basic block: + * - Iterate the instructions to create the dependency graph + * - Re-emit instructions, "pulling" from all the values that are depended upon by the block's terminal. + * - Emit any remaining instructions that cannot be globally reordered, starting from later instructions first. + * - Save any globally-reorderable instructions into a global map that is shared across blocks, so they can be + * emitted by the first block that needs them. + * + * Emitting instructions is currently naive: we just iterate in the order that the dependencies were established. + * If instruction 4 depends on instructions 1, 2, and 3, we'll visit in depth-first order and emit 1, 2, 3, 4. + * That's true even if instruction 1 and 2 are simple instructions (for ex primitives) while instruction 3 has its + * own large dependency tree. + * + * ## Issues/things to explore: + * + * - An obvious improvement is to weight the nodes and emit dependencies based on weight. Alternatively, we could try to + * determine the reactive dependencies of each node, and try to emit nodes that have the same dependencies together. + * - Reordering destructure statements means that we also end up deferring the evaluation of its RHS. So i noticed some + * `const [state, setState] = useState(...)` getting moved around. But i think i might have just messed up the bit that + * ensures non-reorderable instructions (like the useState() call here) are serialized. So this should just be a simple fix, + * if i didn't already fix it (need to go back through the fixture output changes) + * - I also noticed that destructuring being moved meant that some reactive scopes ended up with less precise input, because + * the destructure moved into the reactive scope itself (so the scope depends on the rvalue of the destructure, not the lvalues). + * This is weird, i need to debug. + * - Probably more things. + */ +export function instructionReordering(fn: HIRFunction): void { + DEBUG && console.log(printFunction(fn)); + const globalDependencies: Dependencies = new Map(); + for (const [, block] of fn.body.blocks) { + reorderBlock(fn.env, block, globalDependencies); + } + markInstructionIds(fn.body); + DEBUG && console.log(printFunction(fn)); +} + +const DEBUG = false; + +type Dependencies = Map; +type Node = { + instruction: Instruction | null; + dependencies: Array; + depth: number | null; +}; + +function reorderBlock( + env: Environment, + block: BasicBlock, + globalDependencies: Dependencies +): void { + DEBUG && console.log(`bb${block.id}`); + const dependencies: Dependencies = new Map(); + const locals = new Map(); + let previousIdentifier: IdentifierId | null = null; + for (const instr of block.instructions) { + const node: Node = getOrInsertDefault( + dependencies, + instr.lvalue.identifier.id, + { + instruction: instr, + dependencies: [], + depth: null, + } + ); + if (getReorderingLevel(instr) === ReorderingLevel.None) { + if (previousIdentifier !== null) { + node.dependencies.push(previousIdentifier); + } + previousIdentifier = instr.lvalue.identifier.id; + } + for (const operand of eachInstructionValueOperand(instr.value)) { + if ( + operand.identifier.name !== null && + operand.identifier.name.kind === "named" + ) { + const previous = locals.get(operand.identifier.name.value); + if (previous !== undefined) { + node.dependencies.push(previous); + } + locals.set(operand.identifier.name.value, instr.lvalue.identifier.id); + } else { + if (dependencies.has(operand.identifier.id) || globalDependencies.has(operand.identifier.id)) { + node.dependencies.push(operand.identifier.id); + } + } + } + dependencies.set(instr.lvalue.identifier.id, node); + + for (const lvalue of eachInstructionValueLValue(instr.value)) { + const lvalueNode = getOrInsertDefault( + dependencies, + lvalue.identifier.id, + { + instruction: null, + dependencies: [], + depth: null, + } + ); + lvalueNode.dependencies.push(instr.lvalue.identifier.id); + if ( + lvalue.identifier.name !== null && + lvalue.identifier.name.kind === "named" + ) { + const previous = locals.get(lvalue.identifier.name.value); + if (previous !== undefined) { + node.dependencies.push(previous); + } + locals.set(lvalue.identifier.name.value, instr.lvalue.identifier.id); + } + } + } + + function getDepth(env: Environment, id: IdentifierId): number { + const node = dependencies.get(id); + if (node == null) { + return 0; + } + if (node.depth !== null) { + return node.depth; + } + node.depth = 0; + let depth = + node.instruction != null && mayAllocate(env, node.instruction) ? 1 : 0; + for (const dep of node.dependencies) { + depth += getDepth(env, dep); + } + node.depth = depth; + return depth; + } + + const instructions: Array = []; + + function print( + id: IdentifierId, + seen: Set, + depth: number = 0 + ): void { + const node = dependencies.get(id) ?? globalDependencies.get(id); + if (node == null || seen.has(id)) { + DEBUG && console.log(`${"\t|".repeat(depth)} skip $${id}`); + return; + } + seen.add(id); + node.dependencies.sort((a, b) => { + const aDepth = getDepth(env, a); + const bDepth = getDepth(env, b); + return bDepth - aDepth; + }); + for (const dep of node.dependencies) { + print(dep, seen, depth + 1); + } + DEBUG && console.log(`${"\t|".repeat(depth)} ${printNode(id, node)}`); + } + const seen = new Set(); + if (DEBUG) { + for (const operand of eachTerminalOperand(block.terminal)) { + print(operand.identifier.id, seen); + } + for (const id of Array.from(dependencies.keys()).reverse()) { + print(id, seen); + } + } + + function emit(id: IdentifierId): void { + const node = dependencies.get(id) ?? globalDependencies.get(id); + if (node == null) { + return; + } + dependencies.delete(id); + globalDependencies.delete(id); + node.dependencies.sort((a, b) => { + const aDepth = getDepth(env, a); + const bDepth = getDepth(env, b); + return bDepth - aDepth; + }); + for (const dep of node.dependencies) { + emit(dep); + } + if (node.instruction !== null) { + instructions.push(node.instruction); + } + } + + for (const operand of eachTerminalOperand(block.terminal)) { + DEBUG && console.log(`terminal operand: $${operand.identifier.id}`); + emit(operand.identifier.id); + } + /** + * Gross hack: for value blocks we want the terminal operand to be emitted last, since that's its value. + * For other blocks the exact order doesn't matter, we assume instructions whose values aren't depended + * upon by the block terminal are used later, so it makes sense to order them last. + */ + const index = instructions.length; + for (const id of Array.from(dependencies.keys()).reverse()) { + const node = dependencies.get(id); + if (node == null) { + continue; + } + if ( + node.instruction !== null && + getReorderingLevel(node.instruction) === ReorderingLevel.Global && + (block.kind === 'block' || block.kind === 'catch') + ) { + globalDependencies.set(id, node); + DEBUG && console.log(`global: $${id}`); + } else { + DEBUG && console.log(`other: $${id}`); + emit(id); + } + } + if (block.kind !== 'block' && block.kind !== 'catch') { + const extra = instructions.splice(index); + instructions.splice(0, 0, ...extra); + } + block.instructions = instructions; + DEBUG && console.log(); +} + +function printDeps(deps: Dependencies): string { + return ( + "[\n" + + Array.from(deps) + .map(([id, dep]) => printNode(id, dep)) + .join("\n") + + "\n]" + ); +} + +function printNode(id: number, node: Node): string { + if ( + node.instruction != null && + node.instruction.value.kind === "FunctionExpression" + ) { + return `$${id} FunctionExpression deps=[${node.dependencies + .map((x) => `$${x}`) + .join(", ")}]`; + } + return `$${id} ${ + node.instruction != null ? printInstruction(node.instruction) : "" + } deps=[${node.dependencies.map((x) => `$${x}`).join(", ")}] depth=${ + node.depth + }`; +} + +enum ReorderingLevel { + None = "none", + Local = "local", + Global = "global", +} +function getReorderingLevel(instr: Instruction): ReorderingLevel { + switch (instr.value.kind) { + case "JsxExpression": + case "JsxFragment": + case "JSXText": + case "LoadGlobal": + case "Primitive": + case "TemplateLiteral": { + return ReorderingLevel.Global; + } + /* + For locals, a simple and robust strategy is to figure out the range of instructions where the identifier may be reassigned, + and then allow reordering of LoadLocal instructions which occur after this range. Obviously for const, this means that all + LoadLocals can be reordered, so a simpler thing to start with is just to only allow reordering of loads of known-consts. + + With this overall strategy we can allow global reordering of LoadLocals and remove the global/local reordering distinction + (all reordering can be global). + + case "Destructure": + case "StoreLocal": + case "LoadLocal": + { + return ReorderingLevel.Local; + } + */ + default: { + return ReorderingLevel.None; + } + } +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts index a8142c8720ac5..68dcff31efc58 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts @@ -165,7 +165,10 @@ export function isMutable({ id }: Instruction, place: Place): boolean { return id >= range.start && id < range.end; } -function mayAllocate(env: Environment, instruction: Instruction): boolean { +export function mayAllocate( + env: Environment, + instruction: Instruction +): boolean { const { value } = instruction; switch (value.kind) { case "Destructure": { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MemoizeFbtOperandsInSameScope.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MemoizeFbtOperandsInSameScope.ts index daab49d22b267..774aeea1c54ae 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MemoizeFbtOperandsInSameScope.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MemoizeFbtOperandsInSameScope.ts @@ -94,6 +94,8 @@ function visit(fn: HIRFunction, fbtValues: Set): void { operand.identifier.mutableRange.start ) ); + + fbtValues.add(operand.identifier.id); } } else if ( isFbtJsxExpression(fbtValues, value) || @@ -126,6 +128,23 @@ function visit(fn: HIRFunction, fbtValues: Set): void { */ fbtValues.add(operand.identifier.id); } + } else if (fbtValues.has(lvalue.identifier.id)) { + const fbtScope = lvalue.identifier.scope; + if (fbtScope === null) { + return; + } + + for (const operand of eachReactiveValueOperand(value)) { + operand.identifier.scope = fbtScope; + + // Expand the jsx element's range to account for its operands + fbtScope.range.start = makeInstructionId( + Math.min( + fbtScope.range.start, + operand.identifier.mutableRange.start + ) + ); + } } } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts index 149ba34bdf651..a63b565eaebda 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts @@ -29,7 +29,10 @@ import { } from "../HIR/ObjectShape"; import { eachInstructionLValue } from "../HIR/visitors"; import { assertExhaustive } from "../Utils/utils"; -import { printReactiveScopeSummary } from "./PrintReactiveFunction"; +import { + printReactiveFunction, + printReactiveScopeSummary, +} from "./PrintReactiveFunction"; import { ReactiveFunctionTransform, ReactiveFunctionVisitor, @@ -84,9 +87,16 @@ import { export function mergeReactiveScopesThatInvalidateTogether( fn: ReactiveFunction ): void { + if (DEBUG) { + console.log(printReactiveFunction(fn)); + } const lastUsageVisitor = new FindLastUsageVisitor(); visitReactiveFunction(fn, lastUsageVisitor, undefined); visitReactiveFunction(fn, new Transform(lastUsageVisitor.lastUsage), null); + + if (DEBUG) { + console.log(printReactiveFunction(fn)); + } } const DEBUG: boolean = false; @@ -176,6 +186,7 @@ class Transform extends ReactiveFunctionTransform( array: Array, predicate: (item: T) => boolean diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect-usecallback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect-usecallback.expect.md index 33c6e23105139..7a7535560946f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect-usecallback.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect-usecallback.expect.md @@ -67,19 +67,16 @@ function Component() { } useEffect(t1, t2); let t3; + let t4; if ($[3] === Symbol.for("react.memo_cache_sentinel")) { t3 = () => { setState(someGlobal.value); }; - $[3] = t3; - } else { - t3 = $[3]; - } - let t4; - if ($[4] === Symbol.for("react.memo_cache_sentinel")) { t4 = [someGlobal]; + $[3] = t3; $[4] = t4; } else { + t3 = $[3]; t4 = $[4]; } useEffect(t3, t4); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect.expect.md index 44813be9f180a..b79635c84088f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect.expect.md @@ -39,60 +39,51 @@ import { useEffect, useState } from "react"; let someGlobal = {}; function Component() { - const $ = _c(7); + const $ = _c(6); const [state, setState] = useState(someGlobal); let t0; + let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { + const setGlobal = () => { someGlobal.value = true; }; - $[0] = t0; - } else { - t0 = $[0]; - } - const setGlobal = t0; - let t1; - let t2; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = () => { + + t0 = () => { setGlobal(); }; - t2 = []; + t1 = []; + $[0] = t0; $[1] = t1; - $[2] = t2; } else { + t0 = $[0]; t1 = $[1]; - t2 = $[2]; } - useEffect(t1, t2); + useEffect(t0, t1); + let t2; let t3; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t3 = () => { + if ($[2] === Symbol.for("react.memo_cache_sentinel")) { + t2 = () => { setState(someGlobal.value); }; + t3 = [someGlobal]; + $[2] = t2; $[3] = t3; } else { + t2 = $[2]; t3 = $[3]; } - let t4; - if ($[4] === Symbol.for("react.memo_cache_sentinel")) { - t4 = [someGlobal]; - $[4] = t4; - } else { - t4 = $[4]; - } - useEffect(t3, t4); + useEffect(t2, t3); - const t5 = String(state); - let t6; - if ($[5] !== t5) { - t6 =
{t5}
; + const t4 = String(state); + let t5; + if ($[4] !== t4) { + t5 =
{t4}
; + $[4] = t4; $[5] = t5; - $[6] = t6; } else { - t6 = $[6]; + t5 = $[5]; } - return t6; + return t5; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect-indirect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect-indirect.expect.md index 27e2d3b3a45a4..0a4527a0a4706 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect-indirect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect-indirect.expect.md @@ -39,60 +39,51 @@ import { useEffect, useState } from "react"; let someGlobal = false; function Component() { - const $ = _c(7); + const $ = _c(6); const [state, setState] = useState(someGlobal); let t0; + let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { + const setGlobal = () => { someGlobal = true; }; - $[0] = t0; - } else { - t0 = $[0]; - } - const setGlobal = t0; - let t1; - let t2; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = () => { + + t0 = () => { setGlobal(); }; - t2 = []; + t1 = []; + $[0] = t0; $[1] = t1; - $[2] = t2; } else { + t0 = $[0]; t1 = $[1]; - t2 = $[2]; } - useEffect(t1, t2); + useEffect(t0, t1); + let t2; let t3; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t3 = () => { + if ($[2] === Symbol.for("react.memo_cache_sentinel")) { + t2 = () => { setState(someGlobal); }; + t3 = [someGlobal]; + $[2] = t2; $[3] = t3; } else { + t2 = $[2]; t3 = $[3]; } - let t4; - if ($[4] === Symbol.for("react.memo_cache_sentinel")) { - t4 = [someGlobal]; - $[4] = t4; - } else { - t4 = $[4]; - } - useEffect(t3, t4); + useEffect(t2, t3); - const t5 = String(state); - let t6; - if ($[5] !== t5) { - t6 =
{t5}
; + const t4 = String(state); + let t5; + if ($[4] !== t4) { + t5 =
{t4}
; + $[4] = t4; $[5] = t5; - $[6] = t6; } else { - t6 = $[6]; + t5 = $[5]; } - return t6; + return t5; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect.expect.md index 293e32f4a191d..e4cd0e22c12f8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect.expect.md @@ -54,19 +54,16 @@ function Component() { } useEffect(t0, t1); let t2; + let t3; if ($[2] === Symbol.for("react.memo_cache_sentinel")) { t2 = () => { setState(someGlobal); }; - $[2] = t2; - } else { - t2 = $[2]; - } - let t3; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { t3 = [someGlobal]; + $[2] = t2; $[3] = t3; } else { + t2 = $[2]; t3 = $[3]; } useEffect(t2, t3); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md index 3f212a4add872..d5f8643d5b1c1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md @@ -70,19 +70,16 @@ function Component() { } useEffect(t0, t1); let t2; + let t3; if ($[2] === Symbol.for("react.memo_cache_sentinel")) { t2 = () => { setState(someGlobal.value); }; - $[2] = t2; - } else { - t2 = $[2]; - } - let t3; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { t3 = [someGlobal]; + $[2] = t2; $[3] = t3; } else { + t2 = $[2]; t3 = $[3]; } useEffect(t2, t3); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/concise-arrow-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/concise-arrow-expr.expect.md index b993630ce98d0..5b88a40644927 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/concise-arrow-expr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/concise-arrow-expr.expect.md @@ -15,24 +15,17 @@ function component() { ```javascript import { c as _c } from "react/compiler-runtime"; function component() { - const $ = _c(2); + const $ = _c(1); const [x, setX] = useState(0); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = (v) => setX(v); + const handler = (v) => setX(v); + t0 = ; $[0] = t0; } else { t0 = $[0]; } - const handler = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ; - $[1] = t1; - } else { - t1 = $[1]; - } - return t1; + return t0; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md index cd2fbc1011a4a..ad638cf28d871 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md @@ -36,65 +36,45 @@ function mayMutate() {} ```javascript import { c as _c } from "react/compiler-runtime"; function ComponentA(props) { - const $ = _c(6); - let a; - let b; + const $ = _c(2); + let t0; if ($[0] !== props) { - a = []; - b = []; + const a = []; + const b = []; if (b) { a.push(props.p0); } if (props.p1) { b.push(props.p2); } - $[0] = props; - $[1] = a; - $[2] = b; - } else { - a = $[1]; - b = $[2]; - } - let t0; - if ($[3] !== a || $[4] !== b) { + t0 = ; - $[3] = a; - $[4] = b; - $[5] = t0; + $[0] = props; + $[1] = t0; } else { - t0 = $[5]; + t0 = $[1]; } return t0; } function ComponentB(props) { - const $ = _c(6); - let a; - let b; + const $ = _c(2); + let t0; if ($[0] !== props) { - a = []; - b = []; + const a = []; + const b = []; if (mayMutate(b)) { a.push(props.p0); } if (props.p1) { b.push(props.p2); } - $[0] = props; - $[1] = a; - $[2] = b; - } else { - a = $[1]; - b = $[2]; - } - let t0; - if ($[3] !== a || $[4] !== b) { + t0 = ; - $[3] = a; - $[4] = b; - $[5] = t0; + $[0] = props; + $[1] = t0; } else { - t0 = $[5]; + t0 = $[1]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md index 7be6b15a887dd..8ea2190480003 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md @@ -17,25 +17,19 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(2); + const $ = _c(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { + const onEvent = () => { console.log(42); }; + + t0 = ; $[0] = t0; } else { t0 = $[0]; } - const onEvent = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ; - $[1] = t1; - } else { - t1 = $[1]; - } - return t1; + return t0; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-outside-of-lambda.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-outside-of-lambda.expect.md index 9b70b18c24b6a..8d53b0cc42d60 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-outside-of-lambda.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-outside-of-lambda.expect.md @@ -27,26 +27,20 @@ import { c as _c } from "react/compiler-runtime"; import { Stringify } from "shared-runtime"; function Component(props) { - const $ = _c(2); - let callback; + const $ = _c(1); + let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { let x; x = null; - callback = () => { + const callback = () => { console.log(x); }; x = {}; - $[0] = callback; - } else { - callback = $[0]; - } - let t0; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { t0 = ; - $[1] = t0; + $[0] = t0; } else { - t0 = $[1]; + t0 = $[0]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/declare-reassign-variable-in-function-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/declare-reassign-variable-in-function-declaration.expect.md index 4c6faaaad25f4..b9fc15ea0a7be 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/declare-reassign-variable-in-function-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/declare-reassign-variable-in-function-declaration.expect.md @@ -18,7 +18,7 @@ function Component() { ```javascript import { c as _c } from "react/compiler-runtime"; function Component() { - const $ = _c(2); + const $ = _c(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { let x; @@ -27,20 +27,13 @@ function Component() { x = 9; }; - t0 = bar(foo); + const y = bar(foo); + t0 = ; $[0] = t0; } else { t0 = $[0]; } - const y = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ; - $[1] = t1; - } else { - t1 = $[1]; - } - return t1; + return t0; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-and-local-variables-with-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-and-local-variables-with-default.expect.md index e93fbb3b45fcf..d8be3af6cbd34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-and-local-variables-with-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-and-local-variables-with-default.expect.md @@ -56,7 +56,7 @@ function useFragment(_arg1, _arg2) { } function Component(props) { - const $ = _c(15); + const $ = _c(9); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = graphql`...`; @@ -65,67 +65,52 @@ function Component(props) { t0 = $[0]; } const post = useFragment(t0, props.post); - let media; - let allUrls; - let onClick; + let t1; if ($[1] !== post) { - allUrls = []; + const allUrls = []; - const { media: t1, comments: t2, urls: t3 } = post; - media = t1 === undefined ? null : t1; - let t4; - if ($[5] !== t2) { - t4 = t2 === undefined ? [] : t2; - $[5] = t2; - $[6] = t4; - } else { - t4 = $[6]; - } - const comments = t4; + const { media: t2, comments: t3, urls: t4 } = post; + const media = t2 === undefined ? null : t2; let t5; - if ($[7] !== t3) { + if ($[3] !== t3) { t5 = t3 === undefined ? [] : t3; - $[7] = t3; - $[8] = t5; + $[3] = t3; + $[4] = t5; } else { - t5 = $[8]; + t5 = $[4]; } - const urls = t5; + const comments = t5; let t6; - if ($[9] !== comments.length) { - t6 = (e) => { + if ($[5] !== t4) { + t6 = t4 === undefined ? [] : t4; + $[5] = t4; + $[6] = t6; + } else { + t6 = $[6]; + } + const urls = t6; + let t7; + if ($[7] !== comments.length) { + t7 = (e) => { if (!comments.length) { return; } console.log(comments.length); }; - $[9] = comments.length; - $[10] = t6; + $[7] = comments.length; + $[8] = t7; } else { - t6 = $[10]; + t7 = $[8]; } - onClick = t6; + const onClick = t7; allUrls.push(...urls); - $[1] = post; - $[2] = media; - $[3] = allUrls; - $[4] = onClick; - } else { - media = $[2]; - allUrls = $[3]; - onClick = $[4]; - } - let t1; - if ($[11] !== media || $[12] !== allUrls || $[13] !== onClick) { t1 = ; - $[11] = media; - $[12] = allUrls; - $[13] = onClick; - $[14] = t1; + $[1] = post; + $[2] = t1; } else { - t1 = $[14]; + t1 = $[2]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md index 665b4a65fd063..69e0f07088e0b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md @@ -30,17 +30,15 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(8); + const $ = _c(4); const post = useFragment(graphql`...`, props.post); - let media; - let onClick; + let t0; if ($[0] !== post) { const allUrls = []; - const { media: t0, comments, urls } = post; - media = t0; + const { media, comments, urls } = post; let t1; - if ($[3] !== comments.length) { + if ($[2] !== comments.length) { t1 = (e) => { if (!comments.length) { return; @@ -48,29 +46,19 @@ function Component(props) { console.log(comments.length); }; - $[3] = comments.length; - $[4] = t1; + $[2] = comments.length; + $[3] = t1; } else { - t1 = $[4]; + t1 = $[3]; } - onClick = t1; + const onClick = t1; allUrls.push(...urls); - $[0] = post; - $[1] = media; - $[2] = onClick; - } else { - media = $[1]; - onClick = $[2]; - } - let t0; - if ($[5] !== media || $[6] !== onClick) { t0 = ; - $[5] = media; - $[6] = onClick; - $[7] = t0; + $[0] = post; + $[1] = t0; } else { - t0 = $[7]; + t0 = $[1]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md index ad843e230fc48..2fc5577fb9712 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md @@ -99,42 +99,42 @@ function Component(t0) { t2 = $[12]; } let t3; - if ($[13] !== t2 || $[14] !== x) { - t3 = ; - $[13] = t2; - $[14] = x; + if ($[13] !== a || $[14] !== b) { + t3 = [a, b]; + $[13] = a; + $[14] = b; $[15] = t3; } else { t3 = $[15]; } let t4; - if ($[16] !== a || $[17] !== b) { - t4 = [a, b]; - $[16] = a; - $[17] = b; + if ($[16] !== t3 || $[17] !== z) { + t4 = ; + $[16] = t3; + $[17] = z; $[18] = t4; } else { t4 = $[18]; } let t5; - if ($[19] !== t4 || $[20] !== z) { - t5 = ; - $[19] = t4; - $[20] = z; + if ($[19] !== t2 || $[20] !== x) { + t5 = ; + $[19] = t2; + $[20] = x; $[21] = t5; } else { t5 = $[21]; } let t6; - if ($[22] !== t3 || $[23] !== t5) { + if ($[22] !== t5 || $[23] !== t4) { t6 = ( <> - {t3} {t5} + {t4} ); - $[22] = t3; - $[23] = t5; + $[22] = t5; + $[23] = t4; $[24] = t6; } else { t6 = $[24]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-repro-trycatch-nested-overlapping-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-repro-trycatch-nested-overlapping-range.expect.md index ca77829e2f7f4..2390842e78f7d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-repro-trycatch-nested-overlapping-range.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-repro-trycatch-nested-overlapping-range.expect.md @@ -20,7 +20,7 @@ function Foo() { ## Error ``` -Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 2:24(18:26) +Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 2:23(17:25) ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-bug-ref-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-bug-ref-mutable-range.expect.md index 7cd2acc9affab..ead99369987cb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-bug-ref-mutable-range.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-bug-ref-mutable-range.expect.md @@ -21,7 +21,7 @@ function Foo(props, ref) { ## Error ``` -Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 1:21(16:23) +Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 2:20(16:23) ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-reactive-scope-overlaps-try.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-reactive-scope-overlaps-try.expect.md index 95cdbe5aeea76..e10a451cf3af1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-reactive-scope-overlaps-try.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-reactive-scope-overlaps-try.expect.md @@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = { ## Error ``` -Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 4:19(5:22) +Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 3:17(4:20) ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-no-whitespace-btw-text-and-param.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-no-whitespace-btw-text-and-param.expect.md index b48c92bb761d0..a305b961baf09 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-no-whitespace-btw-text-and-param.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-no-whitespace-btw-text-and-param.expect.md @@ -29,15 +29,16 @@ import fbt from "fbt"; const _ = fbt; function Component(t0) { const $ = _c(2); - const { value } = t0; let t1; - if ($[0] !== value) { + if ($[0] !== t0) { + const { value } = t0; + t1 = fbt._( "Before text{paramName}After text", [fbt._param("paramName", value)], { hk: "aKEGX" }, ); - $[0] = value; + $[0] = t0; $[1] = t1; } else { t1 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace.expect.md index 5e67bbc163194..13de247d0b4ef 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace.expect.md @@ -30,9 +30,10 @@ import fbt from "fbt"; const _ = fbt; function Component(t0) { const $ = _c(2); - const { value } = t0; let t1; - if ($[0] !== value) { + if ($[0] !== t0) { + const { value } = t0; + t1 = fbt._( "Before text {paramName}", [ @@ -44,7 +45,7 @@ function Component(t0) { ], { hk: "3z5SVE" }, ); - $[0] = value; + $[0] = t0; $[1] = t1; } else { t1 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-single-space-btw-param-and-text.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-single-space-btw-param-and-text.expect.md index 7fa312c49f791..b75a8261125d0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-single-space-btw-param-and-text.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-single-space-btw-param-and-text.expect.md @@ -29,15 +29,16 @@ import fbt from "fbt"; const _ = fbt; function Component(t0) { const $ = _c(2); - const { value } = t0; let t1; - if ($[0] !== value) { + if ($[0] !== t0) { + const { value } = t0; + t1 = fbt._( "Before text {paramName} after text", [fbt._param("paramName", value)], { hk: "26pxNm" }, ); - $[0] = value; + $[0] = t0; $[1] = t1; } else { t1 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-around-param-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-around-param-value.expect.md index 3bfd3bab52c15..9d939a90b6168 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-around-param-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-around-param-value.expect.md @@ -29,15 +29,16 @@ import fbt from "fbt"; const _ = fbt; function Component(t0) { const $ = _c(2); - const { value } = t0; let t1; - if ($[0] !== value) { + if ($[0] !== t0) { + const { value } = t0; + t1 = fbt._( "Before text {paramName} after text", [fbt._param("paramName", value)], { hk: "26pxNm" }, ); - $[0] = value; + $[0] = t0; $[1] = t1; } else { t1 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-within-text.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-within-text.expect.md index 55326204caa41..2e854647a85ac 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-within-text.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-whitespace-within-text.expect.md @@ -31,15 +31,16 @@ import fbt from "fbt"; const _ = fbt; function Component(t0) { const $ = _c(2); - const { value } = t0; let t1; - if ($[0] !== value) { + if ($[0] !== t0) { + const { value } = t0; + t1 = fbt._( "Before text {paramName} after text more text and more and more and more and more and more and more and more and more and blah blah blah blah", [fbt._param("paramName", value)], { hk: "24ZPpO" }, ); - $[0] = value; + $[0] = t0; $[1] = t1; } else { t1 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md index 387031fc181c7..402b4df8a12ab 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md @@ -29,10 +29,11 @@ import { c as _c } from "react/compiler-runtime"; import fbt from "fbt"; function Component(t0) { - const $ = _c(4); - const { name, data, icon } = t0; + const $ = _c(2); let t1; - if ($[0] !== name || $[1] !== icon || $[2] !== data) { + if ($[0] !== t0) { + const { name, data, icon } = t0; + t1 = ( {fbt._( @@ -61,12 +62,10 @@ function Component(t0) { )} ); - $[0] = name; - $[1] = icon; - $[2] = data; - $[3] = t1; + $[0] = t0; + $[1] = t1; } else { - t1 = $[3]; + t1 = $[1]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/lambda-with-fbt.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/lambda-with-fbt.expect.md index 5ac0ad17a0645..f7e71f4be7bb9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/lambda-with-fbt.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/lambda-with-fbt.expect.md @@ -42,10 +42,10 @@ import { c as _c } from "react/compiler-runtime"; import { fbt } from "fbt"; function Component() { - const $ = _c(2); + const $ = _c(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { + const buttonLabel = () => { if (!someCondition) { return fbt._("Purchase as a gift", null, { hk: "1gHj4g" }); } else { @@ -66,23 +66,17 @@ function Component() { } } }; - $[0] = t0; - } else { - t0 = $[0]; - } - const buttonLabel = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ( + + t0 = ( + ); t1 = {state}; - $[1] = state; + $[0] = state; + $[1] = t0; $[2] = t1; } else { + t0 = $[1]; t1 = $[2]; } let t2; - if ($[3] !== state) { - t2 = ( - - ); - $[3] = state; - $[4] = t2; + if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + t2 = ; + $[3] = t2; } else { - t2 = $[4]; + t2 = $[3]; } let t3; - if ($[5] !== t1 || $[6] !== t2) { + if ($[4] !== t1 || $[5] !== t0) { t3 = (
- {t0} - {t1} {t2} + {t1} + {t0}
); - $[5] = t1; - $[6] = t2; - $[7] = t3; + $[4] = t1; + $[5] = t0; + $[6] = t3; } else { - t3 = $[7]; + t3 = $[6]; } return t3; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-scopes-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-scopes-callback.expect.md index eacff50f8892c..8e80428cceca7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-scopes-callback.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-scopes-callback.expect.md @@ -26,7 +26,7 @@ import { c as _c } from "react/compiler-runtime"; import { useState } from "react"; function Component() { - const $ = _c(6); + const $ = _c(4); const [state, setState] = useState(0); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { @@ -39,34 +39,26 @@ function Component() { } const onClick = t0; let t1; - if ($[1] !== state) { - t1 = Count: {state}; - $[1] = state; - $[2] = t1; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + t1 = ; + $[1] = t1; } else { - t1 = $[2]; + t1 = $[1]; } let t2; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t2 = ; - $[3] = t2; - } else { - t2 = $[3]; - } - let t3; - if ($[4] !== t1) { - t3 = ( + if ($[2] !== state) { + t2 = ( <> + Count: {state} {t1} - {t2} ); - $[4] = t1; - $[5] = t3; + $[2] = state; + $[3] = t2; } else { - t3 = $[5]; + t2 = $[3]; } - return t3; + return t2; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-default-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-default-gating-test.expect.md index b7685a3d40fc6..4bbc85df89d87 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-default-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-default-gating-test.expect.md @@ -36,27 +36,20 @@ const ErrorView = isForgetEnabled_Fixtures() export default Renderer = isForgetEnabled_Fixtures() ? (props) => { - const $ = _c(2); + const $ = _c(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = ; - $[0] = t0; - } else { - t0 = $[0]; - } - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ( + t0 = ( - {t0} + ); - $[1] = t1; + $[0] = t0; } else { - t1 = $[1]; + t0 = $[0]; } - return t1; + return t0; } : (props) => ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-gating-test.expect.md index 6056b8f378f0e..e7bf6b327e95b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-export-gating-test.expect.md @@ -36,27 +36,20 @@ const ErrorView = isForgetEnabled_Fixtures() export const Renderer = isForgetEnabled_Fixtures() ? (props) => { - const $ = _c(2); + const $ = _c(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = ; - $[0] = t0; - } else { - t0 = $[0]; - } - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ( + t0 = ( - {t0} + ); - $[1] = t1; + $[0] = t0; } else { - t1 = $[1]; + t0 = $[0]; } - return t1; + return t0; } : (props) => ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-gating-test.expect.md index e830d72ed94c5..4ce7ec0fc4061 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multi-arrow-expr-gating-test.expect.md @@ -38,27 +38,20 @@ const ErrorView = isForgetEnabled_Fixtures() const Renderer = isForgetEnabled_Fixtures() ? (props) => { - const $ = _c(2); + const $ = _c(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = ; - $[0] = t0; - } else { - t0 = $[0]; - } - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ( + t0 = ( - {t0} + ); - $[1] = t1; + $[0] = t0; } else { - t1 = $[1]; + t0 = $[0]; } - return t1; + return t0; } : (props) => ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/property-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/property-assignment.expect.md index 65b2c46abf5bb..523b5b29bd8c6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/property-assignment.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/property-assignment.expect.md @@ -18,30 +18,19 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(6); - let x; - let child; + const $ = _c(2); + let t0; if ($[0] !== props.p0) { - x = {}; + const x = {}; const y = []; x.y = y; - child = ; + const child = ; x.y.push(props.p0); - $[0] = props.p0; - $[1] = x; - $[2] = child; - } else { - x = $[1]; - child = $[2]; - } - let t0; - if ($[3] !== x || $[4] !== child) { t0 = {child}; - $[3] = x; - $[4] = child; - $[5] = t0; + $[0] = props.p0; + $[1] = t0; } else { - t0 = $[5]; + t0 = $[1]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md index 0cda46f5a05e0..9358d39cf448a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md @@ -23,42 +23,32 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(9); - let x; - let y; + const $ = _c(5); + let t0; if ($[0] !== props.p0 || $[1] !== props.p1 || $[2] !== props.p2) { - x = []; + let x = []; x.push(props.p0); - y = x; + const y = x; if (props.p1) { - let t0; - if ($[5] === Symbol.for("react.memo_cache_sentinel")) { - t0 = []; - $[5] = t0; + let t1; + if ($[4] === Symbol.for("react.memo_cache_sentinel")) { + t1 = []; + $[4] = t1; } else { - t0 = $[5]; + t1 = $[4]; } - x = t0; + x = t1; } y.push(props.p2); + + t0 = ; $[0] = props.p0; $[1] = props.p1; $[2] = props.p2; - $[3] = x; - $[4] = y; - } else { - x = $[3]; - y = $[4]; - } - let t0; - if ($[6] !== x || $[7] !== y) { - t0 = ; - $[6] = x; - $[7] = y; - $[8] = t0; + $[3] = t0; } else { - t0 = $[8]; + t0 = $[3]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment.expect.md index 82cb494c9e4ee..3804326553c93 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment.expect.md @@ -22,39 +22,29 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(8); - let x; - let y; + const $ = _c(4); + let t0; if ($[0] !== props.p0 || $[1] !== props.p1) { - x = []; + let x = []; x.push(props.p0); - y = x; - let t0; - if ($[4] === Symbol.for("react.memo_cache_sentinel")) { - t0 = []; - $[4] = t0; + const y = x; + let t1; + if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + t1 = []; + $[3] = t1; } else { - t0 = $[4]; + t1 = $[3]; } - x = t0; + x = t1; y.push(props.p1); + + t0 = ; $[0] = props.p0; $[1] = props.p1; - $[2] = x; - $[3] = y; - } else { - x = $[2]; - y = $[3]; - } - let t0; - if ($[5] !== x || $[6] !== y) { - t0 = ; - $[5] = x; - $[6] = y; - $[7] = t0; + $[2] = t0; } else { - t0 = $[7]; + t0 = $[2]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md index 75627f01a7035..0c731395e2a4e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md @@ -29,30 +29,39 @@ import { c as _c } from "react/compiler-runtime"; import { Stringify } from "shared-runtime"; function Component(t0) { - const $ = _c(3); + const $ = _c(5); const { id } = t0; - let t1; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t1 = ; + + const t1 = id ? true : false; + let t2; + if ($[0] !== t1) { + t2 = ; $[0] = t1; + $[1] = t2; } else { - t1 = $[0]; + t2 = $[1]; } - const t2 = id ? true : false; let t3; - if ($[1] !== t2) { - t3 = ( + if ($[2] === Symbol.for("react.memo_cache_sentinel")) { + t3 = ; + $[2] = t3; + } else { + t3 = $[2]; + } + let t4; + if ($[3] !== t2) { + t4 = ( <> - {t1} - + {t3} + {t2} ); - $[1] = t2; - $[2] = t3; + $[3] = t2; + $[4] = t4; } else { - t3 = $[2]; + t4 = $[4]; } - return t3; + return t4; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-instruction-part-of-already-closed-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-instruction-part-of-already-closed-scope.expect.md index f1fc418d92c33..7465af20323e7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-instruction-part-of-already-closed-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-instruction-part-of-already-closed-scope.expect.md @@ -35,10 +35,9 @@ import { c as _c } from "react/compiler-runtime"; // @enableAssumeHooksFollowRul import { Stringify, identity, useHook } from "shared-runtime"; function Component(t0) { - const $ = _c(17); + const $ = _c(15); const { index } = t0; const data = useHook(); - let T0; let t1; let t2; let t3; @@ -47,62 +46,60 @@ function Component(t0) { const b = identity(data, index); const c = identity(data, index); - const t4 = identity(b); - if ($[6] !== t4) { - t2 = ; - $[6] = t4; - $[7] = t2; - } else { - t2 = $[7]; - } - const t5 = identity(a); - if ($[8] !== t5) { - t3 = ; - $[8] = t5; - $[9] = t3; - } else { - t3 = $[9]; - } - T0 = Stringify; + t3 = identity(b); + t2 = identity(a); t1 = identity(c); $[0] = data; $[1] = index; - $[2] = T0; - $[3] = t1; - $[4] = t2; - $[5] = t3; + $[2] = t1; + $[3] = t2; + $[4] = t3; } else { - T0 = $[2]; - t1 = $[3]; - t2 = $[4]; - t3 = $[5]; + t1 = $[2]; + t2 = $[3]; + t3 = $[4]; } let t4; - if ($[10] !== T0 || $[11] !== t1) { - t4 = ; - $[10] = T0; - $[11] = t1; - $[12] = t4; + if ($[5] !== t1) { + t4 = ; + $[5] = t1; + $[6] = t4; } else { - t4 = $[12]; + t4 = $[6]; } let t5; - if ($[13] !== t2 || $[14] !== t3 || $[15] !== t4) { - t5 = ( + if ($[7] !== t2) { + t5 = ; + $[7] = t2; + $[8] = t5; + } else { + t5 = $[8]; + } + let t6; + if ($[9] !== t3) { + t6 = ; + $[9] = t3; + $[10] = t6; + } else { + t6 = $[10]; + } + let t7; + if ($[11] !== t6 || $[12] !== t5 || $[13] !== t4) { + t7 = (
- {t2} - {t3} + {t6} + {t5} {t4}
); - $[13] = t2; - $[14] = t3; - $[15] = t4; - $[16] = t5; + $[11] = t6; + $[12] = t5; + $[13] = t4; + $[14] = t7; } else { - t5 = $[16]; + t7 = $[14]; } - return t5; + return t7; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md index 5eff1aa0fe5e2..8c6eae7b8454e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md @@ -17,34 +17,30 @@ function Component(listItem, thread) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(listItem, thread) { - const $ = _c(7); + const $ = _c(6); let t0; let t1; - let t2; if ($[0] !== thread.threadType || $[1] !== listItem) { const isFoo = isFooThread(thread.threadType); - t1 = useBar; - t2 = listItem; + t1 = listItem; t0 = getBadgeText(listItem, isFoo); $[0] = thread.threadType; $[1] = listItem; $[2] = t0; $[3] = t1; - $[4] = t2; } else { t0 = $[2]; t1 = $[3]; - t2 = $[4]; } - let t3; - if ($[5] !== t0) { - t3 = [t0]; - $[5] = t0; - $[6] = t3; + let t2; + if ($[4] !== t0) { + t2 = [t0]; + $[4] = t0; + $[5] = t2; } else { - t3 = $[6]; + t2 = $[5]; } - const body = t1(t2, t3); + const body = useBar(t1, t2); return body; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-separate-scopes-for-divs.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-separate-scopes-for-divs.expect.md index 0a38e47b34ea7..19d5fbdf8c3ec 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-separate-scopes-for-divs.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-separate-scopes-for-divs.expect.md @@ -56,33 +56,33 @@ function Component(t0) { t2 = $[1]; } let t3; - if ($[2] !== t2) { - t3 =
; - $[2] = t2; + if ($[2] !== cond) { + t3 = cond === false && ( +
+ ); + $[2] = cond; $[3] = t3; } else { t3 = $[3]; } let t4; - if ($[4] !== cond) { - t4 = cond === false && ( -
- ); - $[4] = cond; + if ($[4] !== t2) { + t4 =
; + $[4] = t2; $[5] = t4; } else { t4 = $[5]; } let t5; - if ($[6] !== t3 || $[7] !== t4) { + if ($[6] !== t4 || $[7] !== t3) { t5 = ( <> - {t3} {t4} + {t3} ); - $[6] = t3; - $[7] = t4; + $[6] = t4; + $[7] = t3; $[8] = t5; } else { t5 = $[8]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md index 07e508b259365..6ca1483fad1da 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md @@ -24,13 +24,12 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(6); + const $ = _c(2); const item = props.item; - let baseVideos; - let thumbnails; + let t0; if ($[0] !== item) { - thumbnails = []; - baseVideos = getBaseVideos(item); + const thumbnails = []; + const baseVideos = getBaseVideos(item); baseVideos.forEach((video) => { const baseVideo = video.hasBaseVideo; @@ -38,21 +37,12 @@ function Component(props) { thumbnails.push({ extraVideo: true }); } }); - $[0] = item; - $[1] = baseVideos; - $[2] = thumbnails; - } else { - baseVideos = $[1]; - thumbnails = $[2]; - } - let t0; - if ($[3] !== baseVideos || $[4] !== thumbnails) { + t0 = ; - $[3] = baseVideos; - $[4] = thumbnails; - $[5] = t0; + $[0] = item; + $[1] = t0; } else { - t0 = $[5]; + t0 = $[1]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md index 0dbe08c710523..a7389041bb12d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md @@ -24,35 +24,26 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(6); - let x; - let y; + const $ = _c(2); + let t0; if ($[0] !== props) { - x = []; + const x = []; + let y; if (props.p0) { x.push(props.p1); y = x; } - $[0] = props; - $[1] = x; - $[2] = y; - } else { - x = $[1]; - y = $[2]; - } - let t0; - if ($[3] !== x || $[4] !== y) { + t0 = ( {x} {y} ); - $[3] = x; - $[4] = y; - $[5] = t0; + $[0] = props; + $[1] = t0; } else { - t0 = $[5]; + t0 = $[1]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md index a3e6dfeb8572a..915218fcfa467 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md @@ -33,25 +33,25 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(9); - let x; + const $ = _c(7); let y; + let t0; if ($[0] !== props) { - x = []; + const x = []; bb0: switch (props.p0) { case 1: { break bb0; } case true: { x.push(props.p2); - let t0; + let t1; if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t0 = []; - $[3] = t0; + t1 = []; + $[3] = t1; } else { - t0 = $[3]; + t1 = $[3]; } - y = t0; + y = t1; } default: { break bb0; @@ -60,31 +60,25 @@ function Component(props) { y = x; } } - $[0] = props; - $[1] = x; - $[2] = y; - } else { - x = $[1]; - y = $[2]; - } - let t0; - if ($[4] !== x) { + t0 = ; - $[4] = x; - $[5] = t0; + $[0] = props; + $[1] = y; + $[2] = t0; } else { - t0 = $[5]; + y = $[1]; + t0 = $[2]; } const child = t0; y.push(props.p4); let t1; - if ($[6] !== y || $[7] !== child) { + if ($[4] !== y || $[5] !== child) { t1 = {child}; - $[6] = y; - $[7] = child; - $[8] = t1; + $[4] = y; + $[5] = child; + $[6] = t1; } else { - t1 = $[8]; + t1 = $[6]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md index 14ac820af7c55..0c5aea9c7da9c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md @@ -28,11 +28,11 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(8); - let x; + const $ = _c(6); let y; + let t0; if ($[0] !== props) { - x = []; + const x = []; switch (props.p0) { case true: { x.push(props.p2); @@ -42,31 +42,25 @@ function Component(props) { y = x; } } - $[0] = props; - $[1] = x; - $[2] = y; - } else { - x = $[1]; - y = $[2]; - } - let t0; - if ($[3] !== x) { + t0 = ; - $[3] = x; - $[4] = t0; + $[0] = props; + $[1] = y; + $[2] = t0; } else { - t0 = $[4]; + y = $[1]; + t0 = $[2]; } const child = t0; y.push(props.p4); let t1; - if ($[5] !== y || $[6] !== child) { + if ($[3] !== y || $[4] !== child) { t1 = {child}; - $[5] = y; - $[6] = child; - $[7] = t1; + $[3] = y; + $[4] = child; + $[5] = t1; } else { - t1 = $[7]; + t1 = $[5]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md index 2fdb888230e40..9f8fed44f0a02 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md @@ -24,10 +24,10 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(4); - let x; + const $ = _c(2); + let t0; if ($[0] !== props.cond) { - x = {}; + const x = {}; const onChange = (e) => { maybeMutate(x, e.target.value); @@ -36,18 +36,11 @@ function Component(props) { } onChange(); - $[0] = props.cond; - $[1] = x; - } else { - x = $[1]; - } - let t0; - if ($[2] !== x) { t0 = ; - $[2] = x; - $[3] = t0; + $[0] = props.cond; + $[1] = t0; } else { - t0 = $[3]; + t0 = $[1]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-test-field-load-binary-op.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-test-field-load-binary-op.expect.md index 6f6ab2e3a119c..3bb448d26d070 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-test-field-load-binary-op.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-test-field-load-binary-op.expect.md @@ -21,22 +21,15 @@ function component() { ```javascript import { c as _c } from "react/compiler-runtime"; function component() { - const $ = _c(2); + const $ = _c(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = makeSomePrimitive(); + t0 = { u: makeSomePrimitive(), v: makeSomePrimitive() }; $[0] = t0; } else { t0 = $[0]; } - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = { u: t0, v: makeSomePrimitive() }; - $[1] = t1; - } else { - t1 = $[1]; - } - const x = t1; + const x = t0; const u = x.u; const v = x.v; if (u > v) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-arg-memoized.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-arg-memoized.expect.md index eadd8b7de8b7c..af4bab363b258 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-arg-memoized.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-arg-memoized.expect.md @@ -27,42 +27,42 @@ function Component(props) { import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(6); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
; + $[0] = t0; + } else { + t0 = $[0]; + } const dispatch = useDispatch(); useFreeze(dispatch); - let t0; - if ($[0] !== dispatch) { - t0 = () => { + let t1; + if ($[1] !== dispatch) { + t1 = () => { dispatch({ kind: "update" }); }; - $[0] = dispatch; - $[1] = t0; + $[1] = dispatch; + $[2] = t1; } else { - t0 = $[1]; + t1 = $[2]; } - const onUpdate = t0; - let t1; + const onUpdate = t1; let t2; - if ($[2] !== onUpdate) { - t1 = () => { + let t3; + if ($[3] !== onUpdate) { + t2 = () => { onUpdate(); }; - t2 = [onUpdate]; - $[2] = onUpdate; - $[3] = t1; + t3 = [onUpdate]; + $[3] = onUpdate; $[4] = t2; - } else { - t1 = $[3]; - t2 = $[4]; - } - useEffect(t1, t2); - let t3; - if ($[5] === Symbol.for("react.memo_cache_sentinel")) { - t3 =
; $[5] = t3; } else { + t2 = $[4]; t3 = $[5]; } - return t3; + useEffect(t2, t3); + return t0; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md index 90847235ffd07..fe99e2ddb6be8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md @@ -36,23 +36,30 @@ import { c as _c } from "react/compiler-runtime"; // @enableTransitivelyFreezeFu function Component(props) { const $ = _c(9); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
; + $[0] = t0; + } else { + t0 = $[0]; + } const item = useMutable(props.itemId); const dispatch = useDispatch(); useFreeze(dispatch); - let t0; - if ($[0] !== dispatch) { - t0 = () => { + let t1; + if ($[1] !== dispatch) { + t1 = () => { dispatch(createExitAction()); }; - $[0] = dispatch; - $[1] = t0; + $[1] = dispatch; + $[2] = t1; } else { - t0 = $[1]; + t1 = $[2]; } - const exit = t0; - let t1; - if ($[2] !== item.value || $[3] !== exit) { - t1 = () => { + const exit = t1; + let t2; + if ($[3] !== item.value || $[4] !== exit) { + t2 = () => { const cleanup = GlobalEventEmitter.addListener("onInput", () => { if (item.value) { exit(); @@ -60,32 +67,24 @@ function Component(props) { }); return () => cleanup.remove(); }; - $[2] = item.value; - $[3] = exit; - $[4] = t1; - } else { - t1 = $[4]; - } - let t2; - if ($[5] !== exit || $[6] !== item) { - t2 = [exit, item]; - $[5] = exit; - $[6] = item; - $[7] = t2; + $[3] = item.value; + $[4] = exit; + $[5] = t2; } else { - t2 = $[7]; + t2 = $[5]; } - useEffect(t1, t2); - - maybeMutate(item); let t3; - if ($[8] === Symbol.for("react.memo_cache_sentinel")) { - t3 =
; + if ($[6] !== exit || $[7] !== item) { + t3 = [exit, item]; + $[6] = exit; + $[7] = item; $[8] = t3; } else { t3 = $[8]; } - return t3; + useEffect(t2, t3); + maybeMutate(item); + return t0; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md index 017b282205d68..3405bd8cf6da2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md @@ -80,7 +80,6 @@ function Component(props) { return t2; } default: { - logEvent("Invalid step"); let t1; if ($[6] === Symbol.for("react.memo_cache_sentinel")) { t1 = ; @@ -88,6 +87,7 @@ function Component(props) { } else { t1 = $[6]; } + logEvent("Invalid step"); return t1; } } diff --git a/compiler/packages/snap/src/runner.ts b/compiler/packages/snap/src/runner.ts index 55fcaa66e91c5..9d1ecc7b6c280 100644 --- a/compiler/packages/snap/src/runner.ts +++ b/compiler/packages/snap/src/runner.ts @@ -34,6 +34,7 @@ type RunnerOptions = { watch: boolean; filter: boolean; update: boolean; + verbose: boolean; }; const opts: RunnerOptions = yargs @@ -61,10 +62,19 @@ const opts: RunnerOptions = yargs "Only run fixtures which match the contents of testfilter.txt" ) .default("filter", false) + .boolean('verbose') + .describe('verbose', 'Enable additional logging') + .default('verbose', false) .help("help") .strict() .parseSync(hideBin(process.argv)); +function log(msg: string): void { + if (opts.verbose) { + console.log(msg); + } +} + /** * Do a test run and return the test results */ @@ -98,16 +108,20 @@ async function runFixtures( entries = await Promise.all(work); } else { + log('runFixtures() start'); entries = []; for (const [fixtureName, fixture] of fixtures) { + log(`${fixture.inputPath} start`); let output = await runnerWorker.transformFixture( fixture, compilerVersion, (filter?.debug ?? false) && isOnlyFixture, true ); + log('...complete'); entries.push([fixtureName, output]); } + log('runFixtures() complete'); } return new Map(entries);