Skip to content
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

[compiler] Empty dep arrays for globals/module-scoped values/imports #31666

Merged
merged 2 commits into from
Dec 3, 2024

Conversation

jbrown215
Copy link
Contributor

@jbrown215 jbrown215 commented Dec 3, 2024

Any LoadGlobal in the "infer deps" position can safely use an empty dep array. Globals have no reactive deps!

I just keep messing up sapling. This is the revised version of #31662

Summary:

We can keep track of outlined functions and insert an empty dep array when we find one passed to an effect. Outlined functions
always have no deps!

Outlined functions are given unique names, so we can look at LoadGlobals and see if one of those names is used.
Copy link

vercel bot commented Dec 3, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
react-compiler-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 3, 2024 6:35pm

const numRequiredArgs = moduleTargets.get(DEFAULT_EXPORT);
if (numRequiredArgs != null) {
autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
} else if (value.kind === 'LoadGlobal') {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I consolidated all of the loadglobal cases here and merged the autodepFnConfig lookups

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Could we also update the PR title and description (e.g. no deps array for all global / module / imports, not just outlined fns)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep!

@jbrown215 jbrown215 marked this pull request as ready for review December 3, 2024 17:20
@@ -117,8 +116,19 @@ export function inferEffectDependencies(fn: HIRFunction): void {
autodepFnLoads.get(value.callee.identifier.id) === value.args.length &&
value.args[0].kind === 'Identifier'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we check value.args.length or moduleTargets in a followup? Either bailing out or skipping seems reasonable, but this looks like it might crash compilation on useInferEffect() calls with no args.

(I might be wrong though, could have missed a Environment validation fn!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add an environment validation for it. That number should always be greater than 0, otherwise there is no lambda to analyze

@@ -177,6 +177,16 @@ export function inferEffectDependencies(fn: HIRFunction): void {
// Step 2: push the inferred deps array as an argument of the useEffect
value.args.push({...depsPlace, effect: Effect.Freeze});
rewriteInstrs.set(instr.id, newInstructions);
} else if (loadGlobals.has(value.args[0].identifier.id)) {
// We outlined the function expression, so we know it has no dependencies
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: change comments?

@@ -34,7 +34,7 @@ import { print } from "shared-runtime";
* before OutlineFunctions
*/
function OutlinedFunctionInEffect() {
useEffect(_temp);
useEffect(_temp, []);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉!!

Copy link
Contributor

@mofeiZ mofeiZ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Please see the value.args.length / validating Environment.inferEffectDependencies comment though.

repro in snap:

  • change numRequiredArgs to 0 in Environment test defaults
// @inferEffectDependencies
import {useEffect} from 'react';

function Foo({arg}) {
  useEffect();
}

See babel pipeline failure

FAIL: todo
 >> Unexpected error during test: 
Expected fixture `todo` to succeed but it failed with error:

/todo.ts: Cannot read properties of undefined (reading 'kind')

Summary:

We can keep track of outlined functions and insert an empty dep array when we find one passed to an effect. Outlined functions
always have no deps!

Outlined functions are given unique names, so we can look at LoadGlobals and see if one of those names is used.
@jbrown215 jbrown215 changed the title [compiler] Support outlined fns for auto-deps [compiler] Empty dep arrays for globals/module-scoped values/imports Dec 3, 2024
@jbrown215 jbrown215 merged commit 6bcf0d2 into facebook:main Dec 3, 2024
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants