Support JSX fragments (#736)

* handle jsx fragments

* update effects for jsx fragments
This commit is contained in:
Joseph Savona
2022-11-04 11:16:50 -07:00
parent 871a171a1f
commit 24ea3fa4bc
8 changed files with 97 additions and 1 deletions
+12 -1
View File
@@ -957,6 +957,17 @@ function lowerExpression(
loc: exprLoc,
};
}
case "JSXFragment": {
const expr = exprPath as NodePath<t.JSXFragment>;
const children = expr
.get("children")
.map((child) => lowerJsxElement(builder, child));
return {
kind: "JsxFragment",
children,
loc: exprLoc,
};
}
default: {
todo(`lowerExpression(${exprNode.type})`);
// assertExhaustive(
@@ -1082,7 +1093,7 @@ function lowerJsxElement(
): Place {
const exprNode = exprPath.node;
const exprLoc = exprNode.loc ?? GeneratedSource;
if (exprPath.isJSXElement()) {
if (exprPath.isJSXElement() || exprPath.isJSXFragment()) {
return lowerExpressionToPlace(builder, exprPath);
} else if (exprPath.isJSXExpressionContainer()) {
const expression = exprPath.get("expression");
+8
View File
@@ -247,6 +247,14 @@ function writeInstr(cx: Context, instr: Instruction, body: Array<t.Statement>) {
);
break;
}
case "JsxFragment": {
value = t.jsxFragment(
t.jsxOpeningFragment(),
t.jsxClosingFragment(),
instrValue.children.map((child) => codegenJsxElement(cx, child))
);
break;
}
case "OtherStatement": {
const node = instrValue.node;
if (t.isStatement(node)) {
+1
View File
@@ -207,6 +207,7 @@ export type InstructionData =
properties: Map<string, Place> | null; // null === empty object
}
| { kind: "ArrayExpression"; elements: Array<Place> }
| { kind: "JsxFragment"; children: Array<Place> }
/**
* Catch-all for statements such as type imports, nested class declarations, etc
@@ -574,6 +574,13 @@ function inferBlock(env: Environment, block: BasicBlock) {
}
break;
}
case "JsxFragment": {
valueKind = ValueKind.Frozen;
for (const child of instrValue.children) {
env.reference(child, Effect.Freeze);
}
break;
}
case "JSXText":
case "Primitive": {
valueKind = ValueKind.Immutable;
+6
View File
@@ -215,6 +215,12 @@ function printInstructionValue(instrValue: InstructionValue): string {
}
break;
}
case "JsxFragment": {
value = `JsxFragment [${instrValue.children
.map((child) => printPlace(child))
.join(", ")}]`;
break;
}
case "NewExpression": {
value = `New ${printPlace(instrValue.callee)}(${instrValue.args
.map((arg) => printPlace(arg))
+4
View File
@@ -344,6 +344,10 @@ function rewriteUses(instr: Instruction, builder: SSABuilder) {
instrValue.elements = instrValue.elements.map((e) => builder.getPlace(e));
break;
}
case "JsxFragment": {
instrValue.children = instrValue.children.map((e) => builder.getPlace(e));
break;
}
case "OtherStatement":
case "Primitive":
case "JSXText": {
@@ -0,0 +1,49 @@
## Input
```javascript
function Foo(props) {
return (
<>
Hello {props.greeting}{" "}
<div>
<>Text</>
</div>
</>
);
}
```
## HIR
```
bb0:
Const mutate $14 = "\n Hello "
Const mutate $15 = " "
Const mutate $16 = "\n "
Const mutate $17 = "div"
Const mutate $18 = "\n "
Const mutate $19 = "Text"
Const mutate $20 = JsxFragment [read $19]
Const mutate $21 = "\n "
Const mutate $22 = JSX <read $17>{read $18}{read $20}{read $21}</read $17>
Const mutate $23 = "\n "
Const mutate $24 = JsxFragment [read $14, read props$13.greeting, read $15, read $16, read $22, read $23]
Return read $24
```
## Code
```javascript
function Foo$0(props$13) {
return (
<>
Hello {props$13.greeting}
{<div>{<>Text</>}</div>}
</>
);
}
```
@@ -0,0 +1,10 @@
function Foo(props) {
return (
<>
Hello {props.greeting}{" "}
<div>
<>Text</>
</div>
</>
);
}