@samitouri / QOS-React / commits / 8a0d3169fd

Record todo bailouts in CodegenReactiveFunction

Went over this pass and converted any todos to bailouts, otherwise we continue to throw an invariant if there's an internal error

Lauren Tan committed Feb 1, 2023 at 14:49 UTC 8a0d3169fdb526ac68567ed9b3d6cd7b67d2ded3
6 files changed +51 -27
compiler/forget/src/CompilerError.ts
+1 -1
@@ -13,7 +13,7 @@ export enum ErrorSeverity {
13 export type CompilerErrorOptions = {
14 reason: string;
15 severity: ErrorSeverity;
16 - nodePath: AnyNodePath;
16 + nodePath: AnyNodePath | null;
17 };
18 type AnyNodePath = NodePath<Node | null | undefined>;
19 type CompilerErrorKind = typeof InvalidInputError | typeof TodoError;
compiler/forget/src/CompilerPipeline.ts
+2 -6
@@ -46,11 +46,7 @@ export type CompilerPipelineValue =
46 export function* run(
47 func: NodePath<t.FunctionDeclaration>
48 ): Generator<CompilerPipelineValue, t.Function> {
49 - const lowering = lower(func).orElse((error) => {
50 - throw error;
51 - });
52 -
53 - const hir = lowering.unwrap();
49 + const hir = lower(func).unwrap();
50 yield log({ kind: "hir", name: "HIR", value: hir });
51
52 mergeConsecutiveBlocks(hir);
@@ -153,7 +149,7 @@ export function* run(
149 value: reactiveFunction,
150 });
151
156 - const ast = codegenReactiveFunction(reactiveFunction);
152 + const ast = codegenReactiveFunction(reactiveFunction).unwrap();
153 yield log({ kind: "ast", name: "Codegen", value: ast });
154
155 return ast;
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+32 -19
@@ -7,6 +7,7 @@
7
8 import * as t from "@babel/types";
9 import invariant from "invariant";
10 +import { CompilerError, ErrorSeverity } from "../CompilerError";
11 import {
12 BlockId,
13 GeneratedSource,
@@ -24,12 +25,12 @@ import {
25 ReactiveValue,
26 SourceLocation,
27 } from "../HIR/HIR";
27 -import { todoInvariant } from "../Utils/todo";
28 +import { Err, Ok, Result } from "../Utils/Result";
29 import { assertExhaustive } from "../Utils/utils";
30
31 export function codegenReactiveFunction(
32 fn: ReactiveFunction
32 -): t.FunctionDeclaration {
33 +): Result<t.FunctionDeclaration, CompilerError> {
34 const cx = new Context();
35 const params = fn.params.map((param) => convertIdentifier(param.identifier));
36 const body = codegenBlock(cx, fn.body);
@@ -56,13 +57,20 @@ export function codegenReactiveFunction(
57 ])
58 );
59 }
59 - return createFunctionDeclaration(
60 - fn.loc,
61 - fn.id !== null ? convertIdentifier(fn.id) : null,
62 - params,
63 - body,
64 - fn.generator,
65 - fn.async
60 +
61 + if (cx.errors.hasErrors()) {
62 + return Err(cx.errors);
63 + }
64 +
65 + return Ok(
66 + createFunctionDeclaration(
67 + fn.loc,
68 + fn.id !== null ? convertIdentifier(fn.id) : null,
69 + params,
70 + body,
71 + fn.generator,
72 + fn.async
73 + )
74 );
75 }
76
@@ -70,6 +78,7 @@ class Context {
78 #nextCacheIndex: number = 0;
79 #identifiers: Set<Identifier> = new Set();
80 temp: Temporaries = new Map();
81 + errors: CompilerError = new CompilerError();
82
83 get nextCacheIndex(): number {
84 return this.#nextCacheIndex++;
@@ -711,17 +720,22 @@ function codegenInstructionValue(
720 } else {
721 if (t.isVariableDeclaration(stmt)) {
722 const declarator = stmt.declarations[0];
714 - todoInvariant(
715 - false,
716 - `Cannot declare variables in a value block, tried to declare '${
723 + cx.errors.push({
724 + reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${
725 (declarator.id as t.Identifier).name
718 - }'`
719 - );
726 + }'`,
727 + severity: ErrorSeverity.Todo,
728 + nodePath: null,
729 + });
730 + return t.stringLiteral(`TODO handle ${declarator.id}`);
731 + } else {
732 + cx.errors.push({
733 + reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`,
734 + severity: ErrorSeverity.Todo,
735 + nodePath: null,
736 + });
737 + return t.stringLiteral(`TODO handle ${stmt.type}`);
738 }
721 - todoInvariant(
722 - false,
723 - `Handle conversion of ${stmt.type} to expression`
724 - );
739 }
740 });
741 if (expressions.length === 0) {
@@ -788,7 +802,6 @@ function codegenValue(
802 }
803
804 function codegenPlace(cx: Context, place: Place): t.Expression {
791 - todoInvariant(place.kind === "Identifier", "support scope values");
805 let tmp = cx.temp.get(place.identifier.id);
806 if (tmp != null) {
807 return tmp;
compiler/forget/src/Utils/Result.ts
+6
@@ -167,6 +167,9 @@ class OkImpl<T> implements Result<T, never> {
167 }
168
169 unwrapErr(): never {
170 + if (this.val instanceof Error) {
171 + throw this.val;
172 + }
173 throw new Error(`Can't unwrap \`Ok\` to \`Err\`: ${this.val}`);
174 }
175 }
@@ -227,6 +230,9 @@ class ErrImpl<E> implements Result<never, E> {
230 }
231
232 unwrap(): never {
233 + if (this.val instanceof Error) {
234 + throw this.val;
235 + }
236 throw new Error(`Can't unwrap \`Err\` to \`Ok\`: ${this.val}`);
237 }
238
compiler/forget/src/__tests__/Result-test.ts
+9
@@ -1,3 +1,4 @@
1 +import { CompilerError } from "../CompilerError";
2 import { Err, Ok, Result } from "../Utils/Result";
3
4 function addMax10(a: number, b: number): Result<number, string> {
@@ -9,6 +10,8 @@ function onlyFoo(foo: string): Result<string, string> {
10 return foo === "foo" ? Ok(foo) : Err(foo);
11 }
12
13 +class CustomDummyError extends Error {}
14 +
15 describe("Result", () => {
16 test(".map", () => {
17 expect(addMax10(1, 1).map((n) => n * 2)).toEqual(Ok(4));
@@ -107,6 +110,9 @@ describe("Result", () => {
110 }).toThrowErrorMatchingInlineSnapshot(
111 `"Can't unwrap \`Err\` to \`Ok\`: 20 is too high"`
112 );
113 + expect(() => {
114 + Err(new CustomDummyError("oops")).unwrap();
115 + }).toThrowErrorMatchingInlineSnapshot(`"oops"`);
116 });
117
118 test(".unwrapOr", () => {
@@ -126,5 +132,8 @@ describe("Result", () => {
132 `"Can't unwrap \`Ok\` to \`Err\`: 2"`
133 );
134 expect(addMax10(10, 10).unwrapErr()).toEqual("20 is too high");
135 + expect(() => {
136 + Ok(new CustomDummyError("oops")).unwrapErr();
137 + }).toThrowErrorMatchingInlineSnapshot(`"oops"`);
138 });
139 });
compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md
+1 -1
@@ -19,7 +19,7 @@ function f(reader) {
19 ## Error
20
21 ```
22 -TODO: Cannot declare variables in a value block, tried to declare 'value$0'
22 +[ReactForget] Todo: (CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare 'value$0'
23 ```
24
25
\ No newline at end of file