@@ -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,
777787namespace {
778788// Local information associated with an imported generic.
779789struct 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.
793826static 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)
34073447static 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)
37833822auto 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)
39343966static 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)
39994022auto 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)
40634085auto 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
41154132auto ImportImplsFromApiFile (Context& context) -> void {
0 commit comments