Skip to content

Commit 4a8efd8

Browse files
authored
Rewrite generic binding imports to use AddLoadedImportRef (#6388)
This is part of trying to rewrite pending specific/generic code to make use of the standard constant resolution flow. The LoadImportRef code was a particular sticking point due to the recursion it does, which makes it difficult to adapt over.
1 parent eb0dcc8 commit 4a8efd8

File tree

3 files changed

+81
-64
lines changed

3 files changed

+81
-64
lines changed

toolchain/check/import_ref.cpp

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -434,15 +434,13 @@ class ImportRefResolver : public ImportContext {
434434

435435
// Performs resolution for one instruction and then performs all work we
436436
// deferred.
437-
// NOLINTNEXTLINE(misc-no-recursion)
438437
auto Resolve(SemIR::InstId inst_id) -> SemIR::ConstantId {
439438
auto const_id = ResolveOneInst(inst_id);
440439
PerformPendingWork();
441440
return const_id;
442441
}
443442

444443
// Wraps constant evaluation with logic to handle constants.
445-
// NOLINTNEXTLINE(misc-no-recursion)
446444
auto ResolveConstant(SemIR::ConstantId import_const_id) -> SemIR::ConstantId {
447445
return Resolve(GetInstWithConstantValue(import_ir(), import_const_id));
448446
}
@@ -511,6 +509,18 @@ static auto AddImportRef(ImportContext& context, SemIR::InstId inst_id,
511509
entity_name_id);
512510
}
513511

512+
// Handles setting a constant on instructions related to an import.
513+
static auto SetIndirectConstantValues(
514+
Context& context, llvm::ArrayRef<SemIR::ImportIRInst> indirect_insts,
515+
SemIR::ConstantId constant_id) -> void {
516+
for (const auto& import_ir_inst : indirect_insts) {
517+
auto ir_index =
518+
context.sem_ir().import_irs().GetRawIndex(import_ir_inst.ir_id());
519+
context.import_ir_constant_values()[ir_index].Set(import_ir_inst.inst_id(),
520+
constant_id);
521+
}
522+
}
523+
514524
// Adds an import_ref instruction for an instruction that we have already loaded
515525
// from an imported IR, with a known constant value. This is useful when the
516526
// instruction has a symbolic constant value, in order to produce an instruction
@@ -622,7 +632,7 @@ static auto GetLocalTypeInstId(ImportRefResolver& resolver,
622632
// The input instruction is a TypeInstId, and import does not change the type
623633
// of instructions, so the result is also a valid TypeInstId.
624634
return SemIR::TypeInstId::UnsafeMake(
625-
GetLocalConstantInstId(resolver, static_cast<SemIR::InstId>(inst_id)));
635+
GetLocalConstantInstId(resolver, inst_id));
626636
}
627637

