-
Notifications
You must be signed in to change notification settings - Fork 47.7k
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] Delete LoweredFunction.dependencies and hoisted instructions #32096
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -148,6 +148,14 @@ function collectScopeInfo(fn: HIRFunction): ScopeInfo { | |
const scope = place.identifier.scope; | ||
if (scope != null) { | ||
placeScopes.set(place, scope); | ||
/** | ||
* Record both mutating and non-mutating scopes to merge scopes with | ||
* still-mutating values with inner scopes that alias those values | ||
* (see `nonmutating-capture-in-unsplittable-memo-block`) | ||
* | ||
* Note that this isn't perfect, as it also leads to merging of mutating | ||
* scopes with JSX single-instruction scopes (see `mutation-within-jsx`) | ||
*/ | ||
if (scope.range.start !== scope.range.end) { | ||
getOrInsertDefault(scopeStarts, scope.range.start, new Set()).add( | ||
scope, | ||
|
@@ -254,7 +262,7 @@ function visitPlace( | |
* of the stack to the mutated outer scope. | ||
*/ | ||
const placeScope = getPlaceScope(id, place); | ||
if (placeScope != null && isMutable({id} as any, place)) { | ||
if (placeScope != null && isMutable({id}, place)) { | ||
const placeScopeIdx = activeScopes.indexOf(placeScope); | ||
if (placeScopeIdx !== -1 && placeScopeIdx !== activeScopes.length - 1) { | ||
joined.union([placeScope, ...activeScopes.slice(placeScopeIdx + 1)]); | ||
|
@@ -275,6 +283,13 @@ function getOverlappingReactiveScopes( | |
for (const instr of block.instructions) { | ||
visitInstructionId(instr.id, context, state); | ||
for (const place of eachInstructionOperand(instr)) { | ||
if ( | ||
(instr.value.kind === 'FunctionExpression' || | ||
instr.value.kind === 'ObjectMethod') && | ||
place.identifier.type.kind === 'Primitive' | ||
) { | ||
continue; | ||
} | ||
Comment on lines
+286
to
+292
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you double-check this case a bit more? Every time we have to special case something like this there's a chance that we're overlooking the larger rule. Why do we need to skip primitives, and why only for functionexpr/objectmethod? If nothing else, this repeatedly checks properties of the instruction value for every single operand, which is inefficient, but i'm more concerned with the check itself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense! This change special cases function calls that capture identifiers whose type is We can remove this check (which leads to more merged scopes) or generalize it in visitPlace in a later PR. |
||
visitPlace(instr.id, place, state); | ||
} | ||
for (const place of eachInstructionLValue(instr)) { | ||
|
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 can now be cleaned up 🎉