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] Recognize that refs are stable #30679

Merged
merged 5 commits into from
Aug 14, 2024

Conversation

mvitousek
Copy link
Contributor

@mvitousek mvitousek commented Aug 13, 2024

Stack from ghstack (oldest at bottom):

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. We can mark useRef as producing a stable value to get better memoization

…n dependency is a ref

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

[ghstack-poisoned]
Copy link

vercel bot commented Aug 13, 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 Aug 13, 2024 9:33pm

mvitousek added a commit that referenced this pull request Aug 13, 2024
…n dependency is a ref

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

ghstack-source-id: 5cd2aa1f0a9b06348b46ee5383b26a35c4e81db9
Pull Request resolved: #30679
@@ -258,6 +260,13 @@ function validateInferredDep(
}
}
let errorDiagnostic: CompareDependencyResult | null = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: move the let errorDiagnostic ... down since it's unrelated to the new if block

Copy link
Contributor

@josephsavona josephsavona left a comment

Choose a reason for hiding this comment

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

One thing to note is that it's possible to have a reactive ref:

const ref1 = useRef(..);
const ref2 = useRef(..);
const ref = props.cond ? ref1 : ref2;

...in which case we wouldn't want to prune ref as dependency in a subsequent reactive-scope/memo-block. In practice this is very rare, but unless we guard against that case the change here isn't 100% safe.

…ization when dependency is a ref"

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

[ghstack-poisoned]
mvitousek added a commit that referenced this pull request Aug 13, 2024
…n dependency is a ref

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

ghstack-source-id: a8e56b5c79715b53443a7be1fbe17ca5a2af23f6
Pull Request resolved: #30679
@mvitousek
Copy link
Contributor Author

mvitousek commented Aug 13, 2024

@josephsavona Good catch! I pulled this thread a little more and realized that we already have the technology to mark useRef results as non-reactive at their point of creation (the isStableType predicate) and we just weren't doing so. I updated this PR to include refs as nonreactive, which now changes a lot of memoization results to never include refs in the first place. And of course, refs will now be reactive if the dominator analysis determines that they should be, as in your example

…ization when dependency is a ref"

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

[ghstack-poisoned]
mvitousek added a commit that referenced this pull request Aug 13, 2024
…n dependency is a ref

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

ghstack-source-id: 01f0078c5c3f15174fcba4af2115844527a79ff4
Pull Request resolved: #30679
…ization when dependency is a ref"

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

[ghstack-poisoned]
mvitousek added a commit that referenced this pull request Aug 13, 2024
…n dependency is a ref

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

ghstack-source-id: 685d859d1eed5d1e19dbbbfadc75be3875ddb6ea
Pull Request resolved: #30679
…ization when dependency is a ref"

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

[ghstack-poisoned]
Copy link
Contributor

@josephsavona josephsavona left a comment

Choose a reason for hiding this comment

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

sogood

@mvitousek mvitousek changed the title [compiler] Allow different dependencies from explicit memoization when dependency is a ref [compiler] Recognize that refs are stable Aug 14, 2024
@mvitousek mvitousek merged commit 7e0d3d8 into gh/mvitousek/25/base Aug 14, 2024
19 checks passed
mvitousek added a commit that referenced this pull request Aug 14, 2024
…n dependency is a ref

Summary:
In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source.

ghstack-source-id: 685d859d1eed5d1e19dbbbfadc75be3875ddb6ea
Pull Request resolved: #30679
@mvitousek mvitousek deleted the gh/mvitousek/25/head branch August 14, 2024 17:54
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