mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[valueblocks] Convert logical terminal to ReactiveValue
Implements the conversion from LogicalTerminal into a ReactiveLogicalValue (and ReactiveSequenveValue if necessary). The implementation is a bit rough, i clean it up in subsequent PRs which revealed parts of the logic that could be shared w ternaries.
This commit is contained in:
@@ -93,7 +93,10 @@ export type ReactiveInstruction = {
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type ReactiveValue = InstructionValue | ReactiveLogicalValue;
|
||||
export type ReactiveValue =
|
||||
| InstructionValue
|
||||
| ReactiveLogicalValue
|
||||
| ReactiveSequenceValue;
|
||||
|
||||
export type ReactiveLogicalValue = {
|
||||
kind: "LogicalExpression";
|
||||
@@ -103,6 +106,13 @@ export type ReactiveLogicalValue = {
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type ReactiveSequenceValue = {
|
||||
kind: "SequenceExpression";
|
||||
instructions: Array<ReactiveInstruction>;
|
||||
value: ReactiveValue;
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type ReactiveTerminal =
|
||||
| ReactiveBreakTerminal
|
||||
| ReactiveContinueTerminal
|
||||
|
||||
@@ -339,6 +339,16 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
|
||||
} ${printInstructionValue(instrValue.right)}`;
|
||||
break;
|
||||
}
|
||||
case "SequenceExpression": {
|
||||
value = [
|
||||
`Sequence`,
|
||||
...instrValue.instructions.map(
|
||||
(instr) => ` ${printInstruction(instr)}`
|
||||
),
|
||||
` ${printInstructionValue(instrValue.value)}`,
|
||||
].join("\n");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(
|
||||
instrValue,
|
||||
|
||||
@@ -19,11 +19,24 @@ import {
|
||||
} from "../HIR";
|
||||
import {
|
||||
HIRFunction,
|
||||
Instruction,
|
||||
InstructionKind,
|
||||
ReactiveBreakTerminal,
|
||||
ReactiveContinueTerminal,
|
||||
ReactiveFunction,
|
||||
ReactiveInstruction,
|
||||
ReactiveLogicalValue,
|
||||
ReactiveSequenceValue,
|
||||
ReactiveTerminalStatement,
|
||||
ReactiveValue,
|
||||
Terminal,
|
||||
} from "../HIR/HIR";
|
||||
import {
|
||||
printInstructionValue,
|
||||
printPlace,
|
||||
printTerminal,
|
||||
} from "../HIR/PrintHIR";
|
||||
import { mapInstructionOperands } from "../HIR/visitors";
|
||||
import { assertExhaustive } from "../Utils/utils";
|
||||
|
||||
/**
|
||||
@@ -407,7 +420,16 @@ class Driver {
|
||||
const scheduleId = this.cx.schedule(fallthroughId, "if");
|
||||
scheduleIds.push(scheduleId);
|
||||
|
||||
this.visitBlock(this.cx.ir.blocks.get(terminal.test)!, blockValue);
|
||||
const { place, value } = this.visitValueTerminal(terminal);
|
||||
blockValue.push({
|
||||
kind: "instruction",
|
||||
instruction: {
|
||||
id: terminal.id,
|
||||
lvalue: { kind: InstructionKind.Const, place },
|
||||
value,
|
||||
loc: terminal.loc,
|
||||
},
|
||||
});
|
||||
|
||||
this.cx.unschedule(scheduleId);
|
||||
this.visitBlock(this.cx.ir.blocks.get(fallthroughId)!, blockValue);
|
||||
@@ -447,6 +469,119 @@ class Driver {
|
||||
}
|
||||
}
|
||||
|
||||
visitValueTerminal(terminal: Terminal): {
|
||||
value: ReactiveValue;
|
||||
place: Place;
|
||||
fallthrough: BlockId;
|
||||
} {
|
||||
switch (terminal.kind) {
|
||||
case "logical": {
|
||||
let testBlock: BasicBlock;
|
||||
let leftValue: ReactiveValue | null = null;
|
||||
let leftPlace: Place | null = null;
|
||||
const defaultTestBlock = this.cx.ir.blocks.get(terminal.test)!;
|
||||
if (defaultTestBlock.terminal.kind === "branch") {
|
||||
testBlock = defaultTestBlock;
|
||||
} else {
|
||||
const leftResult = this.visitValueTerminal(defaultTestBlock.terminal);
|
||||
testBlock = this.cx.ir.blocks.get(leftResult.fallthrough)!;
|
||||
leftValue = leftResult.value;
|
||||
leftPlace = leftResult.place;
|
||||
}
|
||||
|
||||
invariant(
|
||||
testBlock.terminal.kind === "branch",
|
||||
"Unexpected terminal kind '%s' for logical test block",
|
||||
testBlock.terminal.kind
|
||||
);
|
||||
const leftInstructions: Array<ReactiveInstruction> =
|
||||
testBlock.instructions;
|
||||
const leftBlock = this.cx.ir.blocks.get(testBlock.terminal.consequent)!;
|
||||
leftInstructions.push(...leftBlock.instructions);
|
||||
// TODO: If right block ends in a value terminal, recursively process with visitValueTerminal
|
||||
// similar to handling for the compound lhs case.
|
||||
const rightBlock = this.cx.ir.blocks.get(testBlock.terminal.alternate)!;
|
||||
const rightInstructions: Array<ReactiveInstruction> =
|
||||
rightBlock.instructions;
|
||||
const place = leftInstructions.at(-1)!.lvalue!.place;
|
||||
invariant(
|
||||
place.identifier ===
|
||||
rightInstructions.at(-1)!.lvalue!.place.identifier,
|
||||
"Expected both branches of a logical expression to store to the same temporary"
|
||||
);
|
||||
if (leftPlace !== null) {
|
||||
leftInstructions.forEach((instr) =>
|
||||
mapInstructionOperands(instr as Instruction, (place) => {
|
||||
return place.identifier === leftPlace!.identifier
|
||||
? (leftValue! as Place)
|
||||
: place;
|
||||
})
|
||||
);
|
||||
rightInstructions.forEach((instr) =>
|
||||
mapInstructionOperands(instr as Instruction, (place) => {
|
||||
return place.identifier === leftPlace!.identifier
|
||||
? (leftValue! as Place)
|
||||
: place;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
let left: ReactiveValue;
|
||||
if (leftInstructions.length === 1) {
|
||||
left = leftInstructions[0]!.value;
|
||||
} else {
|
||||
const sequence: ReactiveSequenceValue = {
|
||||
kind: "SequenceExpression",
|
||||
instructions: leftInstructions.slice(0, -1),
|
||||
value: leftInstructions.at(-1)!.value,
|
||||
loc: terminal.loc,
|
||||
};
|
||||
left = sequence;
|
||||
}
|
||||
let right: ReactiveValue;
|
||||
if (rightInstructions.length === 1) {
|
||||
right = rightInstructions[0]!.value;
|
||||
} else {
|
||||
const sequence: ReactiveSequenceValue = {
|
||||
kind: "SequenceExpression",
|
||||
instructions: rightInstructions.slice(0, -1),
|
||||
value: rightInstructions.at(-1)!.value,
|
||||
loc: terminal.loc,
|
||||
};
|
||||
right = sequence;
|
||||
}
|
||||
const value: ReactiveLogicalValue = {
|
||||
kind: "LogicalExpression",
|
||||
operator: terminal.operator,
|
||||
left,
|
||||
right,
|
||||
loc: terminal.loc,
|
||||
};
|
||||
console.log(
|
||||
printTerminal(terminal) +
|
||||
" testBlock=" +
|
||||
testBlock.id +
|
||||
" " +
|
||||
printPlace(place) +
|
||||
"=" +
|
||||
printInstructionValue(value)
|
||||
);
|
||||
return {
|
||||
place: { ...place },
|
||||
value,
|
||||
fallthrough: terminal.fallthrough,
|
||||
};
|
||||
}
|
||||
default: {
|
||||
invariant(
|
||||
false,
|
||||
"Unexpected value block terminal kind '%s'",
|
||||
terminal.kind
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitInitBlock(parent: ReactiveBlock, block: BasicBlock): ReactiveValueBlock {
|
||||
const initBlock: ReactiveValueBlock = {
|
||||
kind: "value-block",
|
||||
|
||||
@@ -93,7 +93,7 @@ function codegenBlock(cx: Context, block: ReactiveBlock): t.BlockStatement {
|
||||
const statement = codegenInstructionNullable(
|
||||
cx,
|
||||
item.instruction,
|
||||
codegenInstructionValue(cx.temp, item.instruction.value)
|
||||
codegenInstructionValue(cx, item.instruction.value)
|
||||
);
|
||||
if (statement !== null) {
|
||||
statements.push(statement);
|
||||
@@ -272,7 +272,7 @@ function codegenTerminal(
|
||||
}
|
||||
case "if": {
|
||||
return t.ifStatement(
|
||||
codegenPlace(cx.temp, terminal.test),
|
||||
codegenPlace(cx, terminal.test),
|
||||
codegenBlock(cx, terminal.consequent),
|
||||
terminal.alternate !== null
|
||||
? codegenBlock(cx, terminal.alternate)
|
||||
@@ -281,22 +281,22 @@ function codegenTerminal(
|
||||
}
|
||||
case "return": {
|
||||
return t.returnStatement(
|
||||
terminal.value !== null ? codegenPlace(cx.temp, terminal.value) : null
|
||||
terminal.value !== null ? codegenPlace(cx, terminal.value) : null
|
||||
);
|
||||
}
|
||||
case "switch": {
|
||||
return t.switchStatement(
|
||||
codegenPlace(cx.temp, terminal.test),
|
||||
codegenPlace(cx, terminal.test),
|
||||
terminal.cases.map((case_) => {
|
||||
const test =
|
||||
case_.test !== null ? codegenPlace(cx.temp, case_.test) : null;
|
||||
case_.test !== null ? codegenPlace(cx, case_.test) : null;
|
||||
const block = codegenBlock(cx, case_.block!);
|
||||
return t.switchCase(test, [block]);
|
||||
})
|
||||
);
|
||||
}
|
||||
case "throw": {
|
||||
return t.throwStatement(codegenPlace(cx.temp, terminal.value));
|
||||
return t.throwStatement(codegenPlace(cx, terminal.value));
|
||||
}
|
||||
case "while": {
|
||||
const test = codegenValueBlock(cx, terminal.test);
|
||||
@@ -319,7 +319,7 @@ function codegenInstructionNullable(
|
||||
let statement;
|
||||
if (instr.lvalue !== null && cx.declared(instr.lvalue.place.identifier)) {
|
||||
statement = codegenInstruction(
|
||||
cx.temp,
|
||||
cx,
|
||||
{
|
||||
...instr,
|
||||
lvalue: {
|
||||
@@ -330,7 +330,7 @@ function codegenInstructionNullable(
|
||||
value
|
||||
);
|
||||
} else {
|
||||
statement = codegenInstruction(cx.temp, instr, value);
|
||||
statement = codegenInstruction(cx, instr, value);
|
||||
}
|
||||
if (statement.type === "EmptyStatement") {
|
||||
return null;
|
||||
@@ -348,7 +348,7 @@ function codegenForInit(
|
||||
body.length === 0,
|
||||
"Expected for init block to produce only temporaries"
|
||||
);
|
||||
return codegenInstructionValue(cx.temp, init.last.value);
|
||||
return codegenInstructionValue(cx, init.last.value);
|
||||
} else {
|
||||
invariant(
|
||||
body.length === 1,
|
||||
@@ -376,7 +376,7 @@ function codegenValueBlock(
|
||||
}
|
||||
});
|
||||
if (block.last !== null) {
|
||||
const value = codegenInstructionValue(cx.temp, block.last.value);
|
||||
const value = codegenInstructionValue(cx, block.last.value);
|
||||
expressions.push(value);
|
||||
}
|
||||
invariant(
|
||||
@@ -431,6 +431,7 @@ const createVariableDeclaration = withLoc(t.variableDeclaration);
|
||||
const createWhileStatement = withLoc(t.whileStatement);
|
||||
const createTaggedTemplateExpression = withLoc(t.taggedTemplateExpression);
|
||||
const createLogicalExpression = withLoc(t.logicalExpression);
|
||||
const createSequenceExpression = withLoc(t.sequenceExpression);
|
||||
|
||||
type Temporaries = Map<IdentifierId, t.Expression>;
|
||||
|
||||
@@ -439,7 +440,7 @@ function codegenLabel(id: BlockId): string {
|
||||
}
|
||||
|
||||
function codegenInstruction(
|
||||
temp: Temporaries,
|
||||
cx: Context,
|
||||
instr: ReactiveInstruction,
|
||||
value: t.Expression
|
||||
): t.Statement {
|
||||
@@ -451,7 +452,7 @@ function codegenInstruction(
|
||||
}
|
||||
if (instr.lvalue.place.identifier.name === null) {
|
||||
// temporary
|
||||
temp.set(instr.lvalue.place.identifier.id, value);
|
||||
cx.temp.set(instr.lvalue.place.identifier.id, value);
|
||||
return t.emptyStatement();
|
||||
} else {
|
||||
switch (instr.lvalue.kind) {
|
||||
@@ -482,21 +483,21 @@ function codegenInstruction(
|
||||
}
|
||||
|
||||
function codegenInstructionValue(
|
||||
temp: Temporaries,
|
||||
cx: Context,
|
||||
instrValue: ReactiveValue
|
||||
): t.Expression {
|
||||
let value: t.Expression;
|
||||
switch (instrValue.kind) {
|
||||
case "ArrayExpression": {
|
||||
const elements = instrValue.elements.map((element) =>
|
||||
codegenPlace(temp, element)
|
||||
codegenPlace(cx, element)
|
||||
);
|
||||
value = t.arrayExpression(elements);
|
||||
break;
|
||||
}
|
||||
case "BinaryExpression": {
|
||||
const left = codegenPlace(temp, instrValue.left);
|
||||
const right = codegenPlace(temp, instrValue.right);
|
||||
const left = codegenPlace(cx, instrValue.left);
|
||||
const right = codegenPlace(cx, instrValue.right);
|
||||
value = createBinaryExpression(
|
||||
instrValue.loc,
|
||||
instrValue.operator,
|
||||
@@ -508,41 +509,41 @@ function codegenInstructionValue(
|
||||
case "UnaryExpression": {
|
||||
value = t.unaryExpression(
|
||||
instrValue.operator as "throw", // todo
|
||||
codegenPlace(temp, instrValue.value)
|
||||
codegenPlace(cx, instrValue.value)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "Primitive": {
|
||||
value = codegenValue(temp, instrValue.value);
|
||||
value = codegenValue(cx, instrValue.value);
|
||||
break;
|
||||
}
|
||||
case "CallExpression": {
|
||||
const callee = codegenPlace(temp, instrValue.callee);
|
||||
const args = instrValue.args.map((arg) => codegenPlace(temp, arg));
|
||||
const callee = codegenPlace(cx, instrValue.callee);
|
||||
const args = instrValue.args.map((arg) => codegenPlace(cx, arg));
|
||||
value = createCallExpression(instrValue.loc, callee, args);
|
||||
break;
|
||||
}
|
||||
case "PropertyCall": {
|
||||
const receiver = codegenPlace(temp, instrValue.receiver);
|
||||
const receiver = codegenPlace(cx, instrValue.receiver);
|
||||
const callee = t.memberExpression(
|
||||
receiver,
|
||||
t.identifier(instrValue.property)
|
||||
);
|
||||
const args = instrValue.args.map((arg) => codegenPlace(temp, arg));
|
||||
const args = instrValue.args.map((arg) => codegenPlace(cx, arg));
|
||||
value = createCallExpression(instrValue.loc, callee, args);
|
||||
break;
|
||||
}
|
||||
case "ComputedCall": {
|
||||
const receiver = codegenPlace(temp, instrValue.receiver);
|
||||
const property = codegenPlace(temp, instrValue.property);
|
||||
const receiver = codegenPlace(cx, instrValue.receiver);
|
||||
const property = codegenPlace(cx, instrValue.property);
|
||||
const callee = t.memberExpression(receiver, property, true);
|
||||
const args = instrValue.args.map((arg) => codegenPlace(temp, arg));
|
||||
const args = instrValue.args.map((arg) => codegenPlace(cx, arg));
|
||||
value = createCallExpression(instrValue.loc, callee, args);
|
||||
break;
|
||||
}
|
||||
case "NewExpression": {
|
||||
const callee = codegenPlace(temp, instrValue.callee);
|
||||
const args = instrValue.args.map((arg) => codegenPlace(temp, arg));
|
||||
const callee = codegenPlace(cx, instrValue.callee);
|
||||
const args = instrValue.args.map((arg) => codegenPlace(cx, arg));
|
||||
value = t.newExpression(callee, args);
|
||||
break;
|
||||
}
|
||||
@@ -551,10 +552,7 @@ function codegenInstructionValue(
|
||||
if (instrValue.properties !== null) {
|
||||
for (const [property, value] of instrValue.properties) {
|
||||
properties.push(
|
||||
t.objectProperty(
|
||||
t.stringLiteral(property),
|
||||
codegenPlace(temp, value)
|
||||
)
|
||||
t.objectProperty(t.stringLiteral(property), codegenPlace(cx, value))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -571,11 +569,11 @@ function codegenInstructionValue(
|
||||
attributes.push(
|
||||
t.jsxAttribute(
|
||||
t.jsxIdentifier(prop),
|
||||
t.jsxExpressionContainer(codegenPlace(temp, value))
|
||||
t.jsxExpressionContainer(codegenPlace(cx, value))
|
||||
)
|
||||
);
|
||||
}
|
||||
let tagValue = codegenPlace(temp, instrValue.tag);
|
||||
let tagValue = codegenPlace(cx, instrValue.tag);
|
||||
let tag: string;
|
||||
if (tagValue.type === "Identifier") {
|
||||
tag = tagValue.name;
|
||||
@@ -588,7 +586,7 @@ function codegenInstructionValue(
|
||||
}
|
||||
const children =
|
||||
instrValue.children !== null
|
||||
? instrValue.children.map((child) => codegenJsxElement(temp, child))
|
||||
? instrValue.children.map((child) => codegenJsxElement(cx, child))
|
||||
: [];
|
||||
value = t.jsxElement(
|
||||
t.jsxOpeningElement(
|
||||
@@ -608,7 +606,7 @@ function codegenInstructionValue(
|
||||
value = t.jsxFragment(
|
||||
t.jsxOpeningFragment(),
|
||||
t.jsxClosingFragment(),
|
||||
instrValue.children.map((child) => codegenJsxElement(temp, child))
|
||||
instrValue.children.map((child) => codegenJsxElement(cx, child))
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -624,24 +622,24 @@ function codegenInstructionValue(
|
||||
value = t.assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(
|
||||
codegenPlace(temp, instrValue.object),
|
||||
codegenPlace(cx, instrValue.object),
|
||||
t.identifier(instrValue.property)
|
||||
),
|
||||
codegenPlace(temp, instrValue.value)
|
||||
codegenPlace(cx, instrValue.value)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "PropertyLoad": {
|
||||
if (instrValue.optional) {
|
||||
value = t.optionalMemberExpression(
|
||||
codegenPlace(temp, instrValue.object),
|
||||
codegenPlace(cx, instrValue.object),
|
||||
t.identifier(instrValue.property),
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
value = t.memberExpression(
|
||||
codegenPlace(temp, instrValue.object),
|
||||
codegenPlace(cx, instrValue.object),
|
||||
t.identifier(instrValue.property)
|
||||
);
|
||||
}
|
||||
@@ -651,24 +649,24 @@ function codegenInstructionValue(
|
||||
value = t.assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(
|
||||
codegenPlace(temp, instrValue.object),
|
||||
codegenPlace(temp, instrValue.property),
|
||||
codegenPlace(cx, instrValue.object),
|
||||
codegenPlace(cx, instrValue.property),
|
||||
true
|
||||
),
|
||||
codegenPlace(temp, instrValue.value)
|
||||
codegenPlace(cx, instrValue.value)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "ComputedLoad": {
|
||||
value = t.memberExpression(
|
||||
codegenPlace(temp, instrValue.object),
|
||||
codegenPlace(temp, instrValue.property),
|
||||
codegenPlace(cx, instrValue.object),
|
||||
codegenPlace(cx, instrValue.property),
|
||||
true
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "Identifier": {
|
||||
value = codegenPlace(temp, instrValue);
|
||||
value = codegenPlace(cx, instrValue);
|
||||
break;
|
||||
}
|
||||
case "FunctionExpression": {
|
||||
@@ -681,7 +679,7 @@ function codegenInstructionValue(
|
||||
case "TaggedTemplateExpression": {
|
||||
value = createTaggedTemplateExpression(
|
||||
instrValue.loc,
|
||||
codegenPlace(temp, instrValue.tag),
|
||||
codegenPlace(cx, instrValue.tag),
|
||||
t.templateLiteral([t.templateElement(instrValue.value)], [])
|
||||
);
|
||||
break;
|
||||
@@ -690,11 +688,39 @@ function codegenInstructionValue(
|
||||
value = createLogicalExpression(
|
||||
instrValue.loc,
|
||||
instrValue.operator,
|
||||
codegenInstructionValue(temp, instrValue.left),
|
||||
codegenInstructionValue(temp, instrValue.right)
|
||||
codegenInstructionValue(cx, instrValue.left),
|
||||
codegenInstructionValue(cx, instrValue.right)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "SequenceExpression": {
|
||||
const body = codegenBlock(
|
||||
cx,
|
||||
instrValue.instructions.map((instruction) => ({
|
||||
kind: "instruction",
|
||||
instruction,
|
||||
}))
|
||||
).body;
|
||||
const expressions = body.map((stmt) => {
|
||||
if (stmt.type === "ExpressionStatement") {
|
||||
return stmt.expression;
|
||||
} else {
|
||||
todoInvariant(
|
||||
false,
|
||||
`Handle conversion of ${stmt.type} to expression`
|
||||
);
|
||||
}
|
||||
});
|
||||
if (expressions.length === 0) {
|
||||
value = codegenInstructionValue(cx, instrValue.value);
|
||||
} else {
|
||||
value = createSequenceExpression(instrValue.loc, [
|
||||
...expressions,
|
||||
codegenInstructionValue(cx, instrValue.value),
|
||||
]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(
|
||||
instrValue,
|
||||
@@ -706,7 +732,7 @@ function codegenInstructionValue(
|
||||
}
|
||||
|
||||
function codegenJsxElement(
|
||||
temp: Temporaries,
|
||||
cx: Context,
|
||||
place: Place
|
||||
):
|
||||
| t.JSXText
|
||||
@@ -714,7 +740,7 @@ function codegenJsxElement(
|
||||
| t.JSXSpreadChild
|
||||
| t.JSXElement
|
||||
| t.JSXFragment {
|
||||
const value = codegenPlace(temp, place);
|
||||
const value = codegenPlace(cx, place);
|
||||
switch (value.type) {
|
||||
case "StringLiteral": {
|
||||
return t.jsxText(value.value);
|
||||
@@ -730,7 +756,7 @@ function codegenLVal(lval: LValue): t.LVal {
|
||||
}
|
||||
|
||||
function codegenValue(
|
||||
temp: Temporaries,
|
||||
cx: Context,
|
||||
value: boolean | number | string | null | undefined
|
||||
): t.Expression {
|
||||
if (typeof value === "number") {
|
||||
@@ -748,9 +774,9 @@ function codegenValue(
|
||||
}
|
||||
}
|
||||
|
||||
function codegenPlace(temp: Temporaries, place: Place): t.Expression {
|
||||
function codegenPlace(cx: Context, place: Place): t.Expression {
|
||||
todoInvariant(place.kind === "Identifier", "support scope values");
|
||||
let tmp = temp.get(place.identifier.id);
|
||||
let tmp = cx.temp.get(place.identifier.id);
|
||||
if (tmp != null) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -91,6 +91,13 @@ export function* eachReactiveValueOperand(
|
||||
yield* eachReactiveValueOperand(instrValue.right);
|
||||
break;
|
||||
}
|
||||
case "SequenceExpression": {
|
||||
for (const instr of instrValue.instructions) {
|
||||
yield* eachReactiveValueOperand(instr.value);
|
||||
}
|
||||
yield* eachReactiveValueOperand(instrValue.value);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
yield* eachInstructionValueOperand(instrValue);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,6 @@ export function leaveSSA(fn: HIRFunction) {
|
||||
(terminal.kind === "if" ||
|
||||
terminal.kind === "switch" ||
|
||||
terminal.kind === "while" ||
|
||||
terminal.kind === "logical" ||
|
||||
terminal.kind === "for") &&
|
||||
terminal.fallthrough !== null
|
||||
) {
|
||||
@@ -149,6 +148,11 @@ export function leaveSSA(fn: HIRFunction) {
|
||||
pushPhis(rewritePhis, update);
|
||||
update.phis.clear();
|
||||
}
|
||||
if (terminal.kind === "logical") {
|
||||
const fallthrough = fn.body.blocks.get(terminal.fallthrough)!;
|
||||
pushPhis(rewritePhis, fallthrough);
|
||||
fallthrough.phis.clear();
|
||||
}
|
||||
|
||||
for (const { phi, block: phiBlock } of reassignmentPhis) {
|
||||
// In some cases one of the phi operands can be defined *before* the let binding
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @only
|
||||
function component(props) {
|
||||
let a = props.a && props.b;
|
||||
let a = (props.a && props.b && props.c) || props.d;
|
||||
return a;
|
||||
// let b = props.c || props.d;
|
||||
// let c = props.e ?? props.f;
|
||||
@@ -15,25 +16,19 @@ function component(props) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @only
|
||||
function component(props) {
|
||||
const $ = React.useMemoCache();
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== props.b;
|
||||
let t2;
|
||||
if (c_0 || c_1) {
|
||||
t2 = undefined;
|
||||
if (props.a) {
|
||||
t2 = props.a;
|
||||
} else {
|
||||
t2 = props.b;
|
||||
}
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = t2;
|
||||
const c_0 = $[0] !== props;
|
||||
let t1;
|
||||
if (c_0) {
|
||||
t1 = (props.a && props.b && props.c) || props.d;
|
||||
$[0] = props;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
t1 = $[1];
|
||||
}
|
||||
const a = t2;
|
||||
const a = t1;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @only
|
||||
function component(props) {
|
||||
let a = props.a && props.b;
|
||||
let a = (props.a && props.b && props.c) || props.d;
|
||||
return a;
|
||||
// let b = props.c || props.d;
|
||||
// let c = props.e ?? props.f;
|
||||
|
||||
Reference in New Issue
Block a user