Fix JSXMemberExpression dependency calculation
Fixes T173101142 — we previously computed incorrect function expression dependencies for JSXMemberExpressions. This PR applies similar logic to JSXMemberExpression as we use for MemberExpression. ## Test Plan Synced internally, only one file changes output. I manually investigated to confirm — the change is that a function expression's dependencies are more precise and correct. See https://fburl.com/everpaste/4dqewxqv
Joe Savona committed
Feb 26, 2024 at 15:04 UTC
d81da8e2f55ae9f46384a7a9d73e43fdca26994a
3 files changed
+35
-2
compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts
+31
-1
@@ -3803,6 +3803,7 @@ function gatherCapturedDeps(
3803
*/
3804
let dependency:
3805
| NodePath<t.MemberExpression>
3806
+ | NodePath<t.JSXMemberExpression>
3807
| NodePath<t.Identifier>
3808
| NodePath<t.JSXIdentifier>;
3809
if (path.isJSXOpeningElement()) {
@@ -3820,7 +3821,25 @@ function gatherCapturedDeps(
3821
"Invalid logic in gatherCapturedDeps"
3822
);
3823
baseIdentifier = current;
3823
- dependency = current;
3824
+
3825
+ /*
3826
+ * Get the expression to depend on, which may involve PropertyLoads
3827
+ * for member expressions
3828
+ */
3829
+ let currentDep:
3830
+ | NodePath<t.JSXMemberExpression>
3831
+ | NodePath<t.Identifier>
3832
+ | NodePath<t.JSXIdentifier> = baseIdentifier;
3833
+
3834
+ while (true) {
3835
+ const nextDep: null | NodePath<t.Node> = currentDep.parentPath;
3836
+ if (nextDep && nextDep.isJSXMemberExpression()) {
3837
+ currentDep = nextDep;
3838
+ } else {
3839
+ break;
3840
+ }
3841
+ }
3842
+ dependency = currentDep;
3843
} else if (path.isMemberExpression()) {
3844
// Calculate baseIdentifier
3845
let currentId: NodePath<Expression> = path;
@@ -3885,6 +3904,15 @@ function gatherCapturedDeps(
3904
}
3905
3906
exprKey += "." + pathTokens.reverse().join(".");
3907
+ } else if (dependency.isJSXMemberExpression()) {
3908
+ let pathTokens = [];
3909
+ let current: NodePath<t.JSXMemberExpression | t.JSXIdentifier> =
3910
+ dependency;
3911
+ while (current.isJSXMemberExpression()) {
3912
+ const property = current.get("property");
3913
+ pathTokens.push(property.node.name);
3914
+ current = current.get("object");
3915
+ }
3916
}
3917
3918
if (!seenPaths.has(exprKey)) {
@@ -3895,6 +3923,8 @@ function gatherCapturedDeps(
3923
place: lowerIdentifier(builder, dependency),
3924
loc: path.node.loc ?? GeneratedSource,
3925
});
3926
+ } else if (dependency.isJSXMemberExpression()) {
3927
+ loweredDep = lowerJsxMemberExpression(builder, dependency);
3928
} else {
3929
loweredDep = lowerExpressionToTemporary(builder, dependency);
3930
}
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/jsx-memberexpr-tag-in-lambda.expect.md
renamed
+4
-1
@@ -25,6 +25,7 @@ import { unstable_useMemoCache as useMemoCache } from "react";
25
import * as SharedRuntime from "shared-runtime";
26
function useFoo() {
27
const $ = useMemoCache(2);
28
+ const MyLocal = SharedRuntime;
29
let t0;
30
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31
t0 = () => <MyLocal.Text value={4} />;
@@ -49,4 +50,6 @@ export const FIXTURE_ENTRYPOINT = {
50
};
51
52
```
52
-
\ No newline at end of file
53
+
54
+### Eval output
55
+(kind: ok) <div>4</div>
\ No newline at end of file