@samitouri / QOS-React-2 / commits / f42c51b971

[λ] Support member expressions in lambdas

Lower member expression if the receiver is in scope. Skip the remaining path before capturing so we don't recurse down the identifiers in the member expression.

Sathya Gunasekaran committed Jan 19, 2023 at 12:13 UTC f42c51b9718aa767eb3d863f866938d0a13ad74e
9 files changed +281 -3
compiler/forget/src/HIR/BuildHIR.ts
+8 -3
@@ -1665,16 +1665,21 @@ function gatherCapturedDeps(
1665
1666 fn.get("body").traverse({
1667 Expression(path) {
1668 - // TODO(gsn): Handle member expressions
1669 - if (!path.isIdentifier()) {
1668 + let obj = path;
1669 + while (obj.isMemberExpression()) {
1670 + obj = obj.get("object");
1671 + }
1672 +
1673 + if (!obj.isIdentifier()) {
1674 return;
1675 }
1676
1673 - const binding = path.scope.getBinding(path.node.name);
1677 + const binding = obj.scope.getBinding(obj.node.name);
1678 if (binding === undefined || !pureScopes.has(binding.scope)) {
1679 return;
1680 }
1681
1682 + path.skip();
1683 captured.add(lowerExpressionToPlace(builder, path));
1684 },
1685 });
compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.expect.md new
+50
@@ -0,0 +1,50 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a) {
6 + let z = { a };
7 + let x = function () {
8 + z.a;
9 + };
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## Code
16 +
17 +```javascript
18 +function component(a) {
19 + const $ = React.useMemoCache();
20 + const c_0 = $[0] !== a;
21 + let z;
22 + if (c_0) {
23 + z = {
24 + a: a,
25 + };
26 + $[0] = a;
27 + $[1] = z;
28 + } else {
29 + z = $[1];
30 + }
31 +
32 + const c_2 = $[2] !== z.a;
33 + let x;
34 +
35 + if (c_2) {
36 + x = function () {
37 + z.a;
38 + };
39 +
40 + $[2] = z.a;
41 + $[3] = x;
42 + } else {
43 + x = $[3];
44 + }
45 +
46 + return x;
47 +}
48 +
49 +```
50 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.js new
+7
@@ -0,0 +1,7 @@
1 +function component(a) {
2 + let z = { a };
3 + let x = function () {
4 + z.a;
5 + };
6 + return x;
7 +}
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.expect.md new
+63
@@ -0,0 +1,63 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a) {
6 + let z = { a: { a } };
7 + let x = function () {
8 + z.a.a();
9 + };
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## Code
16 +
17 +```javascript
18 +function component(a) {
19 + const $ = React.useMemoCache();
20 + const c_0 = $[0] !== a;
21 + let t1;
22 + if (c_0) {
23 + t1 = {
24 + a: a,
25 + };
26 + $[0] = a;
27 + $[1] = t1;
28 + } else {
29 + t1 = $[1];
30 + }
31 +
32 + const c_2 = $[2] !== t1;
33 + let z;
34 +
35 + if (c_2) {
36 + z = {
37 + a: t1,
38 + };
39 + $[2] = t1;
40 + $[3] = z;
41 + } else {
42 + z = $[3];
43 + }
44 +
45 + const c_4 = $[4] !== z.a.a;
46 + let x;
47 +
48 + if (c_4) {
49 + x = function () {
50 + z.a.a();
51 + };
52 +
53 + $[4] = z.a.a;
54 + $[5] = x;
55 + } else {
56 + x = $[5];
57 + }
58 +
59 + return x;
60 +}
61 +
62 +```
63 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.js new
+7
@@ -0,0 +1,7 @@
1 +function component(a) {
2 + let z = { a: { a } };
3 + let x = function () {
4 + z.a.a();
5 + };
6 + return x;
7 +}
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.expect.md new
+67
@@ -0,0 +1,67 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a) {
6 + let z = { a: { a } };
7 + let x = function () {
8 + (function () {
9 + z.a.a;
10 + })();
11 + };
12 + return x;
13 +}
14 +
15 +```
16 +
17 +## Code
18 +
19 +```javascript
20 +function component(a) {
21 + const $ = React.useMemoCache();
22 + const c_0 = $[0] !== a;
23 + let t1;
24 + if (c_0) {
25 + t1 = {
26 + a: a,
27 + };
28 + $[0] = a;
29 + $[1] = t1;
30 + } else {
31 + t1 = $[1];
32 + }
33 +
34 + const c_2 = $[2] !== t1;
35 + let z;
36 +
37 + if (c_2) {
38 + z = {
39 + a: t1,
40 + };
41 + $[2] = t1;
42 + $[3] = z;
43 + } else {
44 + z = $[3];
45 + }
46 +
47 + const c_4 = $[4] !== z.a.a;
48 + let x;
49 +
50 + if (c_4) {
51 + x = function () {
52 + (function () {
53 + z.a.a;
54 + })();
55 + };
56 +
57 + $[4] = z.a.a;
58 + $[5] = x;
59 + } else {
60 + x = $[5];
61 + }
62 +
63 + return x;
64 +}
65 +
66 +```
67 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.js new
+9
@@ -0,0 +1,9 @@
1 +function component(a) {
2 + let z = { a: { a } };
3 + let x = function () {
4 + (function () {
5 + z.a.a;
6 + })();
7 + };
8 + return x;
9 +}
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.expect.md new
+63
@@ -0,0 +1,63 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a) {
6 + let z = { a: { a } };
7 + let x = function () {
8 + z.a.a;
9 + };
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## Code
16 +
17 +```javascript
18 +function component(a) {
19 + const $ = React.useMemoCache();
20 + const c_0 = $[0] !== a;
21 + let t1;
22 + if (c_0) {
23 + t1 = {
24 + a: a,
25 + };
26 + $[0] = a;
27 + $[1] = t1;
28 + } else {
29 + t1 = $[1];
30 + }
31 +
32 + const c_2 = $[2] !== t1;
33 + let z;
34 +
35 + if (c_2) {
36 + z = {
37 + a: t1,
38 + };
39 + $[2] = t1;
40 + $[3] = z;
41 + } else {
42 + z = $[3];
43 + }
44 +
45 + const c_4 = $[4] !== z.a.a;
46 + let x;
47 +
48 + if (c_4) {
49 + x = function () {
50 + z.a.a;
51 + };
52 +
53 + $[4] = z.a.a;
54 + $[5] = x;
55 + } else {
56 + x = $[5];
57 + }
58 +
59 + return x;
60 +}
61 +
62 +```
63 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.js new
+7
@@ -0,0 +1,7 @@
1 +function component(a) {
2 + let z = { a: { a } };
3 + let x = function () {
4 + z.a.a;
5 + };
6 + return x;
7 +}