[hir] Strip JSXEmptyExpression syntax

`JSXEmptyExpression` is never added to a React element's children [in 
`react.buildChildren`](https://github.com/babel/babel/blob/main/packages/babel-types/src/builders/react/buildChildren.ts), 
which is [used 
by](https://github.com/babel/babel/blob/main/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts#L649) 
`plugin-transform-react-jsx`]. 

An alternative would be to represent JSX expressions differently in HIR, then 
codegen `JSXEmptyExpression`s back when we encounter an `EmptyExpression` 

```js 

-   children: Array<Place>, 

-   children: Array<Place | "EmptyExpression">, 

``` 

(We could also retain `JSXEmptyExpression` as an `InstructionValue` that 
produces a Primitive. However, this would make babel types in Codegen a bit more 
messy, as `JSXEmptyExpression` does not extend `Expression` (which currently is 
the result of every `InstructionValue`).)
This commit is contained in:
mofeiZ
2023-03-27 18:12:18 -04:00
parent 43176b129e
commit ec0abcd643
4 changed files with 61 additions and 27 deletions
+19 -18
View File
@@ -1352,9 +1352,10 @@ function lowerExpression(
const expr = exprPath as NodePath<t.JSXElement>;
const opening = expr.get("openingElement");
const tag = lowerJsxElementName(builder, opening.get("name"));
const children = expr
const children: Array<Place> = expr
.get("children")
.map((child) => lowerJsxElement(builder, child));
.map((child) => lowerJsxElement(builder, child))
.filter(notNull);
const props: Array<JsxAttribute> = [];
for (const attribute of opening.get("attributes")) {
if (attribute.isJSXSpreadAttribute()) {
@@ -1426,9 +1427,10 @@ function lowerExpression(
}
case "JSXFragment": {
const expr = exprPath as NodePath<t.JSXFragment>;
const children = expr
const children: Array<Place> = expr
.get("children")
.map((child) => lowerJsxElement(builder, child));
.map((child) => lowerJsxElement(builder, child))
.filter(notNull);
return {
kind: "JsxFragment",
children,
@@ -1950,27 +1952,22 @@ function lowerJsxElement(
| t.JSXElement
| t.JSXFragment
>
): Place {
): Place | null {
const exprNode = exprPath.node;
const exprLoc = exprNode.loc ?? GeneratedSource;
if (exprPath.isJSXElement() || exprPath.isJSXFragment()) {
return lowerExpressionToTemporary(builder, exprPath);
} else if (exprPath.isJSXExpressionContainer()) {
const expression = exprPath.get("expression");
if (!expression.isExpression()) {
builder.errors.push({
reason: `(BuildHIR::lowerJsxElement) Handle ${expression.type} expressions`,
severity: ErrorSeverity.Todo,
nodePath: expression,
});
const place = lowerValueToTemporary(builder, {
kind: "UnsupportedNode",
node: exprNode,
loc: exprLoc,
});
return { ...place };
if (expression.isJSXEmptyExpression()) {
return null;
} else {
invariant(
expression.isExpression(),
`(BuildHIR::lowerJsxElement) Expected Expression but found ${expression.type}!`
);
return lowerExpressionToTemporary(builder, expression);
}
return lowerExpressionToTemporary(builder, expression);
} else if (exprPath.isJSXText()) {
const place = lowerValueToTemporary(builder, {
kind: "JSXText",
@@ -2465,3 +2462,7 @@ function gatherCapturedDeps(
return { identifiers: [...capturedIds], refs: [...capturedRefs] };
}
function notNull<T>(value: T | null): value is T {
return value !== null;
}
@@ -120,15 +120,6 @@ let moduleLocal = false;
14 |
15 | <Button haha={1}></Button>;
[ReactForget] TodoError: (BuildHIR::lowerJsxElement) Handle JSXEmptyExpression expressions
14 |
15 | <Button haha={1}></Button>;
> 16 | <Button>{/** empty */}</Button>;
| ^^^^^^^^^^^^
17 |
18 | const j = function bar([quz, qux], ...args) {};
19 |
[ReactForget] TodoError: (BuildHIR::lower) Handle RestElement params
16 | <Button>{/** empty */}</Button>;
17 |
@@ -0,0 +1,34 @@
## Input
```javascript
export function Component(props) {
return (
<div>
{}
{props.a}
</div>
);
}
```
## Code
```javascript
export function Component(props) {
const $ = React.unstable_useMemoCache(2);
const c_0 = $[0] !== props.a;
let t0;
if (c_0) {
t0 = <div>{props.a}</div>;
$[0] = props.a;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
@@ -0,0 +1,8 @@
export function Component(props) {
return (
<div>
{}
{props.a}
</div>
);
}