Support JSX fragments (#736)
* handle jsx fragments * update effects for jsx fragments
Joseph Savona committed
Nov 4, 2022 at 11:16 UTC
24ea3fa4bcd7becafab5858a3ef83586ac9fd4f6
8 files changed
+97
-1
compiler/forget/src/HIR/BuildHIR.ts
+12
-1
@@ -957,6 +957,17 @@ function lowerExpression(
957
loc: exprLoc,
958
};
959
}
960
+ case "JSXFragment": {
961
+ const expr = exprPath as NodePath<t.JSXFragment>;
962
+ const children = expr
963
+ .get("children")
964
+ .map((child) => lowerJsxElement(builder, child));
965
+ return {
966
+ kind: "JsxFragment",
967
+ children,
968
+ loc: exprLoc,
969
+ };
970
+ }
971
default: {
972
todo(`lowerExpression(${exprNode.type})`);
973
// assertExhaustive(
@@ -1082,7 +1093,7 @@ function lowerJsxElement(
1093
): Place {
1094
const exprNode = exprPath.node;
1095
const exprLoc = exprNode.loc ?? GeneratedSource;
1085
- if (exprPath.isJSXElement()) {
1096
+ if (exprPath.isJSXElement() || exprPath.isJSXFragment()) {
1097
return lowerExpressionToPlace(builder, exprPath);
1098
} else if (exprPath.isJSXExpressionContainer()) {
1099
const expression = exprPath.get("expression");
compiler/forget/src/HIR/Codegen.ts
+8
@@ -247,6 +247,14 @@ function writeInstr(cx: Context, instr: Instruction, body: Array<t.Statement>) {
247
);
248
break;
249
}
250
+ case "JsxFragment": {
251
+ value = t.jsxFragment(
252
+ t.jsxOpeningFragment(),
253
+ t.jsxClosingFragment(),
254
+ instrValue.children.map((child) => codegenJsxElement(cx, child))
255
+ );
256
+ break;
257
+ }
258
case "OtherStatement": {
259
const node = instrValue.node;
260
if (t.isStatement(node)) {
compiler/forget/src/HIR/HIR.ts
+1
@@ -207,6 +207,7 @@ export type InstructionData =
207
properties: Map<string, Place> | null; // null === empty object
208
}
209
| { kind: "ArrayExpression"; elements: Array<Place> }
210
+ | { kind: "JsxFragment"; children: Array<Place> }
211
212
/**
213
* Catch-all for statements such as type imports, nested class declarations, etc
compiler/forget/src/HIR/InferReferenceEffects.ts
+7
@@ -574,6 +574,13 @@ function inferBlock(env: Environment, block: BasicBlock) {
574
}
575
break;
576
}
577
+ case "JsxFragment": {
578
+ valueKind = ValueKind.Frozen;
579
+ for (const child of instrValue.children) {
580
+ env.reference(child, Effect.Freeze);
581
+ }
582
+ break;
583
+ }
584
case "JSXText":
585
case "Primitive": {
586
valueKind = ValueKind.Immutable;
compiler/forget/src/HIR/PrintHIR.ts
+6
@@ -215,6 +215,12 @@ function printInstructionValue(instrValue: InstructionValue): string {
215
}
216
break;
217
}
218
+ case "JsxFragment": {
219
+ value = `JsxFragment [${instrValue.children
220
+ .map((child) => printPlace(child))
221
+ .join(", ")}]`;
222
+ break;
223
+ }
224
case "NewExpression": {
225
value = `New ${printPlace(instrValue.callee)}(${instrValue.args
226
.map((arg) => printPlace(arg))
compiler/forget/src/HIR/SSAify.ts
+4
@@ -344,6 +344,10 @@ function rewriteUses(instr: Instruction, builder: SSABuilder) {
344
instrValue.elements = instrValue.elements.map((e) => builder.getPlace(e));
345
break;
346
}
347
+ case "JsxFragment": {
348
+ instrValue.children = instrValue.children.map((e) => builder.getPlace(e));
349
+ break;
350
+ }
351
case "OtherStatement":
352
case "Primitive":
353
case "JSXText": {
compiler/forget/src/__tests__/fixtures/hir/jsx-fragment.expect.md
new
+49
@@ -0,0 +1,49 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Foo(props) {
6
+ return (
7
+ <>
8
+ Hello {props.greeting}{" "}
9
+ <div>
10
+ <>Text</>
11
+ </div>
12
+ </>
13
+ );
14
+}
15
+
16
+```
17
+
18
+## HIR
19
+
20
+```
21
+bb0:
22
+ Const mutate $14 = "\n Hello "
23
+ Const mutate $15 = " "
24
+ Const mutate $16 = "\n "
25
+ Const mutate $17 = "div"
26
+ Const mutate $18 = "\n "
27
+ Const mutate $19 = "Text"
28
+ Const mutate $20 = JsxFragment [read $19]
29
+ Const mutate $21 = "\n "
30
+ Const mutate $22 = JSX <read $17>{read $18}{read $20}{read $21}</read $17>
31
+ Const mutate $23 = "\n "
32
+ Const mutate $24 = JsxFragment [read $14, read props$13.greeting, read $15, read $16, read $22, read $23]
33
+ Return read $24
34
+```
35
+
36
+## Code
37
+
38
+```javascript
39
+function Foo$0(props$13) {
40
+ return (
41
+ <>
42
+ Hello {props$13.greeting}
43
+ {<div>{<>Text</>}</div>}
44
+ </>
45
+ );
46
+}
47
+
48
+```
49
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/jsx-fragment.js
new
+10
@@ -0,0 +1,10 @@
1
+function Foo(props) {
2
+ return (
3
+ <>
4
+ Hello {props.greeting}{" "}
5
+ <div>
6
+ <>Text</>
7
+ </div>
8
+ </>
9
+ );
10
+}