diff --git a/compiler/forget/src/CompilerError.ts b/compiler/forget/src/CompilerError.ts index ba4b85b7a2..9d072725e0 100644 --- a/compiler/forget/src/CompilerError.ts +++ b/compiler/forget/src/CompilerError.ts @@ -1,11 +1,13 @@ import { Node, NodePath } from "@babel/traverse"; -import { SourceLocation } from "@babel/types"; +import { SourceLocation as BabelSourceLocation } from "@babel/types"; +import { SourceLocation } from "./HIR"; import { ExtractClassProperties } from "./Utils/types"; import { assertExhaustive } from "./Utils/utils"; export enum ErrorSeverity { InvalidInput = "InvalidInput", Todo = "Todo", + Invariant = "Invariant", } export type CompilerErrorOptions = { @@ -23,6 +25,8 @@ function mapSeverityToErrorCtor(severity: ErrorSeverity): CompilerErrorKind { return InvalidInputError; case ErrorSeverity.Todo: return TodoError; + case ErrorSeverity.Invariant: + return InvariantError; default: assertExhaustive(severity, `Unhandled severity level: ${severity}`); } @@ -39,6 +43,12 @@ class TodoError extends Error { this.name = `${ErrorSeverity.Todo}Error`; } } +class InvariantError extends Error { + constructor(message: string) { + super(message); + this.name = `${ErrorSeverity.Invariant}Error`; + } +} export function tryPrintCodeFrame( options: CompilerErrorOptions @@ -64,7 +74,7 @@ export class CompilerErrorDetail { reason: string; severity: ErrorSeverity; codeframe: string | null; - loc: SourceLocation | null; + loc: BabelSourceLocation | null; constructor(options: CompilerErrorDetailOptions) { this.reason = options.reason; @@ -92,6 +102,19 @@ export class CompilerErrorDetail { export class CompilerError extends Error { details: CompilerErrorDetail[] = []; + static invariant(reason: string, loc: SourceLocation): never { + const errors = new CompilerError(); + errors.pushErrorDetail( + new CompilerErrorDetail({ + codeframe: null, + loc: typeof loc === "symbol" ? null : loc, + reason, + severity: ErrorSeverity.Invariant, + }) + ); + throw errors; + } + constructor(...args: any[]) { super(...args); } diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index 599ddccfdf..cdb1680f80 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -1044,6 +1044,8 @@ function lowerExpression( const operator = expr.node.operator; if (builder.currentBlockKind() === "value") { + // try lowering the RHS in case it also contains errors + lowerExpressionToPlace(builder, expr.get("right")); builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle AssignmentExpression within a LogicalExpression or ConditionalExpression`, severity: ErrorSeverity.Todo, diff --git a/compiler/forget/src/Inference/InferReferenceEffects.ts b/compiler/forget/src/Inference/InferReferenceEffects.ts index cde4340860..40fdaddfc9 100644 --- a/compiler/forget/src/Inference/InferReferenceEffects.ts +++ b/compiler/forget/src/Inference/InferReferenceEffects.ts @@ -6,6 +6,7 @@ */ import invariant from "invariant"; +import { CompilerError } from "../CompilerError"; import { BasicBlock, BlockId, @@ -199,10 +200,14 @@ class Environment { const kind = this.#values.get(value)!; mergedKind = mergedKind !== null ? mergeValues(mergedKind, kind) : kind; } - invariant( - mergedKind !== null, - `Expected at least one value at ${printPlace(place)}` - ); + if (mergedKind === null) { + CompilerError.invariant( + `InferReferenceEffects::kind: Expected at least one value at '${printPlace( + place + )}'`, + place.loc + ); + } return mergedKind; }