-
Notifications
You must be signed in to change notification settings - Fork 49.7k
[compiler] Fix codegen for nested method calls with memoized properties #34100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| const items = makeArray(0, 1, 2, null, 4, false, 6); | ||
| t1 = Math; | ||
| t2 = t1.max; | ||
| t3 = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this cache slot seems unnecessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! See comments just to make sure this is sound
...ges/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-methodcall.expect.md
Outdated
Show resolved
Hide resolved
| // Reconstruct the MemberExpression if we previously saw an Identifier. | ||
| if (memberExpr.type === 'Identifier') { | ||
| const args = instrValue.args.map(arg => codegenArgument(cx, arg)); | ||
| value = createCallExpression( | ||
| cx.env, | ||
| memberExpr, | ||
| args, | ||
| instrValue.loc, | ||
| isHook, | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, the invariant was there to make sure that we don't rewrite a method invocation, which may read from its receiver. In the Math.* cases they are static functions and that isn't a problem, but i'm wondering if the wrong signature could break compilation w the change as implemented.
I think it would be something that a) has the receiver as readonly and b) returns a primitive. Can you try constructing a method like this in shared-runtime and type it (shared-runtime-type-provider) to check that it works correctly?
We received some bug reports about invariants reported by the compiler in their codebase. Adding them as repros. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34099). * #34100 * __->__ #34099
f6affef to
d6b8537
Compare
When processing nested method calls like `Math.floor(diff.bar())`, the compiler would trigger an invariant that `MethodCall::property must be a MemberExpression but got an Identifier`. The issue occurred when the property (e.g., Math.floor) was memoized in a reactive scope and promoted to a named identifier. Later during codegen, retrieving this memoized temporary would return just an Identifier instead of the expected MemberExpression. The fix handles this case by checking if the property has been memoized as an Identifier and using it directly for the call expression, rather than requiring it to be a MemberExpression. This fixes two test cases that were previously failing.
When processing nested method calls like
Math.floor(diff.bar()), the compiler would trigger an invariant thatMethodCall::property must be a MemberExpression but got an Identifier.The issue occurred when the property (e.g., Math.floor) was memoized in a reactive scope and promoted to a named identifier. Later during codegen, retrieving this memoized temporary would return just an Identifier instead of the expected MemberExpression.
The fix handles this case by checking if the property has been memoized as an Identifier and using it directly for the call expression, rather than requiring it to be a MemberExpression.
This fixes two test cases that were previously failing.