@samitouri / QOS-React-1 / commits / d81da8e2f5

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
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/jsx-memberexpr-tag-in-lambda.js renamed