@samitouri / QOS-React-2 / commits / 6f9c9cf9ea

[hir] Make lambdas dependencies be a list of Places

This lets HIR understand and rename dependencies correctly.

Sathya Gunasekaran committed Jan 10, 2023 at 16:06 UTC 6f9c9cf9ea037829b4da4bc419a877e3fc8b7d4a
6 files changed +87 -9
compiler/forget/src/HIR/BuildHIR.ts
+15 -5
@@ -1152,7 +1152,11 @@ function lowerExpression(
1152 const expr = exprPath as NodePath<t.FunctionExpression>;
1153 const name: string | null = expr.get("id")?.node?.name ?? null;
1154 const componentScope: Scope = expr.scope.parent.getFunctionParent()!;
1155 - const dependencies = gatherCapturedDeps(expr, componentScope);
1155 + const dependencies: Array<Place> = gatherCapturedDeps(
1156 + builder,
1157 + expr,
1158 + componentScope
1159 + );
1160 const body = expr.get("body").node;
1161 const params: Array<string> = expr.get("params").map((p) => {
1162 todoInvariant(p.isIdentifier(), "handle non identifier params");
@@ -1562,10 +1566,11 @@ function capturePureScopes(
1566 }
1567
1568 function gatherCapturedDeps(
1569 + builder: HIRBuilder,
1570 fn: NodePath<t.FunctionExpression>,
1571 componentScope: Scope
1567 -): Set<t.Identifier> {
1568 - const captured: Set<t.Identifier> = new Set();
1572 +): Array<Place> {
1573 + const captured: Set<Place> = new Set();
1574
1575 // Capture all the scopes from the parent of this function up to and including
1576 // the component scope.
@@ -1587,9 +1592,14 @@ function gatherCapturedDeps(
1592 return;
1593 }
1594
1590 - captured.add(binding.identifier);
1595 + captured.add({
1596 + kind: "Identifier",
1597 + identifier: builder.resolveIdentifier(binding.identifier),
1598 + effect: Effect.Unknown,
1599 + loc: id.node.loc!,
1600 + });
1601 },
1602 });
1603
1594 - return captured;
1604 + return [...captured];
1605 }
compiler/forget/src/HIR/HIR.ts
+1 -1
@@ -313,7 +313,7 @@ export type InstructionData =
313 kind: "FunctionExpression";
314 name: string | null;
315 params: Array<string>;
316 - dependencies: Set<t.Identifier>;
316 + dependencies: Array<Place>;
317 body: t.BlockStatement;
318 }
319
compiler/forget/src/HIR/PrintHIR.ts
+3 -1
@@ -293,7 +293,9 @@ export function printInstructionValue(instrValue: InstructionValue): string {
293 case "FunctionExpression": {
294 const params = instrValue.params.join(",");
295 const body = generate(instrValue.body).code;
296 - const deps = [...instrValue.dependencies].map((i) => i.name).join(",");
296 + const deps = instrValue.dependencies
297 + .map((i) => printIdentifier(i.identifier))
298 + .join(",");
299 value = `Function ${instrValue.name ?? ""} @deps[${deps}] (${
300 params ?? ""
301 }){${body}}`;
compiler/forget/src/HIR/visitors.ts
+8 -2
@@ -87,9 +87,12 @@ export function* eachInstructionValueOperand(
87 yield* instrValue.elements;
88 break;
89 }
90 + case "FunctionExpression": {
91 + yield* instrValue.dependencies;
92 + break;
93 + }
94 case "OtherStatement":
95 case "Primitive":
92 - case "FunctionExpression":
96 case "JSXText": {
97 break;
98 }
@@ -174,9 +177,12 @@ export function mapInstructionOperands(
177 instrValue.children = instrValue.children.map((e) => fn(e));
178 break;
179 }
180 + case "FunctionExpression": {
181 + instrValue.dependencies = instrValue.dependencies.map((d) => fn(d));
182 + break;
183 + }
184 case "OtherStatement":
185 case "Primitive":
179 - case "FunctionExpression":
186 case "JSXText": {
187 break;
188 }
compiler/forget/src/__tests__/fixtures/hir/prop-capturing-function-1.expect.md new
+53
@@ -0,0 +1,53 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a, b) {
6 + let z = { a, b };
7 + let x = function () {
8 + z;
9 + };
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## Code
16 +
17 +```javascript
18 +function component(a, b) {
19 + const $ = React.useMemoCache();
20 + const c_0 = $[0] !== a;
21 + const c_1 = $[1] !== b;
22 + let z;
23 + if (c_0 || c_1) {
24 + z = {
25 + a: a,
26 + b: b,
27 + };
28 + $[0] = a;
29 + $[1] = b;
30 + $[2] = z;
31 + } else {
32 + z = $[2];
33 + }
34 +
35 + const c_3 = $[3] !== z;
36 + let x;
37 +
38 + if (c_3) {
39 + x = function () {
40 + z;
41 + };
42 +
43 + $[3] = z;
44 + $[4] = x;
45 + } else {
46 + x = $[4];
47 + }
48 +
49 + return x;
50 +}
51 +
52 +```
53 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/prop-capturing-function-1.js new
+7
@@ -0,0 +1,7 @@
1 +function component(a, b) {
2 + let z = { a, b };
3 + let x = function () {
4 + z;
5 + };
6 + return x;
7 +}