-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Defer resolving the eval blocks and value blocks of generics and specifics until we've finished other resolution work. #4202
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
Defer resolving the eval blocks and value blocks of generics and specifics until we've finished other resolution work. #4202
Conversation
specifics until we've finished other resolution work. This avoids import cycles, and reduces the amount of temporary vectors we build before retrying. Import the self specific when importing a generic, now that doing so doesn't introduce cycles.
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.
LG, just a few minor things that had me looking closer. Per separate discussion, I'd also missed in the PR description the mention that Self
is now imported, explaining the test changes.
@@ -1811,6 +1798,106 @@ class ImportRefResolver { | |||
.element_type_id = context_.GetTypeIdForTypeConstant(elem_const_id)}); | |||
} | |||
|
|||
// Perform any work that we deferred until the end of the main Resolve loop. | |||
auto PerformPendingWork() -> void { | |||
while (!pending_generics_.empty() || !pending_specifics_.empty()) { |
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 is weird, can you comment it. :)
toolchain/check/import_ref.cpp
Outdated
auto* local_generic = &context_.generics().Get(pending.local_id); | ||
local_generic->decl_block_id = decl_block_id; | ||
|
||
auto self_specific_id = MakeSelfSpecific(context_, pending.local_id); | ||
local_generic->self_specific_id = self_specific_id; | ||
pending_specifics_.push_back({.import_id = import_generic.self_specific_id, | ||
.local_id = self_specific_id}); | ||
|
||
auto definition_block_id = | ||
ResolveLocalEvalBlock(import_generic, pending.local_id, | ||
SemIR::GenericInstIndex::Region::Definition); | ||
local_generic = &context_.generics().Get(pending.local_id); | ||
local_generic->definition_block_id = definition_block_id; |
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.
The use of a pointer (and reassignment) looked a little odd to me, maybe:
auto* local_generic = &context_.generics().Get(pending.local_id); | |
local_generic->decl_block_id = decl_block_id; | |
auto self_specific_id = MakeSelfSpecific(context_, pending.local_id); | |
local_generic->self_specific_id = self_specific_id; | |
pending_specifics_.push_back({.import_id = import_generic.self_specific_id, | |
.local_id = self_specific_id}); | |
auto definition_block_id = | |
ResolveLocalEvalBlock(import_generic, pending.local_id, | |
SemIR::GenericInstIndex::Region::Definition); | |
local_generic = &context_.generics().Get(pending.local_id); | |
local_generic->definition_block_id = definition_block_id; | |
auto& local_generic = context_.generics().Get(pending.local_id); | |
local_generic.decl_block_id = decl_block_id; | |
auto self_specific_id = MakeSelfSpecific(context_, pending.local_id); | |
local_generic.self_specific_id = self_specific_id; | |
pending_specifics_.push_back({.import_id = import_generic.self_specific_id, | |
.local_id = self_specific_id}); | |
// This may invalidate local_generic. | |
auto definition_block_id = | |
ResolveLocalEvalBlock(import_generic, pending.local_id, | |
SemIR::GenericInstIndex::Region::Definition); | |
context_.generics().Get(pending.local_id).definition_block_id = definition_block_id; |
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.
I started with something like this, but it seemed error-prone to me and harder to systematically get right. Changed to a different approach, what do you think?
toolchain/check/import_ref.cpp
Outdated
local_specific = &context_.specifics().Get(pending.local_id); | ||
local_specific->definition_block_id = definition_block_id; |
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.
Similar to the above, I'd suggest only reusing the same variable when it's significant (which for line 1892, it is, but that doesn't look true here).
local_specific = &context_.specifics().Get(pending.local_id); | |
local_specific->definition_block_id = definition_block_id; | |
context_.specifics().Get(pending.local_id).definition_block_id = definition_block_id; |
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.
Note, suggesting this mainly because I find it easier to figure out what the source is when it's assigned in fewer places.
toolchain/check/import_ref.cpp
Outdated
// Don't store this between calls: the generics list can be reallocated by | ||
// ResolveLocalEvalBlock importing more generics. | ||
auto local_generic = [&]() -> auto& { | ||
return context_.generics().Get(pending.local_id); | ||
}; |
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.
Maybe move onto the type as a function, so calls look like pending.Get(context)
? (lambdas always make me hesitant)
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.
Not, discussed offline, just inlining the fetches
This avoids import cycles, and reduces the number of temporary vectors we build (and potentially throw away on retry). Import the self specific when importing a generic, now that there's no risk that will introduce cycles.
Note that we could take the same approach to import classes, interfaces, and so on, instead of the current third phase of resolution for those instructions, but in this PR I'm just addressing the import cycle I'm currently seeing in a work-in-progress PR.