diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index 9545271fce..5e88b4c4c4 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -127,7 +127,7 @@ export function lower( const terminal: ReturnTerminal = { kind: "return", loc: GeneratedSource, - value: lowerExpressionToPlace(builder, body), + value: lowerExpressionToTemporary(builder, body), id: makeInstructionId(0), }; builder.terminateWithContinuation(terminal, fallthrough); @@ -169,7 +169,7 @@ function lowerStatement( switch (stmtNode.type) { case "ThrowStatement": { const stmt = stmtPath as NodePath; - const value = lowerExpressionToPlace(builder, stmt.get("argument")); + const value = lowerExpressionToTemporary(builder, stmt.get("argument")); const terminal: ThrowTerminal = { kind: "throw", value, @@ -183,7 +183,10 @@ function lowerStatement( const argument = stmt.get("argument"); const value = argument.node != null - ? lowerExpressionToPlace(builder, argument as NodePath) + ? lowerExpressionToTemporary( + builder, + argument as NodePath + ) : null; const terminal: ReturnTerminal = { kind: "return", @@ -225,7 +228,7 @@ function lowerStatement( // If there is no else clause, use the continuation directly alternateBlock = continuationBlock.id; } - const test = lowerExpressionToPlace(builder, stmt.get("test")); + const test = lowerExpressionToTemporary(builder, stmt.get("test")); const terminal: IfTerminal = { kind: "if", test, @@ -353,7 +356,7 @@ function lowerStatement( builder.terminateWithContinuation( { kind: "branch", - test: lowerExpressionToPlace( + test: lowerExpressionToTemporary( builder, test as NodePath ), @@ -409,7 +412,7 @@ function lowerStatement( * The conditional block is empty and exists solely as conditional for * (re)entering or exiting the loop */ - const test = lowerExpressionToPlace(builder, stmt.get("test")); + const test = lowerExpressionToTemporary(builder, stmt.get("test")); const terminal: BranchTerminal = { kind: "branch", test, @@ -525,7 +528,7 @@ function lowerStatement( }); } } - test = lowerExpressionToPlace( + test = lowerExpressionToTemporary( builder, testExpr as NodePath ); @@ -549,7 +552,10 @@ function lowerStatement( cases.push({ test: null, block: continuationBlock.id }); } - const test = lowerExpressionToPlace(builder, stmt.get("discriminant")); + const test = lowerExpressionToTemporary( + builder, + stmt.get("discriminant") + ); builder.terminateWithContinuation( { kind: "switch", @@ -772,7 +778,7 @@ function lowerExpression( hasError = true; continue; } - const value = lowerExpressionToPlace(builder, valuePath); + const value = lowerExpressionToTemporary(builder, valuePath); properties.set(key.name, value); } return hasError @@ -798,7 +804,7 @@ function lowerExpression( continue; } elements.push( - lowerExpressionToPlace(builder, element as NodePath) + lowerExpressionToTemporary(builder, element as NodePath) ); } return hasError @@ -820,7 +826,7 @@ function lowerExpression( }); return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc }; } - const callee = lowerExpressionToPlace(builder, calleePath); + const callee = lowerExpressionToTemporary(builder, calleePath); let args: Place[] = []; let hasError = false; for (const argPath of expr.get("arguments")) { @@ -833,7 +839,7 @@ function lowerExpression( hasError = true; continue; } - args.push(lowerExpressionToPlace(builder, argPath)); + args.push(lowerExpressionToTemporary(builder, argPath)); } return hasError @@ -873,7 +879,7 @@ function lowerExpression( hasError = true; continue; } - args.push(lowerExpressionToPlace(builder, argPath)); + args.push(lowerExpressionToTemporary(builder, argPath)); } if (typeof property === "string") { return { @@ -893,7 +899,7 @@ function lowerExpression( }; } } else { - const callee = lowerExpressionToPlace(builder, calleePath); + const callee = lowerExpressionToTemporary(builder, calleePath); let args: Place[] = []; for (const argPath of expr.get("arguments")) { if (!argPath.isExpression()) { @@ -905,7 +911,7 @@ function lowerExpression( hasError = true; continue; } - args.push(lowerExpressionToPlace(builder, argPath)); + args.push(lowerExpressionToTemporary(builder, argPath)); } return hasError ? { kind: "UnsupportedNode", node: exprNode, loc: exprLoc } @@ -928,8 +934,8 @@ function lowerExpression( }); return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc }; } - const left = lowerExpressionToPlace(builder, leftPath); - const right = lowerExpressionToPlace(builder, expr.get("right")); + const left = lowerExpressionToTemporary(builder, leftPath); + const right = lowerExpressionToTemporary(builder, expr.get("right")); const operator = expr.node.operator; return { kind: "BinaryExpression", @@ -945,7 +951,7 @@ function lowerExpression( let last: Place | null = null; for (const item of expr.get("expressions")) { - last = lowerExpressionToPlace(builder, item); + last = lowerExpressionToTemporary(builder, item); } if (last === null) { builder.errors.push({ @@ -971,7 +977,7 @@ function lowerExpression( builder.push({ id: makeInstructionId(0), lvalue: { kind: InstructionKind.Reassign, place: { ...place } }, - value: lowerExpressionToPlace(builder, expr.get("consequent")), + value: lowerExpressionToTemporary(builder, expr.get("consequent")), loc: exprLoc, }); return { @@ -986,7 +992,7 @@ function lowerExpression( builder.push({ id: makeInstructionId(0), lvalue: { kind: InstructionKind.Reassign, place: { ...place } }, - value: lowerExpressionToPlace(builder, expr.get("alternate")), + value: lowerExpressionToTemporary(builder, expr.get("alternate")), loc: exprLoc, }); return { @@ -1007,7 +1013,7 @@ function lowerExpression( }, testBlock ); - const testPlace = lowerExpressionToPlace(builder, expr.get("test")); + const testPlace = lowerExpressionToTemporary(builder, expr.get("test")); builder.terminateWithContinuation( { kind: "branch", @@ -1048,7 +1054,7 @@ function lowerExpression( builder.push({ id: makeInstructionId(0), lvalue: { kind: InstructionKind.Reassign, place: { ...place } }, - value: lowerExpressionToPlace(builder, expr.get("right")), + value: lowerExpressionToTemporary(builder, expr.get("right")), loc: exprLoc, }); return { @@ -1072,7 +1078,7 @@ function lowerExpression( builder.push({ id: makeInstructionId(0), lvalue: { kind: InstructionKind.Reassign, place: { ...leftPlace } }, - value: lowerExpressionToPlace(builder, expr.get("left")), + value: lowerExpressionToTemporary(builder, expr.get("left")), loc: exprLoc, }); builder.terminateWithContinuation( @@ -1093,7 +1099,7 @@ function lowerExpression( if (builder.currentBlockKind() === "value") { // try lowering the RHS in case it also contains errors - lowerExpressionToPlace(builder, expr.get("right")); + lowerExpressionToTemporary(builder, expr.get("right")); builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle AssignmentExpression within a LogicalExpression or ConditionalExpression`, severity: ErrorSeverity.Todo, @@ -1109,7 +1115,8 @@ function lowerExpression( left.node.loc ?? GeneratedSource, InstructionKind.Reassign, left, - lowerExpression(builder, expr.get("right")) + // NOTE: it's okay not to lower to a temporary here because this is the entire RHS value, not a single operand + lowerExpressionToPlace(builder, expr.get("right")) ); } @@ -1130,7 +1137,7 @@ function lowerExpression( const binaryOperator = operators[operator]; if (binaryOperator == null) { builder.errors.push({ - reason: `(BuildHIR::lowerExpression) Handle ${operator} operaators in AssignmentExpression`, + reason: `(BuildHIR::lowerExpression) Handle ${operator} operators in AssignmentExpression`, severity: ErrorSeverity.Todo, nodePath: expr.get("operator"), }); @@ -1141,8 +1148,8 @@ function lowerExpression( switch (leftNode.type) { case "Identifier": { const leftExpr = left as NodePath; - const place = lowerExpressionToPlace(builder, leftExpr); - const right = lowerExpressionToPlace(builder, expr.get("right")); + const place = lowerIdentifier(builder, leftExpr); + const right = lowerExpressionToTemporary(builder, expr.get("right")); builder.push({ id: makeInstructionId(0), lvalue: { place: { ...place }, kind: InstructionKind.Reassign }, @@ -1191,7 +1198,7 @@ function lowerExpression( kind: "BinaryExpression", operator: binaryOperator, left: { ...previousValuePlace }, - right: lowerExpressionToPlace(builder, expr.get("right")), + right: lowerExpressionToTemporary(builder, expr.get("right")), loc: leftExpr.node.loc ?? GeneratedSource, }, loc: leftExpr.node.loc ?? GeneratedSource, @@ -1252,7 +1259,7 @@ function lowerExpression( let hasError = false; for (const attribute of opening.get("attributes")) { if (attribute.isJSXSpreadAttribute()) { - const argument = lowerExpressionToPlace( + const argument = lowerExpressionToTemporary( builder, attribute.get("argument") ); @@ -1281,7 +1288,7 @@ function lowerExpression( const valueExpr = attribute.get("value"); let value; if (valueExpr.isJSXElement() || valueExpr.isStringLiteral()) { - value = lowerExpressionToPlace(builder, valueExpr); + value = lowerExpressionToTemporary(builder, valueExpr); } else { if (!valueExpr.isJSXExpressionContainer()) { builder.errors.push({ @@ -1302,7 +1309,7 @@ function lowerExpression( hasError = true; continue; } - value = lowerExpressionToPlace(builder, expression); + value = lowerExpressionToTemporary(builder, expression); } const prop: string = name.node.name; props.push({ kind: "JsxAttribute", name: prop, place: value }); @@ -1402,7 +1409,7 @@ function lowerExpression( return { kind: "TaggedTemplateExpression", - tag: lowerExpressionToPlace(builder, expr.get("tag")), + tag: lowerExpressionToTemporary(builder, expr.get("tag")), value, loc: exprLoc, }; @@ -1431,7 +1438,7 @@ function lowerExpression( } const subexprPlaces = subexprs.map((e) => - lowerExpressionToPlace(builder, e as NodePath) + lowerExpressionToTemporary(builder, e as NodePath) ); return { @@ -1446,7 +1453,7 @@ function lowerExpression( return { kind: "UnaryExpression", operator: expr.node.operator, - value: lowerExpressionToPlace(builder, expr.get("argument")), + value: lowerExpressionToTemporary(builder, expr.get("argument")), loc: exprLoc, }; } @@ -1454,7 +1461,7 @@ function lowerExpression( let expr = exprPath as NodePath; return { kind: "TypeCastExpression", - value: lowerExpressionToPlace(builder, expr.get("expression")), + value: lowerExpressionToTemporary(builder, expr.get("expression")), type: expr.get("typeAnnotation").node, loc: exprLoc, }; @@ -1493,7 +1500,7 @@ function lowerExpression( loc: expr.node.loc ?? GeneratedSource, }); const identifier = argument as NodePath; - const place = lowerExpressionToPlace(builder, identifier); + const place = lowerIdentifier(builder, identifier); builder.push({ id: makeInstructionId(0), lvalue: { place: { ...place }, kind: InstructionKind.Reassign }, @@ -1525,7 +1532,7 @@ function lowerMemberExpression( ): { object: Place; property: Place | string; value: InstructionValue } { const exprNode = expr.node; const exprLoc = exprNode.loc ?? GeneratedSource; - const object = lowerExpressionToPlace(builder, expr.get("object")); + const object = lowerExpressionToTemporary(builder, expr.get("object")); const property = expr.get("property"); if (!expr.node.computed) { if (!property.isIdentifier()) { @@ -1565,7 +1572,7 @@ function lowerMemberExpression( }, }; } - const propertyPlace = lowerExpressionToPlace(builder, property); + const propertyPlace = lowerExpressionToTemporary(builder, property); const value: InstructionValue = { kind: "ComputedLoad", object: { ...object }, @@ -1635,7 +1642,7 @@ function lowerJsxElement( const exprNode = exprPath.node; const exprLoc = exprNode.loc ?? GeneratedSource; if (exprPath.isJSXElement() || exprPath.isJSXFragment()) { - return lowerExpressionToPlace(builder, exprPath); + return lowerExpressionToTemporary(builder, exprPath); } else if (exprPath.isJSXExpressionContainer()) { const expression = exprPath.get("expression"); if (!expression.isExpression()) { @@ -1657,7 +1664,7 @@ function lowerJsxElement( }); return { ...place }; } - return lowerExpressionToPlace(builder, expression); + return lowerExpressionToTemporary(builder, expression); } else if (exprPath.isJSXText()) { const place: Place = buildTemporaryPlace(builder, exprLoc); builder.push({ @@ -1694,19 +1701,38 @@ function lowerJsxElement( } } -function lowerExpressionToPlace( +function lowerExpressionToTemporary( builder: HIRBuilder, exprPath: NodePath ): Place { - const instr = lowerExpression(builder, exprPath); - if (instr.kind === "Identifier") { - return instr; + const value = lowerExpression(builder, exprPath); + if (value.kind === "Identifier" && value.identifier.name === null) { + return value; } const exprLoc = exprPath.node.loc ?? GeneratedSource; const place: Place = buildTemporaryPlace(builder, exprLoc); builder.push({ id: makeInstructionId(0), - value: instr, + value: value, + loc: exprLoc, + lvalue: { place: { ...place }, kind: InstructionKind.Const }, + }); + return place; +} + +function lowerExpressionToPlace( + builder: HIRBuilder, + exprPath: NodePath +): Place { + const value = lowerExpression(builder, exprPath); + if (value.kind === "Identifier") { + return value; + } + const exprLoc = exprPath.node.loc ?? GeneratedSource; + const place: Place = buildTemporaryPlace(builder, exprLoc); + builder.push({ + id: makeInstructionId(0), + value: value, loc: exprLoc, lvalue: { place: { ...place }, kind: InstructionKind.Const }, }); @@ -1837,7 +1863,7 @@ function lowerAssignment( case "MemberExpression": { const lvalue = lvaluePath as NodePath; const property = lvalue.get("property"); - const object = lowerExpressionToPlace(builder, lvalue.get("object")); + const object = lowerExpressionToTemporary(builder, lvalue.get("object")); let valuePlace: Place; if (value.kind === "Identifier") { valuePlace = value; @@ -1876,7 +1902,7 @@ function lowerAssignment( }); return { kind: "UnsupportedNode", node: lvalueNode, loc }; } - const propertyPlace = lowerExpressionToPlace(builder, property); + const propertyPlace = lowerExpressionToTemporary(builder, property); return { kind: "ComputedStore", object, @@ -2056,7 +2082,7 @@ function gatherCapturedDeps( path.skip(); capturedIds.add(binding.identifier); - capturedRefs.add(lowerExpressionToPlace(builder, path)); + capturedRefs.add(lowerExpressionToTemporary(builder, path)); }, }); diff --git a/compiler/forget/src/Inference/AnalyseFunctions.ts b/compiler/forget/src/Inference/AnalyseFunctions.ts index 692ce782c7..b4659570b5 100644 --- a/compiler/forget/src/Inference/AnalyseFunctions.ts +++ b/compiler/forget/src/Inference/AnalyseFunctions.ts @@ -1,11 +1,12 @@ import invariant from "invariant"; import { - HIRFunction, + Effect, FunctionExpression, + HIRFunction, Identifier, mergeConsecutiveBlocks, Place, - Effect, + ReactiveScopeDependency, } from "../HIR"; import { constantPropagation } from "../Optimization"; import { eliminateRedundantPhi, enterSSA } from "../SSA"; @@ -14,48 +15,58 @@ import { logHIRFunction } from "../Utils/logger"; import { inferMutableRanges } from "./InferMutableRanges"; import inferReferenceEffects from "./InferReferenceEffects"; -type Dependency = { - place: Place; - path: Array | null; -}; +class State { + properties: Map = new Map(); -function declareProperty( - properties: Map, - lvalue: Place, - object: Place, - property: string -): void { - const objectDependency = properties.get(object.identifier); - let nextDependency: Dependency; - if (objectDependency === undefined) { - nextDependency = { place: object, path: [property] }; - } else { - nextDependency = { - place: objectDependency.place, - path: [...(objectDependency.path ?? []), property], + declareProperty(lvalue: Place, object: Place, property: string): void { + const objectDependency = this.properties.get(object.identifier); + let nextDependency: ReactiveScopeDependency; + if (objectDependency === undefined) { + nextDependency = { place: object, path: [property] }; + } else { + nextDependency = { + place: objectDependency.place, + path: [...(objectDependency.path ?? []), property], + }; + } + this.properties.set(lvalue.identifier, nextDependency); + } + + declareTemporary(lvalue: Place, value: Place): void { + const resolved: ReactiveScopeDependency = this.properties.get( + value.identifier + ) ?? { + place: value, + path: null, }; + this.properties.set(lvalue.identifier, resolved); } - properties.set(lvalue.identifier, nextDependency); } export default function analyseFunctions(func: HIRFunction) { - const properties: Map = new Map(); + const state = new State(); for (const [_, block] of func.body.blocks) { for (const instr of block.instructions) { switch (instr.value.kind) { case "FunctionExpression": { lower(instr.value.loweredFunc); - infer(instr.value, properties, func.context); + infer(instr.value, state, func.context); break; } case "PropertyLoad": { - declareProperty( - properties, + state.declareProperty( instr.lvalue.place, instr.value.object, instr.value.property ); + break; + } + case "Identifier": { + if (instr.lvalue.place.identifier.name === null) { + state.declareTemporary(instr.lvalue.place, instr.value); + } + break; } } } @@ -74,11 +85,7 @@ function lower(func: HIRFunction) { logHIRFunction("AnalyseFunction (inner)", func); } -function infer( - value: FunctionExpression, - properties: Map, - context: Place[] -) { +function infer(value: FunctionExpression, state: State, context: Place[]) { const mutations = new Set( value.loweredFunc.context .filter((dep) => isMutated(dep.identifier)) @@ -89,8 +96,8 @@ function infer( for (const dep of value.dependencies) { let name: string | null = null; - if (properties.has(dep.identifier)) { - const receiver = properties.get(dep.identifier)!; + if (state.properties.has(dep.identifier)) { + const receiver = state.properties.get(dep.identifier)!; name = receiver.place.identifier.name; } else { name = dep.identifier.name; diff --git a/compiler/forget/src/Inference/InferAliasForStores.ts b/compiler/forget/src/Inference/InferAliasForStores.ts index cbdef18866..c36b11ee58 100644 --- a/compiler/forget/src/Inference/InferAliasForStores.ts +++ b/compiler/forget/src/Inference/InferAliasForStores.ts @@ -11,7 +11,6 @@ import { InstructionId, Place, } from "../HIR/HIR"; -import { printInstructionValue } from "../HIR/PrintHIR"; import { eachInstructionValueOperand } from "../HIR/visitors"; import DisjointSet from "../Utils/DisjointSet"; @@ -25,30 +24,12 @@ export function inferAliasForStores( if (lvalue.place.effect !== Effect.Store) { continue; } - switch (value.kind) { - case "ArrayExpression": - case "ObjectExpression": - case "ComputedStore": - case "PropertyStore": - case "FunctionExpression": { - for (const operand of eachInstructionValueOperand(value)) { - if ( - operand.effect === Effect.Capture || - operand.effect === Effect.Store - ) { - maybeAlias(aliases, lvalue.place, operand, instr.id); - } - } - break; - } - default: { - // Effect.Capture & Effect.Store are only used for aliasing - // instructions. - throw new Error( - `Unexpected capture/store instruction: ${printInstructionValue( - value - )}` - ); + for (const operand of eachInstructionValueOperand(value)) { + if ( + operand.effect === Effect.Capture || + operand.effect === Effect.Store + ) { + maybeAlias(aliases, lvalue.place, operand, instr.id); } } } diff --git a/compiler/forget/src/Inference/InferMutableRanges.ts b/compiler/forget/src/Inference/InferMutableRanges.ts index 1f48dde39d..0253fe2845 100644 --- a/compiler/forget/src/Inference/InferMutableRanges.ts +++ b/compiler/forget/src/Inference/InferMutableRanges.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { HIRFunction } from "../HIR/HIR"; +import { HIRFunction, Identifier } from "../HIR/HIR"; import { inferAliases } from "./InferAlias"; import { inferAliasForStores } from "./InferAliasForStores"; import { inferMutableLifetimes } from "./InferMutableLifetimes"; @@ -17,18 +17,22 @@ export function inferMutableRanges(ir: HIRFunction) { // Calculate aliases const aliases = inferAliases(ir); - let size = aliases.size; // Eagerly canonicalize so that if nothing changes we can bail out // after a single iteration - aliases.canonicalize(); - do { - size = aliases.size; + let prevAliases: Map = aliases.canonicalize(); + while (true) { // Infer mutable ranges for aliases that are not fields inferMutableRangesForAlias(ir, aliases); // Update aliasing information of fields inferAliasForStores(ir, aliases); - } while (aliases.size > size || !aliases.canonicalize()); + + const nextAliases = aliases.canonicalize(); + if (areEqualMaps(prevAliases, nextAliases)) { + break; + } + prevAliases = nextAliases; + } // Re-infer mutable ranges for all values inferMutableLifetimes(ir, true); @@ -36,3 +40,18 @@ export function inferMutableRanges(ir: HIRFunction) { // Re-infer mutable ranges for aliases inferMutableRangesForAlias(ir, aliases); } + +function areEqualMaps(a: Map, b: Map): boolean { + if (a.size !== b.size) { + return false; + } + for (const [key, value] of a) { + if (!b.has(key)) { + return false; + } + if (b.get(key) !== value) { + return false; + } + } + return true; +} diff --git a/compiler/forget/src/Inference/InferMutableRangesForAlias.ts b/compiler/forget/src/Inference/InferMutableRangesForAlias.ts index 9a8edfb17d..95b96c8ef7 100644 --- a/compiler/forget/src/Inference/InferMutableRangesForAlias.ts +++ b/compiler/forget/src/Inference/InferMutableRangesForAlias.ts @@ -5,19 +5,6 @@ export function inferMutableRangesForAlias( fn: HIRFunction, aliases: DisjointSet ) { - for (const [_, block] of fn.body.blocks) { - for (const phi of block.phis) { - const isPhiMutatedAfterCreation: boolean = - phi.id.mutableRange.end > - (block.instructions.at(0)?.id ?? block.terminal.id); - if (isPhiMutatedAfterCreation) { - for (const [, operand] of phi.operands) { - aliases.union([phi.id, operand]); - } - } - } - } - const aliasSets = aliases.buildSets(); for (const aliasSet of aliasSets) { // Update mutableRange.end only if the identifiers have actually been @@ -44,4 +31,17 @@ export function inferMutableRangesForAlias( } } } + + for (const [_, block] of fn.body.blocks) { + for (const phi of block.phis) { + const isPhiMutatedAfterCreation: boolean = + phi.id.mutableRange.end > + (block.instructions.at(0)?.id ?? block.terminal.id); + if (isPhiMutatedAfterCreation) { + for (const [, operand] of phi.operands) { + aliases.union([phi.id, operand]); + } + } + } + } } diff --git a/compiler/forget/src/ReactiveScopes/InferReactiveIdentifiers.ts b/compiler/forget/src/ReactiveScopes/InferReactiveIdentifiers.ts index 471950993f..b51e11a1f8 100644 --- a/compiler/forget/src/ReactiveScopes/InferReactiveIdentifiers.ts +++ b/compiler/forget/src/ReactiveScopes/InferReactiveIdentifiers.ts @@ -28,18 +28,20 @@ class Visitor extends ReactiveFunctionVisitor { ) { this.traverseInstruction(instr, reactivityMap); const lval = instr.lvalue; - if (lval == null || reactivityMap.get(lval.place.identifier.id) === true) { + if (lval == null) { return; } const { value } = instr; - let hasReactiveInput = false; - for (const operand of eachReactiveValueOperand(value)) { - // We currently treat free variables (from module or global scope) as - // non-reactive. We may later want type information about specific - // free variables, or a toggle `treatFreeVarsAsReactive`. - if (reactivityMap.get(operand.identifier.id)) { - hasReactiveInput = true; - break; + let hasReactiveInput = reactivityMap.get(lval.place.identifier.id) === true; + if (!hasReactiveInput && value.kind !== "LoadGlobal") { + for (const operand of eachReactiveValueOperand(value)) { + // We currently treat free variables (from module or global scope) as + // non-reactive. We may later want type information about specific + // free variables, or a toggle `treatFreeVarsAsReactive`. + if (reactivityMap.get(operand.identifier.id)) { + hasReactiveInput = true; + break; + } } } if ( @@ -136,7 +138,11 @@ export function inferReactiveIdentifiers( for (const param of fn.params) { reactivityMap.set(param.identifier.id, true); } - visitReactiveFunction(fn, visitor, reactivityMap); + let size: number; + do { + size = reactivityMap.size; + visitReactiveFunction(fn, visitor, reactivityMap); + } while (reactivityMap.size > size); const result = new Set(); reactivityMap.forEach((isReactive, id) => { diff --git a/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts index d4b9af87d7..eddad56535 100644 --- a/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -71,6 +71,7 @@ class Context { // This helps with.. temporaries that are created only for property loads // but can be generalized to all non-allocating temporaries #properties: Map = new Map(); + #temporaries: Map = new Map(); #scopes: Scopes = []; enter(scope: ReactiveScope, fn: () => void): Set { @@ -97,11 +98,16 @@ class Context { this.#reassignments.set(identifier, decl); } + declareTemporary(lvalue: Place, value: Place): void { + this.#temporaries.set(lvalue.identifier, value); + } + declareProperty(lvalue: Place, object: Place, property: string): void { - const objectDependency = this.#properties.get(object.identifier); + const resolvedObject = this.#temporaries.get(object.identifier) ?? object; + const objectDependency = this.#properties.get(resolvedObject.identifier); let nextDependency: ReactiveScopeDependency; if (objectDependency === undefined) { - nextDependency = { place: object, path: [property] }; + nextDependency = { place: resolvedObject, path: [property] }; } else { nextDependency = { place: objectDependency.place, @@ -120,14 +126,16 @@ class Context { } visitOperand(place: Place): void { - this.visitDependency({ place, path: null }); + const resolved = this.#temporaries.get(place.identifier) ?? place; + this.visitDependency({ place: resolved, path: null }); } visitProperty(object: Place, property: string): void { - const objectDependency = this.#properties.get(object.identifier); + const resolvedObject = this.#temporaries.get(object.identifier) ?? object; + const objectDependency = this.#properties.get(resolvedObject.identifier); let nextDependency: ReactiveScopeDependency; if (objectDependency === undefined) { - nextDependency = { place: object, path: [property] }; + nextDependency = { place: resolvedObject, path: [property] }; } else { nextDependency = { place: objectDependency.place, @@ -362,7 +370,16 @@ function visitInstructionValue( value: ReactiveValue, lvalue: LValue | null ): void { - if (value.kind === "PropertyLoad") { + if (value.kind === "Identifier" && lvalue !== null) { + if ( + value.identifier.name !== null && + lvalue.place.identifier.name === null + ) { + context.declareTemporary(lvalue.place, value); + } else { + context.visitOperand(value); + } + } else if (value.kind === "PropertyLoad") { if (lvalue !== null) { context.declareProperty(lvalue.place, value.object, value.property); } else { diff --git a/compiler/forget/src/Utils/DisjointSet.ts b/compiler/forget/src/Utils/DisjointSet.ts index c392b6e9d4..3f66105a77 100644 --- a/compiler/forget/src/Utils/DisjointSet.ts +++ b/compiler/forget/src/Utils/DisjointSet.ts @@ -75,19 +75,16 @@ export default class DisjointSet { /** * Forces the set into canonical form, ie with all items pointing directly to - * their root. Returns true if the set was already in canonical form, false - * otherwise. + * their root, and returns a Map representing the mapping of items to their roots. */ - canonicalize(): boolean { - let isCanonical = true; + canonicalize(): Map { + const entries = new Map(); for (const item of this.#entries.keys()) { const parent = this.#entries.get(item)!; - const root = this.find(item); - if (parent !== root) { - isCanonical = false; - } + const root = this.find(item)!; + entries.set(item, root); } - return isCanonical; + return entries; } /** diff --git a/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-func-simple-alias.expect.md b/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-func-simple-alias.expect.md index 6a84a90a06..8de657bb48 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-func-simple-alias.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/_bug.capturing-func-simple-alias.expect.md @@ -28,12 +28,12 @@ function component(a) { } else { x = $[1]; } - const y = undefined; + (function () { y = x; })(); - mutate(y); - return y; + mutate(undefined); + return undefined; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/_bug_expression-with-assignment.js b/compiler/forget/src/__tests__/fixtures/hir/_bug_expression-with-assignment.js deleted file mode 100644 index 49ae886dad..0000000000 --- a/compiler/forget/src/__tests__/fixtures/hir/_bug_expression-with-assignment.js +++ /dev/null @@ -1,6 +0,0 @@ -function f() { - let x = 1; - // BUG: `x` has different values within this expression. Currently, the - // assignment is evaluated too early. - return x + (x = 2) + x; -} diff --git a/compiler/forget/src/__tests__/fixtures/hir/assignment-expression-computed.expect.md b/compiler/forget/src/__tests__/fixtures/hir/assignment-expression-computed.expect.md index 62cadca01c..5207533242 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/assignment-expression-computed.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/assignment-expression-computed.expect.md @@ -21,10 +21,11 @@ function Component(props) { let x; if (c_0) { x = [props.x]; - const index = 0; - x[index] = x[index] * 2; - const t0 = "0"; - x[t0] = x[t0] + 3; + + const t0 = 0; + x[t0] = x[t0] * 2; + const t1 = "0"; + x[t1] = x[t1] + 3; $[0] = props.x; $[1] = x; } else { diff --git a/compiler/forget/src/__tests__/fixtures/hir/assignment-in-nested-if.expect.md b/compiler/forget/src/__tests__/fixtures/hir/assignment-in-nested-if.expect.md index 4f1f37ae5c..5ee3cdac92 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/assignment-in-nested-if.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/assignment-in-nested-if.expect.md @@ -24,12 +24,14 @@ function useBar(props) { let z = undefined; if (props.a) { if (props.b) { + let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - z = baz(); - $[0] = z; + t0 = baz(); + $[0] = t0; } else { - z = $[0]; + t0 = $[0]; } + z = t0; } } return z; diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.expect.md index 4fd3f277d3..efaa1a7cae 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.expect.md @@ -4,7 +4,7 @@ ```javascript function component(a) { let x = { a }; - let y; + let y = {}; (function () { y["x"] = x; })(); @@ -23,16 +23,16 @@ function component(a) { let y; if (c_0) { const x = { a: a }; - y = undefined; + y = {}; (function () { y["x"] = x; })(); + mutate(y); $[0] = a; $[1] = y; } else { y = $[1]; } - mutate(y); return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.js index d3a669613b..f8a365a283 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.js +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-computed-mutate.js @@ -1,6 +1,6 @@ function component(a) { let x = { a }; - let y; + let y = {}; (function () { y["x"] = x; })(); diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.expect.md index abb653084f..00063417a4 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.expect.md @@ -4,7 +4,7 @@ ```javascript function component(a) { let x = { a }; - let y; + let y = {}; (function () { y.x = x; })(); @@ -23,16 +23,16 @@ function component(a) { let y; if (c_0) { const x = { a: a }; - y = undefined; + y = {}; (function () { y.x = x; })(); + mutate(y); $[0] = a; $[1] = y; } else { y = $[1]; } - mutate(y); return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.js index 6da8bf9d1a..8ea83e13bc 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.js +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-func-alias-mutate.js @@ -1,6 +1,6 @@ function component(a) { let x = { a }; - let y; + let y = {}; (function () { y.x = x; })(); 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 10adb826ba..73a1740d14 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 @@ -19,9 +19,9 @@ function component({ mutator }) { ## Code ```javascript -function component(t15) { +function component(t23) { const $ = React.unstable_useMemoCache(7); - const t0 = t15; + const t0 = t23; const mutator = t0.mutator; const c_0 = $[0] !== mutator; let poke; diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-function-within-block.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-function-within-block.expect.md index ebdfd83a0e..d60e6670e9 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/capturing-function-within-block.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-function-within-block.expect.md @@ -30,16 +30,17 @@ function component(a) { z = $[1]; } const c_2 = $[2] !== z; - let x; + let t0; if (c_2) { - x = function () { + t0 = function () { z; }; $[2] = z; - $[3] = x; + $[3] = t0; } else { - x = $[3]; + t0 = $[3]; } + const x = t0; return x; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/constant-propagation.expect.md b/compiler/forget/src/__tests__/fixtures/hir/constant-propagation.expect.md index 003a163e0e..e53300ae3a 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/constant-propagation.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/constant-propagation.expect.md @@ -28,9 +28,7 @@ function foo() { ```javascript function foo() { console.log("foo"); - - const j = -6; - return j; + return -6; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment-dynamic.expect.md b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment-dynamic.expect.md new file mode 100644 index 0000000000..c4f145c91f --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment-dynamic.expect.md @@ -0,0 +1,21 @@ + +## Input + +```javascript +function f(y) { + let x = y; + return x + (x = 2) + x; +} + +``` + +## Code + +```javascript +function f(y) { + const x = y; + return x + 2 + 2; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment-dynamic.js b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment-dynamic.js new file mode 100644 index 0000000000..e3a58967b4 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment-dynamic.js @@ -0,0 +1,4 @@ +function f(y) { + let x = y; + return x + (x = 2) + x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/_bug_expression-with-assignment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment.expect.md similarity index 52% rename from compiler/forget/src/__tests__/fixtures/hir/_bug_expression-with-assignment.expect.md rename to compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment.expect.md index 4d909a7040..0f4e095dd0 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/_bug_expression-with-assignment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment.expect.md @@ -4,8 +4,6 @@ ```javascript function f() { let x = 1; - // BUG: `x` has different values within this expression. Currently, the - // assignment is evaluated too early. return x + (x = 2) + x; } @@ -15,7 +13,7 @@ function f() { ```javascript function f() { - return 6; + return 5; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment.js b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment.js new file mode 100644 index 0000000000..5d4ec4c51b --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/expression-with-assignment.js @@ -0,0 +1,4 @@ +function f() { + let x = 1; + return x + (x = 2) + x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/hooks-freeze-possibly-mutable-arguments.expect.md b/compiler/forget/src/__tests__/fixtures/hir/hooks-freeze-possibly-mutable-arguments.expect.md index feec1ee910..77dbdb1337 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/hooks-freeze-possibly-mutable-arguments.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/hooks-freeze-possibly-mutable-arguments.expect.md @@ -33,12 +33,14 @@ function Component(props) { if (cond) { a = x; } else { + let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - a = []; - $[0] = a; + t0 = []; + $[0] = t0; } else { - a = $[0]; + t0 = $[0]; } + a = t0; } useFreeze(a); diff --git a/compiler/forget/src/__tests__/fixtures/hir/obj-literal-cached-in-if-else.expect.md b/compiler/forget/src/__tests__/fixtures/hir/obj-literal-cached-in-if-else.expect.md index c552f392d3..9a1877dcd6 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/obj-literal-cached-in-if-else.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/obj-literal-cached-in-if-else.expect.md @@ -23,22 +23,26 @@ function foo(a, b, c, d) { let x = undefined; if (someVal) { const c_0 = $[0] !== b; + let t0; if (c_0) { - x = { b: b }; + t0 = { b: b }; $[0] = b; - $[1] = x; + $[1] = t0; } else { - x = $[1]; + t0 = $[1]; } + x = t0; } else { const c_2 = $[2] !== c; + let t1; if (c_2) { - x = { c: c }; + t1 = { c: c }; $[2] = c; - $[3] = x; + $[3] = t1; } else { - x = $[3]; + t1 = $[3]; } + x = t1; } return x; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/object-pattern-params.expect.md b/compiler/forget/src/__tests__/fixtures/hir/object-pattern-params.expect.md index 1013fcd7b6..c0a8ec7d70 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/object-pattern-params.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/object-pattern-params.expect.md @@ -13,10 +13,10 @@ function component({ a, b }) { ## Code ```javascript -function component(t8) { +function component(t12) { const $ = React.unstable_useMemoCache(7); - const a = t8.a; - const b = t8.b; + const a = t12.a; + const b = t12.b; const c_0 = $[0] !== a; let y; if (c_0) { 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 e9514dd4a5..c7552085ba 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md @@ -36,27 +36,29 @@ function Component(props) { } const y = x; if (props.p1) { + let t0; if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - x = []; - $[2] = x; + t0 = []; + $[2] = t0; } else { - x = $[2]; + t0 = $[2]; } + x = t0; } y.push(props.p2); const c_3 = $[3] !== x; const c_4 = $[4] !== y; - let t0; + let t1; if (c_3 || c_4) { - t0 = ; + t1 = ; $[3] = x; $[4] = y; - $[5] = t0; + $[5] = t1; } else { - t0 = $[5]; + t1 = $[5]; } - return t0; + return t1; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md index f3d722749e..0b3212b74d 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md @@ -30,12 +30,14 @@ function Component(props) { x = []; x.push(props.p0); y = x; + let t0; if ($[4] === Symbol.for("react.memo_cache_sentinel")) { - x = []; - $[4] = x; + t0 = []; + $[4] = t0; } else { - x = $[4]; + t0 = $[4]; } + x = t0; y.push(props.p1); $[0] = props.p0; @@ -48,16 +50,16 @@ function Component(props) { } const c_5 = $[5] !== x; const c_6 = $[6] !== y; - let t0; + let t1; if (c_5 || c_6) { - t0 = ; + t1 = ; $[5] = x; $[6] = y; - $[7] = t0; + $[7] = t1; } else { - t0 = $[7]; + t1 = $[7]; } - return t0; + return t1; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/sequence-expression.expect.md b/compiler/forget/src/__tests__/fixtures/hir/sequence-expression.expect.md index 83f5f1b7b2..dfbf5abb7f 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/sequence-expression.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/sequence-expression.expect.md @@ -18,18 +18,25 @@ function foo() {} ```javascript function sequence(props) { - const $ = React.unstable_useMemoCache(1); + const $ = React.unstable_useMemoCache(2); Math.max(1, 2); - let x; + let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x = foo(); + t0 = foo(); + $[0] = t0; + } else { + t0 = $[0]; + } + let x; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + x = t0; while ((foo(), true)) { foo(); x = 2; } - $[0] = x; + $[1] = x; } else { - x = $[0]; + x = $[1]; } return x; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-arrayexpression.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-arrayexpression.expect.md index b953dd4fb3..fc50027b02 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-arrayexpression.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-arrayexpression.expect.md @@ -16,11 +16,9 @@ function Component(props) { ```javascript function Component(props) { const $ = React.unstable_useMemoCache(1); - const a = 1; - const b = 2; let x; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x = [a, b]; + x = [1, 2]; $[0] = x; } else { x = $[0]; diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-nested-loops-no-reassign.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-nested-loops-no-reassign.expect.md index 8ec987a29f..4193df4b1f 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-nested-loops-no-reassign.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-nested-loops-no-reassign.expect.md @@ -22,13 +22,12 @@ function foo(a, b, c) { ```javascript // @xonly function foo(a, b, c) { - const x = 0; while (a) { while (b) { while (c) {} } } - return x; + return 0; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-objectexpression.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-objectexpression.expect.md index ef6b34dc35..7d3b670978 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-objectexpression.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-objectexpression.expect.md @@ -16,11 +16,9 @@ function Component(props) { ```javascript function Component(props) { const $ = React.unstable_useMemoCache(1); - const a = 1; - const b = 2; let x; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x = { a: a, b: b }; + x = { a: 1, b: 2 }; $[0] = x; } else { x = $[0]; diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-shadowing.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-shadowing.expect.md index 0d979655dd..f486304ece 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-shadowing.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-shadowing.expect.md @@ -25,8 +25,7 @@ function log() {} function Foo(cond) { let str = ""; if (cond) { - const str_0 = "other test"; - log(str_0); + log("other test"); } else { str = "fallthrough test"; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-switch.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-switch.expect.md index a1beb758ee..77c8a658e9 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-switch.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-switch.expect.md @@ -28,8 +28,7 @@ function foo() { ```javascript function foo() { - const x = 1; - bb1: switch (x) { + bb1: switch (1) { case 1: { break bb1; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md index 8ec206869f..8a7807a4a5 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md @@ -17,9 +17,8 @@ function foo() { ```javascript function foo() { - const x = 1; while (true) {} - return x; + return 1; } ``` 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 f451be0992..cad7c3388a 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 @@ -46,12 +46,14 @@ function Component(props) { } case true: { x.push(props.p2); + let t0; if ($[4] === Symbol.for("react.memo_cache_sentinel")) { - y = []; - $[4] = y; + t0 = []; + $[4] = t0; } else { - y = $[4]; + t0 = $[4]; } + y = t0; break bb1; } default: { @@ -81,16 +83,16 @@ function Component(props) { y.push(props.p4); const c_7 = $[7] !== y; const c_8 = $[8] !== child; - let t0; + let t1; if (c_7 || c_8) { - t0 = {child}; + t1 = {child}; $[7] = y; $[8] = child; - $[9] = t0; + $[9] = t1; } else { - t0 = $[9]; + t1 = $[9]; } - return t0; + return t1; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/type-test-primitive.expect.md b/compiler/forget/src/__tests__/fixtures/hir/type-test-primitive.expect.md index c94e6e4dc5..9b0cb3b544 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/type-test-primitive.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/type-test-primitive.expect.md @@ -15,8 +15,7 @@ function component() { ```javascript function component() { - const y = 2; - return y; + return 2; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md b/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md index 46200d32a1..417f1362ea 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md @@ -17,8 +17,7 @@ function foo(a) { ```javascript function foo(a) { - const x = 1; - return a + x; + return a + 1; } ```