From f42c51b9718aa767eb3d863f866938d0a13ad74e Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Thu, 19 Jan 2023 12:13:35 +0000 Subject: [PATCH] =?UTF-8?q?[=CE=BB]=20Support=20member=20expressions=20in?= =?UTF-8?q?=20lambdas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- compiler/forget/src/HIR/BuildHIR.ts | 11 ++- .../hir/capturing-member-expr.expect.md | 50 ++++++++++++++ .../fixtures/hir/capturing-member-expr.js | 7 ++ .../capturing-nested-member-call.expect.md | 63 +++++++++++++++++ .../hir/capturing-nested-member-call.js | 7 ++ ...ested-member-expr-in-nested-func.expect.md | 67 +++++++++++++++++++ ...uring-nested-member-expr-in-nested-func.js | 9 +++ .../capturing-nested-member-expr.expect.md | 63 +++++++++++++++++ .../hir/capturing-nested-member-expr.js | 7 ++ 9 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.js diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index 3929663165..1d2b9da47a 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -1665,16 +1665,21 @@ function gatherCapturedDeps( fn.get("body").traverse({ Expression(path) { - // TODO(gsn): Handle member expressions - if (!path.isIdentifier()) { + let obj = path; + while (obj.isMemberExpression()) { + obj = obj.get("object"); + } + + if (!obj.isIdentifier()) { return; } - const binding = path.scope.getBinding(path.node.name); + const binding = obj.scope.getBinding(obj.node.name); if (binding === undefined || !pureScopes.has(binding.scope)) { return; } + path.skip(); captured.add(lowerExpressionToPlace(builder, path)); }, }); diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.expect.md new file mode 100644 index 0000000000..30973ce532 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +function component(a) { + let z = { a }; + let x = function () { + z.a; + }; + return x; +} + +``` + +## Code + +```javascript +function component(a) { + const $ = React.useMemoCache(); + const c_0 = $[0] !== a; + let z; + if (c_0) { + z = { + a: a, + }; + $[0] = a; + $[1] = z; + } else { + z = $[1]; + } + + const c_2 = $[2] !== z.a; + let x; + + if (c_2) { + x = function () { + z.a; + }; + + $[2] = z.a; + $[3] = x; + } else { + x = $[3]; + } + + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.js new file mode 100644 index 0000000000..e445e9adac --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-member-expr.js @@ -0,0 +1,7 @@ +function component(a) { + let z = { a }; + let x = function () { + z.a; + }; + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.expect.md new file mode 100644 index 0000000000..9d9edbbcea --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.expect.md @@ -0,0 +1,63 @@ + +## Input + +```javascript +function component(a) { + let z = { a: { a } }; + let x = function () { + z.a.a(); + }; + return x; +} + +``` + +## Code + +```javascript +function component(a) { + const $ = React.useMemoCache(); + const c_0 = $[0] !== a; + let t1; + if (c_0) { + t1 = { + a: a, + }; + $[0] = a; + $[1] = t1; + } else { + t1 = $[1]; + } + + const c_2 = $[2] !== t1; + let z; + + if (c_2) { + z = { + a: t1, + }; + $[2] = t1; + $[3] = z; + } else { + z = $[3]; + } + + const c_4 = $[4] !== z.a.a; + let x; + + if (c_4) { + x = function () { + z.a.a(); + }; + + $[4] = z.a.a; + $[5] = x; + } else { + x = $[5]; + } + + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.js new file mode 100644 index 0000000000..463211df83 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.js @@ -0,0 +1,7 @@ +function component(a) { + let z = { a: { a } }; + let x = function () { + z.a.a(); + }; + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.expect.md new file mode 100644 index 0000000000..8709b47cbb --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.expect.md @@ -0,0 +1,67 @@ + +## Input + +```javascript +function component(a) { + let z = { a: { a } }; + let x = function () { + (function () { + z.a.a; + })(); + }; + return x; +} + +``` + +## Code + +```javascript +function component(a) { + const $ = React.useMemoCache(); + const c_0 = $[0] !== a; + let t1; + if (c_0) { + t1 = { + a: a, + }; + $[0] = a; + $[1] = t1; + } else { + t1 = $[1]; + } + + const c_2 = $[2] !== t1; + let z; + + if (c_2) { + z = { + a: t1, + }; + $[2] = t1; + $[3] = z; + } else { + z = $[3]; + } + + const c_4 = $[4] !== z.a.a; + let x; + + if (c_4) { + x = function () { + (function () { + z.a.a; + })(); + }; + + $[4] = z.a.a; + $[5] = x; + } else { + x = $[5]; + } + + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.js new file mode 100644 index 0000000000..3d9ed70b84 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.js @@ -0,0 +1,9 @@ +function component(a) { + let z = { a: { a } }; + let x = function () { + (function () { + z.a.a; + })(); + }; + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.expect.md b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.expect.md new file mode 100644 index 0000000000..98a8386391 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.expect.md @@ -0,0 +1,63 @@ + +## Input + +```javascript +function component(a) { + let z = { a: { a } }; + let x = function () { + z.a.a; + }; + return x; +} + +``` + +## Code + +```javascript +function component(a) { + const $ = React.useMemoCache(); + const c_0 = $[0] !== a; + let t1; + if (c_0) { + t1 = { + a: a, + }; + $[0] = a; + $[1] = t1; + } else { + t1 = $[1]; + } + + const c_2 = $[2] !== t1; + let z; + + if (c_2) { + z = { + a: t1, + }; + $[2] = t1; + $[3] = z; + } else { + z = $[3]; + } + + const c_4 = $[4] !== z.a.a; + let x; + + if (c_4) { + x = function () { + z.a.a; + }; + + $[4] = z.a.a; + $[5] = x; + } else { + x = $[5]; + } + + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.js b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.js new file mode 100644 index 0000000000..c0ac21f1fe --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.js @@ -0,0 +1,7 @@ +function component(a) { + let z = { a: { a } }; + let x = function () { + z.a.a; + }; + return x; +}