diff --git a/compiler/packages/babel-plugin-react-forget/package.json b/compiler/packages/babel-plugin-react-forget/package.json index e70d614144..f0a773f44a 100644 --- a/compiler/packages/babel-plugin-react-forget/package.json +++ b/compiler/packages/babel-plugin-react-forget/package.json @@ -58,7 +58,7 @@ "babel-plugin-syntax-hermes-parser": "^0.15.1", "eslint": "8.27.0", "glob": "^7.1.6", - "hermes-parser": "^0.17.1", + "hermes-parser": "^0.18.2", "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", "prettier": "2.8.8", diff --git a/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Pipeline.ts index bf77ccba7c..498d1e06fa 100644 --- a/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Pipeline.ts @@ -8,7 +8,6 @@ import { NodePath } from "@babel/traverse"; import * as t from "@babel/types"; import prettyFormat from "pretty-format"; -import { lowerToForest } from "../Forest"; import { HIRFunction, ReactiveFunction, @@ -364,10 +363,6 @@ function* runWithEnvironment( validatePreservedManualMemoization(reactiveFunction); } - if (env.config.enableForest) { - yield* lowerToForest(reactiveFunction); - } - const ast = codegenFunction(reactiveFunction).unwrap(); yield log({ kind: "ast", name: "Codegen", value: ast }); diff --git a/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts index ce0d2c0875..7611944c3d 100644 --- a/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts @@ -14,8 +14,8 @@ import { } from "../CompilerError"; import { ExternalFunction, + parseEnvironmentConfig, tryParseExternalFunction, - validateEnvironmentConfig, } from "../HIR/Environment"; import { CodegenFunction } from "../ReactiveScopes"; import { isComponentDeclaration } from "../Utils/ComponentDeclaration"; @@ -67,12 +67,12 @@ function isConfigError(err: unknown): boolean { return false; } -type BabelFn = +export type BabelFn = | NodePath | NodePath | NodePath; -type CompileResult = { +export type CompileResult = { originalFn: BabelFn; compiledFn: CodegenFunction; }; @@ -115,7 +115,7 @@ function handleError( } } -function createNewFunctionNode( +export function createNewFunctionNode( originalFn: BabelFn, compiledFn: CodegenFunction ): t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression { @@ -182,6 +182,8 @@ export function compileProgram( pass: CompilerPass ): void { const options = parsePluginOptions(pass.opts); + const environment = parseEnvironmentConfig(pass.opts.environment ?? {}); + /* * Record lint errors and critical errors as depending on Forget's config, * we may still need to run Forget's analysis on every function (even if we @@ -224,7 +226,8 @@ export function compileProgram( * TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions * is validated */ - const config = validateEnvironmentConfig(pass.opts.environment ?? {}); + const config = environment.unwrap(); + compiledFn = compileFn(fn, config); pass.opts.logger?.logEvent(pass.filename, { kind: "CompileSuccess", diff --git a/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts index 05a0688836..0c93d30ead 100644 --- a/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts @@ -6,9 +6,10 @@ */ import * as t from "@babel/types"; -import { z } from "zod"; +import { ZodError, z } from "zod"; import { fromZodError } from "zod-validation-error"; import { CompilerError } from "../CompilerError"; +import { Err, Ok, Result } from "../Utils/Result"; import { log } from "../Utils/logger"; import { DEFAULT_GLOBALS, @@ -508,6 +509,17 @@ export function isHookName(name: string): boolean { return /^use[A-Z0-9]/.test(name); } +export function parseEnvironmentConfig( + partialConfig: PartialEnvironmentConfig +): Result> { + const config = EnvironmentConfigSchema.safeParse(partialConfig); + if (config.success) { + return Ok(config.data); + } else { + return Err(config.error); + } +} + export function validateEnvironmentConfig( partialConfig: PartialEnvironmentConfig ): EnvironmentConfig { diff --git a/compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts index 086aaf471b..9350369766 100644 --- a/compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts @@ -637,6 +637,7 @@ export type CallExpression = { callee: Place; args: Array; loc: SourceLocation; + typeArguments?: Array; }; /* @@ -712,7 +713,7 @@ export type InstructionValue = | MethodCall | { kind: "UnaryExpression"; - operator: string; + operator: t.UnaryExpression["operator"]; value: Place; loc: SourceLocation; } diff --git a/compiler/packages/babel-plugin-react-forget/src/HIR/visitors.ts b/compiler/packages/babel-plugin-react-forget/src/HIR/visitors.ts index 54007e5e09..55d2536b67 100644 --- a/compiler/packages/babel-plugin-react-forget/src/HIR/visitors.ts +++ b/compiler/packages/babel-plugin-react-forget/src/HIR/visitors.ts @@ -14,6 +14,7 @@ import { Pattern, Place, ReactiveInstruction, + ReactiveValue, SpreadPattern, Terminal, } from "./HIR"; @@ -24,20 +25,26 @@ export function* eachInstructionLValue( if (instr.lvalue !== null) { yield instr.lvalue; } - switch (instr.value.kind) { + yield* eachInstructionValueLValue(instr.value); +} + +export function* eachInstructionValueLValue( + value: ReactiveValue +): Iterable { + switch (value.kind) { case "DeclareLocal": case "DeclareContext": case "StoreLocal": { - yield instr.value.lvalue.place; + yield value.lvalue.place; break; } case "Destructure": { - yield* eachPatternOperand(instr.value.lvalue.pattern); + yield* eachPatternOperand(value.lvalue.pattern); break; } case "PostfixUpdate": case "PrefixUpdate": { - yield instr.value.lvalue; + yield value.lvalue; break; } } diff --git a/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts index 748cbbaaab..537730811d 100644 --- a/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -1164,6 +1164,17 @@ function codegenInstructionValue( break; } case "CallExpression": { + if (cx.env.config.enableForest) { + const callee = codegenPlaceToExpression(cx, instrValue.callee); + const args = instrValue.args.map((arg) => codegenArgument(cx, arg)); + value = t.callExpression(callee, args); + if (instrValue.typeArguments != null) { + value.typeArguments = t.typeParameterInstantiation( + instrValue.typeArguments + ); + } + break; + } const isHook = getHookKind(cx.env, instrValue.callee.identifier) != null; const callee = codegenPlaceToExpression(cx, instrValue.callee); const args = instrValue.args.map((arg) => codegenArgument(cx, arg)); diff --git a/compiler/packages/sprout/src/SproutTodoFilter.ts b/compiler/packages/sprout/src/SproutTodoFilter.ts index aadb901a88..02cbe97542 100644 --- a/compiler/packages/sprout/src/SproutTodoFilter.ts +++ b/compiler/packages/sprout/src/SproutTodoFilter.ts @@ -422,11 +422,12 @@ const skipFilter = new Set([ "readonly-object-method-calls-mutable-lambda", // TODO: 🌲 - "forest/forest-basic", - "forest/forest-basic-jsx", - "forest/forest-primitive-operations", - "forest/computed-load-props", - "forest/property-load-props", + "forest/forest-basic.flow", + "forest/forest-basic-jsx.flow", + "forest/forest-typing.flow", + "forest/forest-primitive-operations.flow", + "forest/computed-load-props.flow", + "forest/property-load-props.flow", // TODO: we probably want to always skip these "rules-of-hooks/rules-of-hooks-0592bd574811", @@ -519,7 +520,7 @@ const skipFilter = new Set([ "bug-jsx-memberexpr-tag-in-lambda", "bug-invalid-code-when-bailout", "component-syntax-ref-gating.flow", - + // 'react-forget-runtime' not yet supported "flag-enable-emit-hook-guards", ]); diff --git a/compiler/yarn.lock b/compiler/yarn.lock index b51d0106a5..fe6f783751 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -6711,6 +6711,11 @@ hermes-estree@0.17.1: resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.17.1.tgz#902806a900c185720424ffcf958027821d23c051" integrity sha512-EdUJms+eRE40OQxysFlPr1mPpvUbbMi7uDAKlScBw8o3tQY22BZ5yx56OYyp1bVaBm+7Cjc3NQz24sJEFXkPxg== +hermes-estree@0.18.2: + version "0.18.2" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.18.2.tgz#fd450fa1659cf074ceaa2ddeeb21674f3b2342f3" + integrity sha512-KoLsoWXJ5o81nit1wSyEZnWUGy9cBna9iYMZBR7skKh7okYAYKqQ9/OczwpMHn/cH0hKDyblulGsJ7FknlfVxQ== + hermes-parser@0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.14.0.tgz#edb2e7172fce996d2c8bbba250d140b70cc1aaaf" @@ -6732,6 +6737,13 @@ hermes-parser@0.17.1, hermes-parser@^0.17.1: dependencies: hermes-estree "0.17.1" +hermes-parser@^0.18.2: + version "0.18.2" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.18.2.tgz#50f15e2fcd559a48c68cd7af259d4292298bd14d" + integrity sha512-1eQfvib+VPpgBZ2zYKQhpuOjw1tH+Emuib6QmjkJWJMhyjM8xnXMvA+76o9LhF0zOAJDZgPfQhg43cyXEyl5Ew== + dependencies: + hermes-estree "0.18.2" + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"