@samitouri / QOS-React / commits / 24ea3fa4bc

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 +}