From af686914d34057dd5558d7a8c1eccb50b39e7e21 Mon Sep 17 00:00:00 2001 From: Niklas Mollenhauer Date: Mon, 3 Jun 2024 18:15:51 +0200 Subject: [PATCH] feat(compiler): Support `import.meta` MetaProperty Resolves #29737 --- .../src/HIR/BuildHIR.ts | 15 +++++ .../src/HIR/HIR.ts | 6 ++ .../src/HIR/PrintHIR.ts | 4 ++ .../src/HIR/visitors.ts | 2 + .../src/Inference/InferReferenceEffects.ts | 1 + .../src/Optimization/DeadCodeElimination.ts | 1 + .../ReactiveScopes/CodegenReactiveFunction.ts | 7 ++ .../InferReactiveScopeVariables.ts | 1 + .../ReactiveScopes/PruneNonEscapingScopes.ts | 1 + .../src/TypeInference/InferTypes.ts | 1 + .../fixtures/compiler/meta-property.expect.md | 67 +++++++++++++++++++ .../fixtures/compiler/meta-property.mjs | 27 ++++++++ .../packages/snap/src/SproutTodoFilter.ts | 3 + compiler/packages/snap/src/fixture-utils.ts | 11 ++- 14 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.mjs diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 91f2fb8c7c12d..5a19efc8bad2e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -2427,6 +2427,21 @@ function lowerExpression( let expr = exprPath as NodePath; return lowerExpression(builder, expr.get("expression")); } + case "MetaProperty": { + let expr = exprPath as NodePath; + if ( + expr.node.meta.name === "import" && + expr.node.property.name === "meta" + ) { + return { + kind: "MetaProperty", + meta: expr.node.meta.name, + property: expr.node.property.name, + loc: expr.node.loc ?? GeneratedSource, + }; + } + return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc }; + } default: { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index afa0799b40d26..6d2b45ac30eed 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -898,6 +898,12 @@ export type InstructionValue = flags: string; loc: SourceLocation; } + | { + kind: "MetaProperty"; + meta: string; + property: string; + loc: SourceLocation; + } // store `object.property = value` | { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index b0a6fb1635b00..5e1be135b76f1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -636,6 +636,10 @@ export function printInstructionValue(instrValue: ReactiveValue): string { value = `RegExp /${instrValue.pattern}/${instrValue.flags}`; break; } + case "MetaProperty": { + value = `MetaProperty ${instrValue.meta}.${instrValue.property}`; + break; + } case "Await": { value = `Await ${printPlace(instrValue.value)}`; break; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts index aaf3ffc4c5379..14c158bb109a1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts @@ -242,6 +242,7 @@ export function* eachInstructionValueOperand( } case "Debugger": case "RegExpLiteral": + case "MetaProperty": case "LoadGlobal": case "UnsupportedNode": case "Primitive": @@ -566,6 +567,7 @@ export function mapInstructionValueOperands( } case "Debugger": case "RegExpLiteral": + case "MetaProperty": case "LoadGlobal": case "UnsupportedNode": case "Primitive": diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts index 19c320b05dfcf..1a2c693681e01 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts @@ -1216,6 +1216,7 @@ function inferBlock( }; break; } + case "MetaProperty": case "LoadGlobal": valueKind = { kind: ValueKind.Global, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts index 8bd6b68078898..ea6cc730258d0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts @@ -350,6 +350,7 @@ function pruneableValue(value: InstructionValue, state: State): boolean { return false; } case "RegExpLiteral": + case "MetaProperty": case "LoadGlobal": case "ArrayExpression": case "BinaryExpression": diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index f43cae083176a..87187311cb4a7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -2021,6 +2021,13 @@ function codegenInstructionValue( value = t.regExpLiteral(instrValue.pattern, instrValue.flags); break; } + case "MetaProperty": { + value = t.metaProperty( + t.identifier(instrValue.meta), + t.identifier(instrValue.property) + ); + break; + } case "Await": { value = t.awaitExpression(codegenPlaceToExpression(cx, instrValue.value)); break; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts index 833b784f0d139..2c9e67646b155 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts @@ -199,6 +199,7 @@ function mayAllocate(env: Environment, instruction: Instruction): boolean { case "DeclareContext": case "StoreLocal": case "LoadGlobal": + case "MetaProperty": case "TypeCastExpression": case "LoadLocal": case "LoadContext": diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts index cfa3700f81ea3..0f5d563eb9514 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts @@ -459,6 +459,7 @@ function computeMemoizationInputs( case "ComputedDelete": case "PropertyDelete": case "LoadGlobal": + case "MetaProperty": case "TemplateLiteral": case "Primitive": case "JSXText": diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index be6004dad7aee..b26dea5a428b4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -338,6 +338,7 @@ function* generateInstructionTypes( case "DeclareLocal": case "NewExpression": case "RegExpLiteral": + case "MetaProperty": case "PropertyStore": case "ComputedStore": case "ComputedLoad": diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.expect.md new file mode 100644 index 0000000000000..32de57f8a053b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.expect.md @@ -0,0 +1,67 @@ + +## Input + +```javascript +function a() { + return import.meta.url; +} + +function b() { + let a = 0; + if (import.meta.url) { + a = 1; + } + return a; +} + +function c() { + let a = 0; + if (import.meta.foo) { + a = 1; + } + return a; +} + +function d() { + let a = 0; + if (import.meta) { + a = 1; + } + return a; +} + +``` + +## Code + +```javascript +function a() { + return import.meta.url; +} + +function b() { + let a = 0; + if (import.meta.url) { + a = 1; + } + return a; +} + +function c() { + let a = 0; + if (import.meta.foo) { + a = 1; + } + return a; +} + +function d() { + let a = 0; + if (import.meta) { + a = 1; + } + return a; +} + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.mjs b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.mjs new file mode 100644 index 0000000000000..3f387b2699f1e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-property.mjs @@ -0,0 +1,27 @@ +function a() { + return import.meta.url; +} + +function b() { + let a = 0; + if (import.meta.url) { + a = 1; + } + return a; +} + +function c() { + let a = 0; + if (import.meta.foo) { + a = 1; + } + return a; +} + +function d() { + let a = 0; + if (import.meta) { + a = 1; + } + return a; +} diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 0bfa03c3971e5..eb853b5769924 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -499,6 +499,9 @@ const skipFilter = new Set([ "useState-unpruned-dependency", "useState-and-other-hook-unpruned-dependency", "change-detect-reassign", + + // needs to be executed as a module + "meta-property", ]); export default skipFilter; diff --git a/compiler/packages/snap/src/fixture-utils.ts b/compiler/packages/snap/src/fixture-utils.ts index 9d3af50b4b2c4..fcea8ec2e1fe0 100644 --- a/compiler/packages/snap/src/fixture-utils.ts +++ b/compiler/packages/snap/src/fixture-utils.ts @@ -10,7 +10,16 @@ import * as glob from "glob"; import path from "path"; import { FILTER_PATH, FIXTURES_PATH, SNAPSHOT_EXTENSION } from "./constants"; -const INPUT_EXTENSIONS = [".js", ".cjs", ".mjs", ".ts", ".cts", ".mts", ".jsx", ".tsx"]; +const INPUT_EXTENSIONS = [ + ".js", + ".cjs", + ".mjs", + ".ts", + ".cts", + ".mts", + ".jsx", + ".tsx", +]; export type TestFilter = { debug: boolean;