From 3f2b346ba0df118e2e6a1bbc4387159d82437873 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 22 Jun 2023 10:18:41 -0400 Subject: [PATCH] Make CompilerError.invariant assert the condition This allows us to mimic the `invariant` api, which means you can just assert that something holds true after execution proceeds to the next line without throwing --- .../src/CompilerError.ts | 25 +++--- .../src/Entrypoint/Program.ts | 34 ++++---- .../src/HIR/AssertConsistentIdentifiers.ts | 29 ++++--- .../src/HIR/AssertTerminalSuccessorsExist.ts | 17 ++-- .../src/HIR/FindContextIdentifiers.ts | 22 +++-- .../babel-plugin-react-forget/src/HIR/HIR.ts | 2 +- .../src/Inference/InferReferenceEffects.ts | 24 +++--- .../ReactiveScopes/BuildReactiveFunction.ts | 11 ++- .../ReactiveScopes/CodegenReactiveFunction.ts | 53 ++++++------ .../InferReactiveIdentifiers.ts | 6 +- .../ReactiveScopes/PromoteUsedTemporaries.ts | 11 ++- .../PropagateScopeDependencies.ts | 28 +++---- .../ReactiveScopes/PruneNonEscapingScopes.ts | 2 +- .../src/SSA/EnterSSA.ts | 24 +++--- .../src/SSA/LeaveSSA.ts | 84 +++++++++---------- 15 files changed, 179 insertions(+), 193 deletions(-) diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/CompilerError.ts b/compiler/forget/packages/babel-plugin-react-forget/src/CompilerError.ts index 870a9464d3..d0c8b9bcd1 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/CompilerError.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/CompilerError.ts @@ -70,20 +70,23 @@ export class CompilerError extends Error { details: CompilerErrorDetail[] = []; static invariant( + condition: unknown, reason: string, loc: SourceLocation, description: string | null = null - ): never { - const errors = new CompilerError(); - errors.pushErrorDetail( - new CompilerErrorDetail({ - description, - loc, - reason, - severity: ErrorSeverity.Invariant, - }) - ); - throw errors; + ): asserts condition { + if (!condition) { + const errors = new CompilerError(); + errors.pushErrorDetail( + new CompilerErrorDetail({ + description, + loc, + reason, + severity: ErrorSeverity.Invariant, + }) + ); + throw errors; + } } static todo( diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts b/compiler/forget/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts index cba1f34fd6..921de23204 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts @@ -53,12 +53,11 @@ export function compileProgram( return; } - if (fn.node.id == null) { - CompilerError.invariant( - "FunctionDeclaration must have a name", - fn.node.loc ?? GeneratedSource - ); - } + CompilerError.invariant( + fn.node.id != null, + "FunctionDeclaration must have a name", + fn.node.loc ?? GeneratedSource + ); const originalIdent = fn.node.id; if (pass.opts.gating != null) { @@ -66,12 +65,11 @@ export function compileProgram( fn.node.id = addSuffix(fn.node.id, "_uncompiled"); // Rename and append compiled function - if (compiled.id == null) { - CompilerError.invariant( - "FunctionDeclaration must produce a name", - fn.node.loc ?? GeneratedSource - ); - } + CompilerError.invariant( + compiled.id != null, + "FunctionDeclaration must produce a name", + fn.node.loc ?? GeneratedSource + ); compiled.id = addSuffix(compiled.id, "_forget"); const compiledFn = fn.insertAfter(compiled)[0]; compiledFn.skip(); @@ -409,12 +407,12 @@ function buildBlockStatement( return wrappedBody.node; } - if (!body.isBlockStatement()) { - CompilerError.invariant( - "Body must be a BlockStatement", - body.node.loc ?? GeneratedSource - ); - } + CompilerError.invariant( + body.isBlockStatement(), + "Body must be a BlockStatement", + body.node.loc ?? GeneratedSource + ); + return body.node; } diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertConsistentIdentifiers.ts b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertConsistentIdentifiers.ts index d5807f1584..d783610b60 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertConsistentIdentifiers.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertConsistentIdentifiers.ts @@ -35,20 +35,18 @@ export function assertConsistentIdentifiers(fn: HIRFunction): void { } } for (const instr of block.instructions) { - if (instr.lvalue.identifier.name !== null) { - CompilerError.invariant( - `Expected all lvalues to be temporaries`, - instr.lvalue.loc, - `Found named lvalue '${instr.lvalue.identifier.name}'` - ); - } - if (assignments.has(instr.lvalue.identifier.id)) { - CompilerError.invariant( - `Expected lvalues to be assigned exactly once`, - instr.lvalue.loc, - `Found duplicate assignment of '${printPlace(instr.lvalue)}'` - ); - } + CompilerError.invariant( + instr.lvalue.identifier.name === null, + `Expected all lvalues to be temporaries`, + instr.lvalue.loc, + `Found named lvalue '${instr.lvalue.identifier.name}'` + ); + CompilerError.invariant( + !assignments.has(instr.lvalue.identifier.id), + `Expected lvalues to be assigned exactly once`, + instr.lvalue.loc, + `Found duplicate assignment of '${printPlace(instr.lvalue)}'` + ); assignments.add(instr.lvalue.identifier.id); for (const operand of eachInstructionLValue(instr)) { validate(identifiers, operand.identifier, operand.loc); @@ -73,8 +71,9 @@ function validate( const previous = identifiers.get(identifier.id); if (previous === undefined) { identifiers.set(identifier.id, identifier); - } else if (identifier !== previous) { + } else { CompilerError.invariant( + identifier === previous, `Duplicate identifier object`, loc ?? GeneratedSource, `Found duplicate identifier object for id ${identifier.id}` diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertTerminalSuccessorsExist.ts b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertTerminalSuccessorsExist.ts index 92dd4edad9..0eb75f28c9 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertTerminalSuccessorsExist.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/AssertTerminalSuccessorsExist.ts @@ -13,15 +13,14 @@ import { mapTerminalSuccessors } from "./visitors"; export function assertTerminalSuccessorsExist(fn: HIRFunction): void { for (const [, block] of fn.body.blocks) { mapTerminalSuccessors(block.terminal, (successor) => { - if (!fn.body.blocks.has(successor)) { - CompilerError.invariant( - `Terminal successor references unknown block`, - (block.terminal as any).loc ?? GeneratedSource, - `Block bb${successor} does not exist for terminal '${printTerminal( - block.terminal - )}'` - ); - } + CompilerError.invariant( + fn.body.blocks.has(successor), + `Terminal successor references unknown block`, + (block.terminal as any).loc ?? GeneratedSource, + `Block bb${successor} does not exist for terminal '${printTerminal( + block.terminal + )}'` + ); return successor; }); } diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/FindContextIdentifiers.ts b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/FindContextIdentifiers.ts index 5220abf9aa..40817642fb 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/FindContextIdentifiers.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/FindContextIdentifiers.ts @@ -137,20 +137,18 @@ function handleAssignment( for (const property of path.get("properties")) { if (property.isObjectProperty()) { const valuePath = property.get("value"); - if (!valuePath.isLVal()) { - CompilerError.invariant( - `[FindContextIdentifiers] Expected object property value to be an LVal, got: ${valuePath.type}`, - valuePath.node.loc ?? GeneratedSource - ); - } + CompilerError.invariant( + valuePath.isLVal(), + `[FindContextIdentifiers] Expected object property value to be an LVal, got: ${valuePath.type}`, + valuePath.node.loc ?? GeneratedSource + ); handleAssignment(reassigned, valuePath); } else { - if (!property.isRestElement()) { - CompilerError.invariant( - `[FindContextIdentifiers] Invalid assumptions for babel types.`, - property.node.loc ?? GeneratedSource - ); - } + CompilerError.invariant( + property.isRestElement(), + `[FindContextIdentifiers] Invalid assumptions for babel types.`, + property.node.loc ?? GeneratedSource + ); handleAssignment(reassigned, property); } } diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/HIR.ts b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/HIR.ts index 1b3a553f68..b2b002ebfe 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/HIR/HIR.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/HIR/HIR.ts @@ -884,7 +884,7 @@ export function isMutableEffect( } case Effect.Unknown: { - CompilerError.invariant("Unexpected unknown effect", location); + CompilerError.invariant(false, "Unexpected unknown effect", location); } case Effect.Read: case Effect.Freeze: { diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts b/compiler/forget/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts index def729e796..adb90428ff 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts @@ -215,13 +215,12 @@ class InferenceState { const kind = this.#values.get(value)!; mergedKind = mergedKind !== null ? mergeValues(mergedKind, kind) : kind; } - if (mergedKind === null) { - CompilerError.invariant( - `InferReferenceEffects::kind: Expected at least one value`, - place.loc, - `No value found at '${printPlace(place)}'` - ); - } + CompilerError.invariant( + mergedKind !== null, + `InferReferenceEffects::kind: Expected at least one value`, + place.loc, + `No value found at '${printPlace(place)}'` + ); return mergedKind; } @@ -268,12 +267,11 @@ class InferenceState { reference(place: Place, effectKind: Effect): void { const values = this.#variables.get(place.identifier.id); if (values === undefined) { - if (effectKind === Effect.Store) { - CompilerError.invariant( - "[InferReferenceEffects] Unhandled store reference effect", - place.loc - ); - } + CompilerError.invariant( + effectKind !== Effect.Store, + "[InferReferenceEffects] Unhandled store reference effect", + place.loc + ); place.effect = effectKind === Effect.ConditionallyMutate ? Effect.ConditionallyMutate diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/BuildReactiveFunction.ts b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/BuildReactiveFunction.ts index bc4598d6ad..41cc146038 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/BuildReactiveFunction.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/BuildReactiveFunction.ts @@ -543,12 +543,11 @@ class Driver { let block: ReactiveBlock; if (this.cx.isScheduled(terminal.block)) { const break_ = this.visitBreak(terminal.block, null); - if (break_ === null) { - CompilerError.invariant( - "Expected a break target for a label whose body is already scheduled", - terminal.loc - ); - } + CompilerError.invariant( + break_ !== null, + "Expected a break target for a label whose body is already scheduled", + terminal.loc + ); block = [break_]; } else { block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block)!); diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts index 29e253e086..ecd9fce018 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -345,13 +345,12 @@ function codegenTerminal( ); } case "for-of": { - if (terminal.init.kind !== "SequenceExpression") { - CompilerError.invariant( - `Expected a sequence expression init for ForOf`, - terminal.init.loc, - `Got '${terminal.init.kind}' expression instead` - ); - } + CompilerError.invariant( + terminal.init.kind === "SequenceExpression", + `Expected a sequence expression init for ForOf`, + terminal.init.loc, + `Got '${terminal.init.kind}' expression instead` + ); if (terminal.init.instructions.length !== 2) { CompilerError.todo( "Support non-trivial ForOf inits", @@ -372,6 +371,7 @@ function codegenTerminal( } default: CompilerError.invariant( + false, `Expected a StoreLocal or Destructure to be assigned to the collection`, iterableItem.value.loc, `Found ${iterableItem.value.kind}` @@ -387,6 +387,7 @@ function codegenTerminal( break; case InstructionKind.Reassign: CompilerError.invariant( + false, "Destructure should never be Reassign as it would be an Object/ArrayPattern", iterableItem.loc ); @@ -510,6 +511,7 @@ function codegenInstructionNullable( } if (hasReasign && hasDeclaration) { CompilerError.invariant( + false, "Encountered a destructuring operation where some identifiers are already declared (reassignments) but others are not (declarations)", instr.loc ); @@ -520,23 +522,21 @@ function codegenInstructionNullable( } switch (kind) { case InstructionKind.Const: { - if (instr.lvalue !== null) { - CompilerError.invariant( - `Const declaration cannot be referenced as an expression`, - instr.value.loc - ); - } + CompilerError.invariant( + instr.lvalue === null, + `Const declaration cannot be referenced as an expression`, + instr.value.loc + ); return createVariableDeclaration(instr.loc, "const", [ t.variableDeclarator(codegenLValue(lvalue), value), ]); } case InstructionKind.Let: { - if (instr.lvalue !== null) { - CompilerError.invariant( - `Const declaration cannot be referenced as an expression`, - instr.value.loc - ); - } + CompilerError.invariant( + instr.lvalue === null, + `Const declaration cannot be referenced as an expression`, + instr.value.loc + ); return createVariableDeclaration(instr.loc, "let", [ t.variableDeclarator(codegenLValue(lvalue), value), ]); @@ -768,6 +768,7 @@ function codegenInstructionValue( } default: { CompilerError.invariant( + false, "Expected an optional value to resolve to a call expression or member expression", instrValue.loc, `Got a '${optionalValue.type}'` @@ -1097,6 +1098,7 @@ function codegenInstructionValue( case "StoreLocal": case "StoreContext": { CompilerError.invariant( + false, `Unexpected ${instrValue.kind} in codegenInstructionValue`, instrValue.loc ); @@ -1276,13 +1278,12 @@ function codegenPlace(cx: Context, place: Place): t.Expression { if (tmp != null) { return tmp; } - if (place.identifier.name === null && tmp === undefined) { - CompilerError.invariant( - `[Codegen] No value found for temporary`, - place.loc, - `Value for '${printPlace(place)}' was not set in the codegen context` - ); - } + CompilerError.invariant( + place.identifier.name !== null || tmp !== undefined, + `[Codegen] No value found for temporary`, + place.loc, + `Value for '${printPlace(place)}' was not set in the codegen context` + ); const identifier = convertIdentifier(place.identifier); identifier.loc = place.loc as any; return identifier; diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/InferReactiveIdentifiers.ts b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/InferReactiveIdentifiers.ts index afeb6d15c0..454f3fe026 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/InferReactiveIdentifiers.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/InferReactiveIdentifiers.ts @@ -105,7 +105,11 @@ class Visitor extends ReactiveFunctionVisitor { break; } case Effect.Unknown: { - CompilerError.invariant("Unexpected unknown effect", operand.loc); + CompilerError.invariant( + false, + "Unexpected unknown effect", + operand.loc + ); } default: { assertExhaustive( diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PromoteUsedTemporaries.ts b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PromoteUsedTemporaries.ts index 8c6421d81f..11694883b3 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PromoteUsedTemporaries.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PromoteUsedTemporaries.ts @@ -75,12 +75,11 @@ export function promoteUsedTemporaries(fn: ReactiveFunction): void { } function promoteTemporary(identifier: Identifier, state: VisitorState): void { - if (identifier.name !== null) { - CompilerError.invariant( - "promoteTemporary: Expected to be called only for temporary variables", - GeneratedSource - ); - } + CompilerError.invariant( + identifier.name === null, + "promoteTemporary: Expected to be called only for temporary variables", + GeneratedSource + ); if (state.tags.has(identifier.id)) { identifier.name = `T${state.nextId++}`; } else { diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PropagateScopeDependencies.ts index 3f6071c90b..a1cc48b822 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -459,22 +459,20 @@ class PropagationVisitor extends ReactiveFunctionVisitor { // OptionalExpression value is a SequenceExpression where the instructions // represent the code prior to the `?` and the final value represents the // conditional code that follows. - if (inner.kind === "SequenceExpression") { - // Instructions are the unconditionally executed portion before the `?` - for (const instr of inner.instructions) { - this.visitInstruction(instr, context); - } - // The final value is the conditional portion following the `?` - context.enterConditional(() => { - this.visitReactiveValue(context, id, inner.value); - }); - } else { - CompilerError.invariant( - "Expected OptionalExpression value to be a SequenceExpression", - value.loc, - `Found a '${value.kind}'` - ); + CompilerError.invariant( + inner.kind === "SequenceExpression", + "Expected OptionalExpression value to be a SequenceExpression", + value.loc, + `Found a '${value.kind}'` + ); + // Instructions are the unconditionally executed portion before the `?` + for (const instr of inner.instructions) { + this.visitInstruction(instr, context); } + // The final value is the conditional portion following the `?` + context.enterConditional(() => { + this.visitReactiveValue(context, id, inner.value); + }); break; } case "LogicalExpression": { diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PruneNonEscapingScopes.ts b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PruneNonEscapingScopes.ts index 4b27332bc9..c00ef919c2 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PruneNonEscapingScopes.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/ReactiveScopes/PruneNonEscapingScopes.ts @@ -601,7 +601,7 @@ function computeMemoizationInputs( }; } case "UnsupportedNode": { - CompilerError.invariant(`Unexpected unsupported node`, value.loc); + CompilerError.invariant(false, `Unexpected unsupported node`, value.loc); } default: { assertExhaustive(value, `Unexpected value kind '${(value as any).kind}'`); diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/SSA/EnterSSA.ts b/compiler/forget/packages/babel-plugin-react-forget/src/SSA/EnterSSA.ts index a89f7c089a..3956980835 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/SSA/EnterSSA.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/SSA/EnterSSA.ts @@ -96,13 +96,12 @@ class SSABuilder { definePlace(oldPlace: Place): Place { const oldId = oldPlace.identifier; - if (this.#unknown.has(oldId)) { - CompilerError.invariant( - `EnterSSA: Expected identifier to be defined before being used`, - oldPlace.loc, - `Identifier ${printIdentifier(oldId)} is undefined` - ); - } + CompilerError.invariant( + !this.#unknown.has(oldId), + `EnterSSA: Expected identifier to be defined before being used`, + oldPlace.loc, + `Identifier ${printIdentifier(oldId)} is undefined` + ); // Do not redefine context references. if (this.#context.has(oldId)) { @@ -249,12 +248,11 @@ function enterSSAImpl( if (blockId === rootEntry) { // NOTE: func.context should be empty for the root function if (func.env.enableOptimizeFunctionExpressions) { - if (func.context.length !== 0) { - CompilerError.invariant( - `Expected function context to be empty for outer function declarations`, - func.loc - ); - } + CompilerError.invariant( + func.context.length === 0, + `Expected function context to be empty for outer function declarations`, + func.loc + ); } else { func.context = func.context.map((p) => builder.defineContext(p)); } diff --git a/compiler/forget/packages/babel-plugin-react-forget/src/SSA/LeaveSSA.ts b/compiler/forget/packages/babel-plugin-react-forget/src/SSA/LeaveSSA.ts index de4ad3718f..f4b81e1f06 100644 --- a/compiler/forget/packages/babel-plugin-react-forget/src/SSA/LeaveSSA.ts +++ b/compiler/forget/packages/babel-plugin-react-forget/src/SSA/LeaveSSA.ts @@ -132,13 +132,12 @@ export function leaveSSA(fn: HIRFunction): void { if (value.kind === "DeclareLocal") { const name = value.lvalue.place.identifier.name; if (name !== null) { - if (declarations.has(name)) { - CompilerError.invariant( - `Unexpected duplicate declaration`, - value.lvalue.place.loc, - `Found duplicate declaration for '${name}'` - ); - } + CompilerError.invariant( + !declarations.has(name), + `Unexpected duplicate declaration`, + value.lvalue.place.loc, + `Found duplicate declaration for '${name}'` + ); declarations.set(name, { lvalue: value.lvalue, place: value.lvalue.place, @@ -153,12 +152,11 @@ export function leaveSSA(fn: HIRFunction): void { originalLVal === undefined || originalLVal.lvalue === value.lvalue // in case this was pre-declared for the `for` initializer ) { - if (originalLVal === undefined && block.kind !== "block") { - CompilerError.invariant( - `TODO: Handle reassignment in a value block where the original declaration was removed by dead code elimination (DCE)`, - value.lvalue.place.loc - ); - } + CompilerError.invariant( + originalLVal !== undefined || block.kind === "block", + `TODO: Handle reassignment in a value block where the original declaration was removed by dead code elimination (DCE)`, + value.lvalue.place.loc + ); declarations.set(value.lvalue.place.identifier.name, { lvalue: value.lvalue, place: value.lvalue.place, @@ -177,15 +175,12 @@ export function leaveSSA(fn: HIRFunction): void { let kind: InstructionKind | null = null; for (const place of eachPatternOperand(value.lvalue.pattern)) { if (place.identifier.name == null) { - if (kind !== null && kind !== InstructionKind.Const) { - CompilerError.invariant( - `Expected consistent kind for destructuring`, - place.loc, - `other places were '${kind}' but '${printPlace( - place - )}' is const` - ); - } + CompilerError.invariant( + kind === null || kind === InstructionKind.Const, + `Expected consistent kind for destructuring`, + place.loc, + `other places were '${kind}' but '${printPlace(place)}' is const` + ); kind = InstructionKind.Const; } else { const originalLVal = declarations.get(place.identifier.name); @@ -193,36 +188,33 @@ export function leaveSSA(fn: HIRFunction): void { originalLVal === undefined || originalLVal.lvalue === value.lvalue ) { - if (originalLVal === undefined && block.kind === "value") { - CompilerError.invariant( - `TODO: Handle reassignment in a value block where the original declaration was removed by dead code elimination (DCE)`, - place.loc - ); - } + CompilerError.invariant( + originalLVal !== undefined || block.kind !== "value", + `TODO: Handle reassignment in a value block where the original declaration was removed by dead code elimination (DCE)`, + place.loc + ); declarations.set(place.identifier.name, { lvalue: value.lvalue, place, }); - if (kind !== null && kind !== InstructionKind.Const) { - CompilerError.invariant( - `Expected consistent kind for destructuring`, - place.loc, - `Other places were '${kind}' but '${printPlace( - place - )}' is const` - ); - } + CompilerError.invariant( + kind === null || kind === InstructionKind.Const, + `Expected consistent kind for destructuring`, + place.loc, + `Other places were '${kind}' but '${printPlace( + place + )}' is const` + ); kind = InstructionKind.Const; } else { - if (kind !== null && kind !== InstructionKind.Reassign) { - CompilerError.invariant( - `Expected consistent kind for destructuring`, - place.loc, - `Other places were '${kind}' but '${printPlace( - place - )}' is reassigned` - ); - } + CompilerError.invariant( + kind === null || kind === InstructionKind.Reassign, + `Expected consistent kind for destructuring`, + place.loc, + `Other places were '${kind}' but '${printPlace( + place + )}' is reassigned` + ); kind = InstructionKind.Reassign; originalLVal.lvalue.kind = InstructionKind.Let; }