mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[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:
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user