From 4c2e457c7c820e5b4bc895735a703cdbf40f3175 Mon Sep 17 00:00:00 2001 From: "Henry Q. Dineen" Date: Wed, 22 May 2024 18:42:06 -0400 Subject: [PATCH] compiler: Handle TSNonNullAssertion expressions (#29218) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary We ran React compiler against part of our codebase and collected compiler errors. One of the more common non-actionable errors is caused by usage of the `!` TypeScript non-null assertion operation: ``` (BuildHIR::lowerExpression) Handle TSNonNullExpression expressions ``` It seems like React Compiler _should_ be able to support this by just ignoring the syntax and using the underlying expression. I'm sure a lot of our non-null assertion usage should not exist and I understand if React Compiler does not want to support this syntax. It wasn't obvious to me if this omission was intentional or if there are future plans to use `TSNonNullExpression` as part of the compiler's analysis. If there are no future plans it seems like just ignoring it should be fine. ## How did you test this change? ```sh ❯ yarn snap --filter yarn run v1.17.3 $ yarn workspace babel-plugin-react-compiler run snap --filter $ node ../snap/dist/main.js --filter PASS non-null-assertion 1 Tests, 1 Passed, 0 Failed ``` --- .../src/HIR/BuildHIR.ts | 4 ++ .../compiler/non-null-assertion.expect.md | 49 +++++++++++++++++++ .../fixtures/compiler/non-null-assertion.ts | 12 +++++ 3 files changed, 65 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.ts 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 d33bfb2694..b42f3daba1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -2407,6 +2407,10 @@ function lowerExpression( loc: expr.node.loc ?? GeneratedSource, }; } + case "TSNonNullExpression": { + let expr = exprPath as NodePath; + return lowerExpression(builder, expr.get("expression")); + } default: { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.expect.md new file mode 100644 index 0000000000..11b8e50c6d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.expect.md @@ -0,0 +1,49 @@ + +## Input + +```javascript +interface ComponentProps { + name?: string; +} + +function Component(props: ComponentProps) { + return props.name!.toUpperCase(); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ name: "Alice" }], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +interface ComponentProps { + name?: string; +} + +function Component(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.name) { + t0 = props.name.toUpperCase(); + $[0] = props.name; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ name: "Alice" }], +}; + +``` + +### Eval output +(kind: ok) "ALICE" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.ts new file mode 100644 index 0000000000..986b9a9a47 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/non-null-assertion.ts @@ -0,0 +1,12 @@ +interface ComponentProps { + name?: string; +} + +function Component(props: ComponentProps) { + return props.name!.toUpperCase(); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ name: "Alice" }], +};