628638
// Returns the ConstantId for a TypeId. Adds unresolved constants to
@@ -777,31 +787,65 @@ static auto MakeIncompleteGeneric(ImportContext& context, SemIR::InstId decl_id,
777787
namespace {
778788
// Local information associated with an imported generic.
779789
struct GenericData {
780-
// TODO: Delete `GenericData` if we still don't use it once generic import is
781-
// more stable.
790+
struct Binding {
791+
// The attached type's constant, which may differ from the type on the
792+
// constant. This needs to be preserved for the ImportRef.
793+
SemIR::ConstantId type_constant_id;
794+
SemIR::ConstantId inst_constant_id;
795+
};
796+
llvm::SmallVector<Binding> bindings;
782797
};
783798
} // namespace
784799

785800
// Gets a local version of the data associated with a generic.
786-
static auto GetLocalGenericData(ImportRefResolver& /*resolver*/,
787-
SemIR::GenericId /*generic_id*/)
801+
static auto GetLocalGenericData(ImportRefResolver& resolver,
802+
SemIR::GenericId import_generic_id)
788803
-> GenericData {
789-
return {};
804+
GenericData generic_data;
805+
if (import_generic_id.has_value()) {
806+
const auto& import_generic =
807+
resolver.import_generics().Get(import_generic_id);
808+
809+
if (import_generic.bindings_id.has_value()) {
810+
auto import_bindings =
811+
resolver.import_inst_blocks().Get(import_generic.bindings_id);
812+
generic_data.bindings.reserve(import_bindings.size());
813+
for (auto import_inst_id : import_bindings) {
814+
generic_data.bindings.push_back(
815+
{.type_constant_id = GetLocalConstantId(
816+
resolver,
817+
resolver.import_insts().GetAttachedType(import_inst_id)),
818+
.inst_constant_id = GetLocalConstantId(resolver, import_inst_id)});
819+
}
820+
}
821+
}
822+
return generic_data;
790823
}
791824

792825
// Adds the given local generic data to the given generic.
793826
static auto SetGenericData(ImportContext& context,
794827
SemIR::GenericId import_generic_id,
795828
SemIR::GenericId new_generic_id,
796-
const GenericData& /*generic_data*/) -> void {
829+
const GenericData& generic_data) -> void {
797830
if (!import_generic_id.has_value()) {
798831
return;
799832
}
800833

801834
const auto& import_generic = context.import_generics().Get(import_generic_id);
802835
auto& new_generic = context.local_generics().Get(new_generic_id);
803-
new_generic.bindings_id =
804-
GetLocalImportRefInstBlock(context, import_generic.bindings_id);
836+
837+
auto import_bindings =
838+
context.import_inst_blocks().Get(import_generic.bindings_id);
839+
llvm::SmallVector<SemIR::InstId> new_bindings;
840+
new_bindings.reserve(import_bindings.size());
841+
for (auto [import_binding_id, binding] :
842+
llvm::zip_equal(import_bindings, generic_data.bindings)) {
843+
auto local_type_id = context.local_types().GetTypeIdForTypeConstantId(
844+
binding.type_constant_id);
845+
new_bindings.push_back(AddLoadedImportRef(
846+
context, local_type_id, import_binding_id, binding.inst_constant_id));
847+
}
848+
new_generic.bindings_id = context.local_inst_blocks().Add(new_bindings);
805849

806850
// Track that we need to fill in the remaining information in
807851
// FinishPendingGeneric.
@@ -3400,10 +3444,6 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
34003444
// `None` if more has been added to the stack. This is the same as
34013445
// TryResolveInst, except that it may resolve symbolic constants as canonical
34023446
// constants instead of as constants associated with a particular generic.
3403-
//
3404-
// TODO: Consider refactoring the body to a helper in order to eliminate
3405-
// recursion.
3406-
// NOLINTNEXTLINE(misc-no-recursion)
34073447
static auto TryResolveInstCanonical(ImportRefResolver& resolver,
34083448
SemIR::InstId inst_id,
34093449
SemIR::ConstantId const_id)
@@ -3779,7 +3819,6 @@ auto ImportRefResolver::ResolveOneInst(SemIR::InstId inst_id)
37793819
return constant_id;
37803820
}
37813821

3782-
// NOLINTNEXTLINE(misc-no-recursion)
37833822
auto ImportRefResolver::ResolveType(SemIR::TypeId import_type_id)
37843823
-> SemIR::TypeId {
37853824
if (!import_type_id.has_value()) {
@@ -3877,13 +3916,7 @@ auto ImportRefResolver::SetResolvedConstId(
38773916
SemIR::InstId inst_id, llvm::ArrayRef<SemIR::ImportIRInst> indirect_insts,
38783917
SemIR::ConstantId const_id) -> void {
38793918
local_constant_values_for_import_insts().Set(inst_id, const_id);
3880-
for (auto indirect_inst : indirect_insts) {
3881-
local_context()
3882-
.import_ir_constant_values()
3883-
[local_context().sem_ir().import_irs().GetRawIndex(
3884-
indirect_inst.ir_id())]
3885-
.Set(indirect_inst.inst_id(), const_id);
3886-
}
3919+
SetIndirectConstantValues(local_context(), indirect_insts, const_id);
38873920
}
38883921

38893922
// Resolves and returns the local contents for an imported instruction block
@@ -3930,22 +3963,13 @@ static auto ResolveLocalEvalBlock(ImportRefResolver& resolver,
39303963
}
39313964

39323965
// Fills in the remaining information in a partially-imported generic.
3933-
// NOLINTNEXTLINE(misc-no-recursion)
39343966
static auto FinishPendingGeneric(ImportRefResolver& resolver,
39353967
ImportContext::PendingGeneric pending)
39363968
-> void {
39373969
const auto& import_generic =
39383970
resolver.import_generics().Get(pending.import_id);
39393971
auto& local_generic = resolver.local_generics().Get(pending.local_id);
39403972

3941-
// Load the bindings for the generic eagerly; they're used to form the self
3942-
// specific.
3943-
// TODO: Avoid recursion.
3944-
for (auto binding_id :
3945-
resolver.local_inst_blocks().Get(local_generic.bindings_id)) {
3946-
LoadImportRef(resolver.local_context(), binding_id);
3947-
}
3948-
39493973
local_generic.decl_block_id =
39503974
ResolveLocalEvalBlock(resolver, import_generic, pending.local_id,
39513975
SemIR::GenericInstIndex::Region::Declaration);
@@ -3995,7 +4019,6 @@ static auto FinishPendingSpecific(ImportRefResolver& resolver,
39954019
}
39964020

39974021
// Perform any work that we deferred until the end of the main Resolve loop.
3998-
// NOLINTNEXTLINE(misc-no-recursion)
39994022
auto ImportRefResolver::PerformPendingWork() -> void {
40004023
// Note that the individual Finish steps can add new pending work, so keep
40014024
// going until we have no more work to do.
@@ -4059,7 +4082,6 @@ static auto GetInstForLoad(Context& context,
40594082
}
40604083
}
40614084

4062-
// NOLINTNEXTLINE(misc-no-recursion)
40634085
auto LoadImportRef(Context& context, SemIR::InstId inst_id) -> void {
40644086
auto inst = context.insts().TryGetAs<SemIR::ImportRefUnloaded>(inst_id);
40654087
if (!inst) {
@@ -4104,12 +4126,7 @@ auto LoadImportRef(Context& context, SemIR::InstId inst_id) -> void {
41044126

41054127
// Store the constant for both the ImportRefLoaded and indirect instructions.
41064128
context.constant_values().Set(inst_id, constant_id);
4107-
for (const auto& import_ir_inst : indirect_insts) {
4108-
context
4109-
.import_ir_constant_values()[context.sem_ir().import_irs().GetRawIndex(
4110-
import_ir_inst.ir_id())]
4111-
.Set(import_ir_inst.inst_id(), constant_id);
4112-
}
4129+
SetIndirectConstantValues(context, indirect_insts, constant_id);
41134130
}
41144131

41154132
auto ImportImplsFromApiFile(Context& context) -> void {

0 commit comments

Comments
 (0)