diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 4ef0989d5365..fbb9dcbacc07 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -226,7 +226,7 @@ class ImportRefResolver { // Iteratively resolves an imported instruction's inner references until a // constant ID referencing the current IR is produced. See the class comment // for more details. - auto Resolve(SemIR::InstId inst_id) -> SemIR::ConstantId { + auto ResolveOneInst(SemIR::InstId inst_id) -> SemIR::ConstantId { work_stack_.push_back({.inst_id = inst_id}); while (!work_stack_.empty()) { auto work = work_stack_.back(); @@ -264,6 +264,14 @@ class ImportRefResolver { return constant_id; } + // Performs resolution for one instruction and then performs all work we + // deferred. + auto Resolve(SemIR::InstId inst_id) -> SemIR::ConstantId { + auto const_id = ResolveOneInst(inst_id); + PerformPendingWork(); + return const_id; + } + // Wraps constant evaluation with logic to handle constants. auto ResolveConstant(SemIR::ConstantId import_const_id) -> SemIR::ConstantId { return Resolve(GetInstWithConstantValue(import_ir_, import_const_id)); @@ -328,17 +336,24 @@ class ImportRefResolver { // Local information associated with an imported generic. struct GenericData { llvm::SmallVector bindings; - // TODO: Add data for the self specific. - llvm::SmallVector decl_block; - llvm::SmallVector definition_block; }; // Local information associated with an imported specific. struct SpecificData { SemIR::ConstantId generic_const_id; llvm::SmallVector args; - llvm::SmallVector decl_block; - llvm::SmallVector definition_block; + }; + + // A generic that we have partially imported. + struct PendingGeneric { + SemIR::GenericId import_id; + SemIR::GenericId local_id; + }; + + // A specific that we have partially imported. + struct PendingSpecific { + SemIR::SpecificId import_id; + SemIR::SpecificId local_id; }; // Looks to see if an instruction has been resolved. If a constant is only @@ -518,26 +533,7 @@ class ImportRefResolver { } const auto& generic = import_ir_.generics().Get(generic_id); - return { - .bindings = GetLocalInstBlockContents(generic.bindings_id), - .decl_block = GetLocalInstBlockContents(generic.decl_block_id), - .definition_block = - GetLocalInstBlockContents(generic.definition_block_id), - }; - } - - // Given the local constant values for the elements of the eval block, builds - // and returns the eval block for a region of a generic. - auto GetLocalEvalBlock(const SemIR::Generic& import_generic, - SemIR::GenericId generic_id, - SemIR::GenericInstIndex::Region region, - llvm::ArrayRef inst_ids) - -> SemIR::InstBlockId { - auto import_block_id = import_generic.GetEvalBlock(region); - if (!import_block_id.is_valid()) { - return SemIR::InstBlockId::Invalid; - } - return RebuildGenericEvalBlock(context_, generic_id, region, inst_ids); + return {.bindings = GetLocalInstBlockContents(generic.bindings_id)}; } // Adds the given local generic data to the given generic. @@ -552,14 +548,9 @@ class ImportRefResolver { auto& new_generic = context_.generics().Get(new_generic_id); new_generic.bindings_id = GetLocalCanonicalInstBlockId( import_generic.bindings_id, generic_data.bindings); - // TODO: Import or rebuild the self specific. - new_generic.decl_block_id = GetLocalEvalBlock( - import_generic, new_generic_id, - SemIR::GenericInstIndex::Region::Declaration, generic_data.decl_block); - new_generic.definition_block_id = - GetLocalEvalBlock(import_generic, new_generic_id, - SemIR::GenericInstIndex::Region::Definition, - generic_data.definition_block); + // Fill in the remaining information in FinishPendingGeneric. + pending_generics_.push_back( + {.import_id = import_generic_id, .local_id = new_generic_id}); } // Gets a local constant value corresponding to an imported generic ID. May @@ -610,9 +601,6 @@ class ImportRefResolver { return { .generic_const_id = GetLocalConstantId(specific.generic_id), .args = GetLocalInstBlockContents(specific.args_id), - .decl_block = GetLocalInstBlockContents(specific.decl_block_id), - .definition_block = - GetLocalInstBlockContents(specific.definition_block_id), }; } @@ -631,17 +619,16 @@ class ImportRefResolver { auto args_id = GetLocalCanonicalInstBlockId(import_specific.args_id, data.args); - // Populate the specific. Note that we might get data from multiple - // different import IRs, so only import data we don't already have. + // Get the specific. auto specific_id = context_.specifics().GetOrAdd(generic_id, args_id); + + // Fill in the remaining information in FinishPendingSpecific, if necessary. auto& specific = context_.specifics().Get(specific_id); - if (!specific.decl_block_id.is_valid()) { - specific.decl_block_id = - GetLocalInstBlockId(import_specific.decl_block_id, data.decl_block); - } - if (!specific.definition_block_id.is_valid()) { - specific.definition_block_id = GetLocalInstBlockId( - import_specific.definition_block_id, data.definition_block); + if (!specific.decl_block_id.is_valid() || + (import_specific.definition_block_id.is_valid() && + !specific.definition_block_id.is_valid())) { + pending_specifics_.push_back( + {.import_id = import_specific_id, .local_id = specific_id}); } return specific_id; } @@ -1811,6 +1798,110 @@ 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 { + // Note that the individual Finish steps can add new pending work, so keep + // going until we have no more work to do. + while (!pending_generics_.empty() || !pending_specifics_.empty()) { + while (!pending_generics_.empty()) { + FinishPendingGeneric(pending_generics_.pop_back_val()); + } + while (!pending_specifics_.empty()) { + FinishPendingSpecific(pending_specifics_.pop_back_val()); + } + } + } + + // Resolves and returns the local contents for an imported instruction block + // of constant instructions. + auto ResolveLocalInstBlockContents(SemIR::InstBlockId import_block_id) + -> llvm::SmallVector { + auto import_block = import_ir_.inst_blocks().Get(import_block_id); + + llvm::SmallVector inst_ids; + inst_ids.reserve(import_block.size()); + for (auto import_inst_id : import_block) { + inst_ids.push_back( + context_.constant_values().GetInstId(ResolveOneInst(import_inst_id))); + } + return inst_ids; + } + + // Resolves and returns a local eval block for a region of an imported + // generic. + auto ResolveLocalEvalBlock(const SemIR::Generic& import_generic, + SemIR::GenericId generic_id, + SemIR::GenericInstIndex::Region region) + -> SemIR::InstBlockId { + auto import_block_id = import_generic.GetEvalBlock(region); + if (!import_block_id.is_valid()) { + return SemIR::InstBlockId::Invalid; + } + + auto inst_ids = ResolveLocalInstBlockContents(import_block_id); + return RebuildGenericEvalBlock(context_, generic_id, region, inst_ids); + } + + // Fills in the remaining information in a partially-imported generic. + auto FinishPendingGeneric(PendingGeneric pending) -> void { + const auto& import_generic = import_ir_.generics().Get(pending.import_id); + + // Don't store the local generic between calls: the generics list can be + // reallocated by ResolveLocalEvalBlock importing more specifics. + + auto decl_block_id = + ResolveLocalEvalBlock(import_generic, pending.local_id, + SemIR::GenericInstIndex::Region::Declaration); + context_.generics().Get(pending.local_id).decl_block_id = decl_block_id; + + auto self_specific_id = MakeSelfSpecific(context_, pending.local_id); + context_.generics().Get(pending.local_id).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); + context_.generics().Get(pending.local_id).definition_block_id = + definition_block_id; + } + + // Resolves and returns a local inst block of constant instructions + // corresponding to an imported inst block. + auto ResolveLocalInstBlock(SemIR::InstBlockId import_block_id) + -> SemIR::InstBlockId { + if (!import_block_id.is_valid()) { + return SemIR::InstBlockId::Invalid; + } + + auto inst_ids = ResolveLocalInstBlockContents(import_block_id); + return context_.inst_blocks().Add(inst_ids); + } + + // Fills in the remaining information in a partially-imported specific. + auto FinishPendingSpecific(PendingSpecific pending) -> void { + const auto& import_specific = import_ir_.specifics().Get(pending.import_id); + + // Don't store the local specific between calls: the specifics list can be + // reallocated by ResolveLocalInstBlock importing more specifics. + + if (!context_.specifics().Get(pending.local_id).decl_block_id.is_valid()) { + auto decl_block_id = ResolveLocalInstBlock(import_specific.decl_block_id); + context_.specifics().Get(pending.local_id).decl_block_id = decl_block_id; + } + + if (!context_.specifics() + .Get(pending.local_id) + .definition_block_id.is_valid() && + import_specific.definition_block_id.is_valid()) { + auto definition_block_id = + ResolveLocalInstBlock(import_specific.definition_block_id); + context_.specifics().Get(pending.local_id).definition_block_id = + definition_block_id; + } + } + auto import_ir_constant_values() -> SemIR::ConstantValueStore& { return context_.import_ir_constant_values()[import_ir_id_.index]; } @@ -1821,6 +1912,10 @@ class ImportRefResolver { llvm::SmallVector work_stack_; // The size of work_stack_ at the start of resolving the current instruction. size_t initial_work_ = 0; + // Generics that we have partially imported but not yet finished importing. + llvm::SmallVector pending_generics_; + // Specifics that we have partially imported but not yet finished importing. + llvm::SmallVector pending_specifics_; }; // Returns a list of ImportIRInsts equivalent to the ImportRef currently being diff --git a/toolchain/check/testdata/class/generic/import.carbon b/toolchain/check/testdata/class/generic/import.carbon index afd1eb3e4484..b609a2d61bf1 100644 --- a/toolchain/check/testdata/class/generic/import.carbon +++ b/toolchain/check/testdata/class/generic/import.carbon @@ -228,11 +228,11 @@ class Class(U:! type) { // CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] // CHECK:STDOUT: %.4: type = struct_type {.n: i32} [template] // CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass, @CompleteClass(%T) [symbolic] +// CHECK:STDOUT: %.5: type = unbound_element_type %CompleteClass.2, i32 [symbolic] // CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] // CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] // CHECK:STDOUT: %F.type.2: type = fn_type @F.1, @CompleteClass(%T) [symbolic] // CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [symbolic] -// CHECK:STDOUT: %.5: type = unbound_element_type %CompleteClass.2, i32 [symbolic] // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] // CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, @CompleteClass(i32) [template] @@ -361,6 +361,8 @@ class Class(U:! type) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%T) {} +// CHECK:STDOUT: // CHECK:STDOUT: specific @CompleteClass(i32) { // CHECK:STDOUT: %T => i32 // CHECK:STDOUT: @@ -384,11 +386,11 @@ class Class(U:! type) { // CHECK:STDOUT: %.2: type = struct_type {.n: i32} [template] // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] // CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass, @CompleteClass(%T) [symbolic] +// CHECK:STDOUT: %.3: type = unbound_element_type %CompleteClass.2, i32 [symbolic] // CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] // CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] // CHECK:STDOUT: %F.type.2: type = fn_type @F.1, @CompleteClass(%T) [symbolic] // CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [symbolic] -// CHECK:STDOUT: %.3: type = unbound_element_type %CompleteClass.2, i32 [symbolic] // CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, @CompleteClass(i32) [template] // CHECK:STDOUT: %.4: type = unbound_element_type %CompleteClass.3, i32 [template] // CHECK:STDOUT: %F.type.3: type = fn_type @F.1, @CompleteClass(i32) [template] @@ -526,6 +528,8 @@ class Class(U:! type) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%T) {} +// CHECK:STDOUT: // CHECK:STDOUT: specific @CompleteClass(i32) { // CHECK:STDOUT: %T => i32 // CHECK:STDOUT: @@ -549,11 +553,11 @@ class Class(U:! type) { // CHECK:STDOUT: %.2: type = struct_type {.n: i32} [template] // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] // CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass, @CompleteClass(%T) [symbolic] +// CHECK:STDOUT: %.3: type = unbound_element_type %CompleteClass.2, i32 [symbolic] // CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] // CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] // CHECK:STDOUT: %F.type.2: type = fn_type @F.1, @CompleteClass(%T) [symbolic] // CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [symbolic] -// CHECK:STDOUT: %.3: type = unbound_element_type %CompleteClass.2, i32 [symbolic] // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] // CHECK:STDOUT: %.4: type = ptr_type i32 [template] @@ -657,6 +661,8 @@ class Class(U:! type) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%T) {} +// CHECK:STDOUT: // CHECK:STDOUT: specific @CompleteClass(constants.%.4) { // CHECK:STDOUT: %T => constants.%.4 // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon b/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon index 87b19a036ed5..7c0808b7e1d6 100644 --- a/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon +++ b/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon @@ -222,3 +222,7 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/lookup/import.carbon b/toolchain/check/testdata/impl/lookup/import.carbon index 934860032e5f..7c47380546b7 100644 --- a/toolchain/check/testdata/impl/lookup/import.carbon +++ b/toolchain/check/testdata/impl/lookup/import.carbon @@ -207,3 +207,5 @@ fn G(c: Impl.C) { // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2(); // CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%Self) {} +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon index 641767678160..826e7197762d 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon @@ -182,3 +182,5 @@ fn G(c: Impl.C) { // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2(); // CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%Self) {} +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/no_prelude/import_self.carbon b/toolchain/check/testdata/impl/no_prelude/import_self.carbon index 8d1247704841..fe7652e51d9f 100644 --- a/toolchain/check/testdata/impl/no_prelude/import_self.carbon +++ b/toolchain/check/testdata/impl/no_prelude/import_self.carbon @@ -192,3 +192,7 @@ fn F(x: (), y: ()) -> () { // CHECK:STDOUT: return %.loc11_23 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/no_prelude/interface_args.carbon b/toolchain/check/testdata/impl/no_prelude/interface_args.carbon index 376479641a9b..2dbb88fa126c 100644 --- a/toolchain/check/testdata/impl/no_prelude/interface_args.carbon +++ b/toolchain/check/testdata/impl/no_prelude/interface_args.carbon @@ -191,22 +191,22 @@ impl A as Factory(B) { // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] // CHECK:STDOUT: %.3: type = interface_type @Action, @Action(%T) [symbolic] // CHECK:STDOUT: %Self.1: @Action.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %.4: type = interface_type @Action, @Action(%B) [template] +// CHECK:STDOUT: %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic] // CHECK:STDOUT: %Op.type.1: type = fn_type @Op.1 [template] // CHECK:STDOUT: %Op.1: %Op.type.1 = struct_value () [template] // CHECK:STDOUT: %Op.type.2: type = fn_type @Op.1, @Action(%T) [symbolic] -// CHECK:STDOUT: %.4: type = assoc_entity_type %.3, %Op.type.2 [symbolic] -// CHECK:STDOUT: %.5: %.4 = assoc_entity element0, imports.%import_ref.7 [symbolic] // CHECK:STDOUT: %Op.2: %Op.type.2 = struct_value () [symbolic] -// CHECK:STDOUT: %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic] -// CHECK:STDOUT: %.6: type = interface_type @Action, @Action(%B) [template] +// CHECK:STDOUT: %.5: type = assoc_entity_type %.3, %Op.type.2 [symbolic] +// CHECK:STDOUT: %.6: %.5 = assoc_entity element0, imports.%import_ref.10 [symbolic] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: %.7: type = ptr_type %.1 [template] // CHECK:STDOUT: %Op.type.3: type = fn_type @Op.1, @Action(%B) [template] // CHECK:STDOUT: %Op.3: %Op.type.3 = struct_value () [template] -// CHECK:STDOUT: %.8: type = assoc_entity_type %.6, %Op.type.3 [template] -// CHECK:STDOUT: %.9: %.8 = assoc_entity element0, imports.%import_ref.7 [template] -// CHECK:STDOUT: %.10: %.4 = assoc_entity element0, imports.%import_ref.12 [symbolic] +// CHECK:STDOUT: %.8: type = assoc_entity_type %.4, %Op.type.3 [template] +// CHECK:STDOUT: %.9: %.8 = assoc_entity element0, imports.%import_ref.10 [template] +// CHECK:STDOUT: %.10: %.5 = assoc_entity element0, imports.%import_ref.12 [symbolic] // CHECK:STDOUT: %Op.type.4: type = fn_type @Op.2 [template] // CHECK:STDOUT: %Op.4: %Op.type.4 = struct_value () [template] // CHECK:STDOUT: %.11: = interface_witness (%Op.4) [template] @@ -219,9 +219,9 @@ impl A as Factory(B) { // CHECK:STDOUT: %import_ref.4 = import_ref Main//action, inst+29, unloaded // CHECK:STDOUT: %import_ref.5 = import_ref Main//action, inst+25, unloaded // CHECK:STDOUT: %import_ref.6 = import_ref Main//action, inst+28, unloaded -// CHECK:STDOUT: %import_ref.7 = import_ref Main//action, inst+12, unloaded -// CHECK:STDOUT: %import_ref.8 = import_ref Main//action, inst+10, unloaded -// CHECK:STDOUT: %import_ref.9: @Action.%.2 (%.4) = import_ref Main//action, inst+16, loaded [symbolic = @Action.%.3 (constants.%.10)] +// CHECK:STDOUT: %import_ref.7 = import_ref Main//action, inst+10, unloaded +// CHECK:STDOUT: %import_ref.8: @Action.%.2 (%.5) = import_ref Main//action, inst+16, loaded [symbolic = @Action.%.3 (constants.%.10)] +// CHECK:STDOUT: %import_ref.9 = import_ref Main//action, inst+12, unloaded // CHECK:STDOUT: %import_ref.10 = import_ref Main//action, inst+12, unloaded // CHECK:STDOUT: %import_ref.11: = import_ref Main//action, inst+42, loaded [template = constants.%.11] // CHECK:STDOUT: %import_ref.12 = import_ref Main//action, inst+12, unloaded @@ -252,18 +252,18 @@ impl A as Factory(B) { // CHECK:STDOUT: %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)] // CHECK:STDOUT: %Op.type: type = fn_type @Op.1, @Action(%T) [symbolic = %Op.type (constants.%Op.type.2)] // CHECK:STDOUT: %Op: @Action.%Op.type (%Op.type.2) = struct_value () [symbolic = %Op (constants.%Op.2)] -// CHECK:STDOUT: %.2: type = assoc_entity_type @Action.%.1 (%.3), @Action.%Op.type (%Op.type.2) [symbolic = %.2 (constants.%.4)] -// CHECK:STDOUT: %.3: @Action.%.2 (%.4) = assoc_entity element0, imports.%import_ref.7 [symbolic = %.3 (constants.%.5)] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Action.%.1 (%.3), @Action.%Op.type (%Op.type.2) [symbolic = %.2 (constants.%.5)] +// CHECK:STDOUT: %.3: @Action.%.2 (%.5) = assoc_entity element0, imports.%import_ref.10 [symbolic = %.3 (constants.%.6)] // CHECK:STDOUT: // CHECK:STDOUT: interface { // CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.8 -// CHECK:STDOUT: .Op = imports.%import_ref.9 -// CHECK:STDOUT: witness = (imports.%import_ref.10) +// CHECK:STDOUT: .Self = imports.%import_ref.7 +// CHECK:STDOUT: .Op = imports.%import_ref.8 +// CHECK:STDOUT: witness = (imports.%import_ref.9) // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl: %A as %.6 { +// CHECK:STDOUT: impl @impl: %A as %.4 { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = imports.%import_ref.11 // CHECK:STDOUT: } @@ -288,8 +288,8 @@ impl A as Factory(B) { // CHECK:STDOUT: %a.ref: %A = name_ref a, %a // CHECK:STDOUT: %Action.ref: %Action.type = name_ref Action, imports.%import_ref.1 [template = constants.%Action] // CHECK:STDOUT: %B.ref: type = name_ref B, imports.%import_ref.3 [template = constants.%B] -// CHECK:STDOUT: %.loc4_23: init type = call %Action.ref(%B.ref) [template = constants.%.6] -// CHECK:STDOUT: %.loc4_26: %.8 = specific_constant imports.%import_ref.9, @Action(constants.%B) [template = constants.%.9] +// CHECK:STDOUT: %.loc4_23: init type = call %Action.ref(%B.ref) [template = constants.%.4] +// CHECK:STDOUT: %.loc4_26: %.8 = specific_constant imports.%import_ref.8, @Action(constants.%B) [template = constants.%.9] // CHECK:STDOUT: %Op.ref: %.8 = name_ref Op, %.loc4_26 [template = constants.%.9] // CHECK:STDOUT: %.1: %Op.type.3 = interface_witness_access imports.%import_ref.11, element0 [template = constants.%Op.4] // CHECK:STDOUT: %Op.call: init %.2 = call %.1() @@ -302,15 +302,11 @@ impl A as Factory(B) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Action(@Action.%T) { -// CHECK:STDOUT: %T => constants.%T -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: specific @Action(constants.%B) { // CHECK:STDOUT: %T => constants.%B // CHECK:STDOUT: // CHECK:STDOUT: !definition: -// CHECK:STDOUT: %.1 => constants.%.6 +// CHECK:STDOUT: %.1 => constants.%.4 // CHECK:STDOUT: %Self => constants.%Self.2 // CHECK:STDOUT: %Op.type => constants.%Op.type.3 // CHECK:STDOUT: %Op => constants.%Op.3 @@ -318,6 +314,12 @@ impl A as Factory(B) { // CHECK:STDOUT: %.3 => constants.%.9 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Action(@Action.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.1(constants.%T, constants.%Self.1) {} +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_action.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -330,14 +332,14 @@ impl A as Factory(B) { // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] // CHECK:STDOUT: %.3: type = interface_type @Action, @Action(%T) [symbolic] // CHECK:STDOUT: %Self.1: @Action.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %.4: type = interface_type @Action, @Action(%B) [template] +// CHECK:STDOUT: %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic] // CHECK:STDOUT: %Op.type.1: type = fn_type @Op [template] // CHECK:STDOUT: %Op.1: %Op.type.1 = struct_value () [template] // CHECK:STDOUT: %Op.type.2: type = fn_type @Op, @Action(%T) [symbolic] -// CHECK:STDOUT: %.4: type = assoc_entity_type %.3, %Op.type.2 [symbolic] -// CHECK:STDOUT: %.5: %.4 = assoc_entity element0, imports.%import_ref.7 [symbolic] // CHECK:STDOUT: %Op.2: %Op.type.2 = struct_value () [symbolic] -// CHECK:STDOUT: %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic] -// CHECK:STDOUT: %.6: type = interface_type @Action, @Action(%B) [template] +// CHECK:STDOUT: %.5: type = assoc_entity_type %.3, %Op.type.2 [symbolic] +// CHECK:STDOUT: %.6: %.5 = assoc_entity element0, imports.%import_ref.10 [symbolic] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] // CHECK:STDOUT: %.7: type = ptr_type %.1 [template] @@ -346,8 +348,8 @@ impl A as Factory(B) { // CHECK:STDOUT: %Op.type.3: type = fn_type @Op, @Action(%C) [template] // CHECK:STDOUT: %Op.3: %Op.type.3 = struct_value () [template] // CHECK:STDOUT: %.9: type = assoc_entity_type %.8, %Op.type.3 [template] -// CHECK:STDOUT: %.10: %.9 = assoc_entity element0, imports.%import_ref.7 [template] -// CHECK:STDOUT: %.11: %.4 = assoc_entity element0, imports.%import_ref.13 [symbolic] +// CHECK:STDOUT: %.10: %.9 = assoc_entity element0, imports.%import_ref.10 [template] +// CHECK:STDOUT: %.11: %.5 = assoc_entity element0, imports.%import_ref.13 [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -357,9 +359,9 @@ impl A as Factory(B) { // CHECK:STDOUT: %import_ref.4: type = import_ref Main//action, inst+29, loaded [template = constants.%C] // CHECK:STDOUT: %import_ref.5 = import_ref Main//action, inst+25, unloaded // CHECK:STDOUT: %import_ref.6 = import_ref Main//action, inst+28, unloaded -// CHECK:STDOUT: %import_ref.7 = import_ref Main//action, inst+12, unloaded -// CHECK:STDOUT: %import_ref.8 = import_ref Main//action, inst+10, unloaded -// CHECK:STDOUT: %import_ref.9: @Action.%.2 (%.4) = import_ref Main//action, inst+16, loaded [symbolic = @Action.%.3 (constants.%.11)] +// CHECK:STDOUT: %import_ref.7 = import_ref Main//action, inst+10, unloaded +// CHECK:STDOUT: %import_ref.8: @Action.%.2 (%.5) = import_ref Main//action, inst+16, loaded [symbolic = @Action.%.3 (constants.%.11)] +// CHECK:STDOUT: %import_ref.9 = import_ref Main//action, inst+12, unloaded // CHECK:STDOUT: %import_ref.10 = import_ref Main//action, inst+12, unloaded // CHECK:STDOUT: %import_ref.11 = import_ref Main//action, inst+42, unloaded // CHECK:STDOUT: %import_ref.12 = import_ref Main//action, inst+30, unloaded @@ -391,18 +393,18 @@ impl A as Factory(B) { // CHECK:STDOUT: %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)] // CHECK:STDOUT: %Op.type: type = fn_type @Op, @Action(%T) [symbolic = %Op.type (constants.%Op.type.2)] // CHECK:STDOUT: %Op: @Action.%Op.type (%Op.type.2) = struct_value () [symbolic = %Op (constants.%Op.2)] -// CHECK:STDOUT: %.2: type = assoc_entity_type @Action.%.1 (%.3), @Action.%Op.type (%Op.type.2) [symbolic = %.2 (constants.%.4)] -// CHECK:STDOUT: %.3: @Action.%.2 (%.4) = assoc_entity element0, imports.%import_ref.7 [symbolic = %.3 (constants.%.5)] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Action.%.1 (%.3), @Action.%Op.type (%Op.type.2) [symbolic = %.2 (constants.%.5)] +// CHECK:STDOUT: %.3: @Action.%.2 (%.5) = assoc_entity element0, imports.%import_ref.10 [symbolic = %.3 (constants.%.6)] // CHECK:STDOUT: // CHECK:STDOUT: interface { // CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.8 -// CHECK:STDOUT: .Op = imports.%import_ref.9 -// CHECK:STDOUT: witness = (imports.%import_ref.10) +// CHECK:STDOUT: .Self = imports.%import_ref.7 +// CHECK:STDOUT: .Op = imports.%import_ref.8 +// CHECK:STDOUT: witness = (imports.%import_ref.9) // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl: %A as %.6 { +// CHECK:STDOUT: impl @impl: %A as %.4 { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = imports.%import_ref.11 // CHECK:STDOUT: } @@ -433,7 +435,7 @@ impl A as Factory(B) { // CHECK:STDOUT: %Action.ref: %Action.type = name_ref Action, imports.%import_ref.1 [template = constants.%Action] // CHECK:STDOUT: %C.ref: type = name_ref C, imports.%import_ref.4 [template = constants.%C] // CHECK:STDOUT: %.loc8_23: init type = call %Action.ref(%C.ref) [template = constants.%.8] -// CHECK:STDOUT: %.loc8_26: %.9 = specific_constant imports.%import_ref.9, @Action(constants.%C) [template = constants.%.10] +// CHECK:STDOUT: %.loc8_26: %.9 = specific_constant imports.%import_ref.8, @Action(constants.%C) [template = constants.%.10] // CHECK:STDOUT: %Op.ref: %.9 = name_ref Op, %.loc8_26 [template = constants.%.10] // CHECK:STDOUT: return // CHECK:STDOUT: } @@ -442,13 +444,15 @@ impl A as Factory(B) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Action(constants.%B) { +// CHECK:STDOUT: %T => constants.%B +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: specific @Action(@Action.%T) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Action(constants.%B) { -// CHECK:STDOUT: %T => constants.%B -// CHECK:STDOUT: } +// CHECK:STDOUT: specific @Op(constants.%T, constants.%Self.1) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @Action(constants.%C) { // CHECK:STDOUT: %T => constants.%C diff --git a/toolchain/check/testdata/index/fail_negative_indexing.carbon b/toolchain/check/testdata/index/fail_negative_indexing.carbon index c4831abd9186..38f432bec494 100644 --- a/toolchain/check/testdata/index/fail_negative_indexing.carbon +++ b/toolchain/check/testdata/index/fail_negative_indexing.carbon @@ -113,3 +113,7 @@ var b: i32 = a[-10]; // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/generic_import.carbon b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon index 7a86b5358f83..deebc6386b14 100644 --- a/toolchain/check/testdata/interface/no_prelude/generic_import.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon @@ -101,13 +101,13 @@ impl C as AddWith(C) { // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] // CHECK:STDOUT: %.3: type = interface_type @AddWith, @AddWith(%T) [symbolic] // CHECK:STDOUT: %Self.1: @AddWith.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic] // CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] // CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] // CHECK:STDOUT: %F.type.2: type = fn_type @F.1, @AddWith(%T) [symbolic] -// CHECK:STDOUT: %.4: type = assoc_entity_type %.3, %F.type.2 [symbolic] -// CHECK:STDOUT: %.5: %.4 = assoc_entity element0, imports.%import_ref.2 [symbolic] // CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [symbolic] -// CHECK:STDOUT: %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %.4: type = assoc_entity_type %.3, %F.type.2 [symbolic] +// CHECK:STDOUT: %.5: %.4 = assoc_entity element0, imports.%import_ref.5 [symbolic] // CHECK:STDOUT: %.6: type = interface_type @AddWith, @AddWith(%C) [template] // CHECK:STDOUT: %F.type.3: type = fn_type @F.2 [template] // CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] @@ -116,10 +116,10 @@ impl C as AddWith(C) { // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %import_ref.1: %AddWith.type = import_ref Main//a, inst+4, loaded [template = constants.%AddWith] -// CHECK:STDOUT: %import_ref.2 = import_ref Main//a, inst+12, unloaded -// CHECK:STDOUT: %import_ref.3 = import_ref Main//a, inst+10, unloaded -// CHECK:STDOUT: %import_ref.4 = import_ref Main//a, inst+16, unloaded -// CHECK:STDOUT: %import_ref.5: @AddWith.%F.type (%F.type.2) = import_ref Main//a, inst+12, loaded [symbolic = @AddWith.%F (constants.%F.1)] +// CHECK:STDOUT: %import_ref.2 = import_ref Main//a, inst+10, unloaded +// CHECK:STDOUT: %import_ref.3 = import_ref Main//a, inst+16, unloaded +// CHECK:STDOUT: %import_ref.4: @AddWith.%F.type (%F.type.2) = import_ref Main//a, inst+12, loaded [symbolic = @AddWith.%F (constants.%F.1)] +// CHECK:STDOUT: %import_ref.5 = import_ref Main//a, inst+12, unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -148,13 +148,13 @@ impl C as AddWith(C) { // CHECK:STDOUT: %F.type: type = fn_type @F.1, @AddWith(%T) [symbolic = %F.type (constants.%F.type.2)] // CHECK:STDOUT: %F: @AddWith.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)] // CHECK:STDOUT: %.2: type = assoc_entity_type @AddWith.%.1 (%.3), @AddWith.%F.type (%F.type.2) [symbolic = %.2 (constants.%.4)] -// CHECK:STDOUT: %.3: @AddWith.%.2 (%.4) = assoc_entity element0, imports.%import_ref.2 [symbolic = %.3 (constants.%.5)] +// CHECK:STDOUT: %.3: @AddWith.%.2 (%.4) = assoc_entity element0, imports.%import_ref.5 [symbolic = %.3 (constants.%.5)] // CHECK:STDOUT: // CHECK:STDOUT: interface { // CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.3 -// CHECK:STDOUT: .F = imports.%import_ref.4 -// CHECK:STDOUT: witness = (imports.%import_ref.5) +// CHECK:STDOUT: .Self = imports.%import_ref.2 +// CHECK:STDOUT: .F = imports.%import_ref.3 +// CHECK:STDOUT: witness = (imports.%import_ref.4) // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -190,6 +190,8 @@ impl C as AddWith(C) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%T, constants.%Self.1) {} +// CHECK:STDOUT: // CHECK:STDOUT: specific @AddWith(constants.%C) { // CHECK:STDOUT: %T => constants.%C // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interface/no_prelude/import.carbon b/toolchain/check/testdata/interface/no_prelude/import.carbon index e04043c9fcda..88dd7d7ccdee 100644 --- a/toolchain/check/testdata/interface/no_prelude/import.carbon +++ b/toolchain/check/testdata/interface/no_prelude/import.carbon @@ -300,3 +300,7 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%Self.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.2(constants.%Self.3) {} +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon index af8db8e8bcff..d43da9175440 100644 --- a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon @@ -96,3 +96,7 @@ fn Main() -> i32 { // CHECK:STDOUT: fn[%self: @Op.%Self (%Self)](%other: @Op.%Self (%Self)) -> @Op.%Self (%Self); // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon b/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon index 72b6340b37ce..5ffc85171bcf 100644 --- a/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon @@ -89,3 +89,7 @@ fn Main() -> i32 { // CHECK:STDOUT: fn[%self: @Op.%Self (%Self)](%other: @Op.%Self (%Self)) -> @Op.%Self (%Self); // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/add.carbon b/toolchain/check/testdata/operators/overloaded/add.carbon index daa0f020ba14..ab5fe06e182d 100644 --- a/toolchain/check/testdata/operators/overloaded/add.carbon +++ b/toolchain/check/testdata/operators/overloaded/add.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/bit_and.carbon b/toolchain/check/testdata/operators/overloaded/bit_and.carbon index 92aa3c93a9c1..99c84ef744e1 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_and.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_and.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/bit_complement.carbon b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon index 892a9f42ada2..49eeda842260 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_complement.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon @@ -136,3 +136,7 @@ fn TestOp(a: C) -> C { // CHECK:STDOUT: return %Op.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/bit_or.carbon b/toolchain/check/testdata/operators/overloaded/bit_or.carbon index 62af63af10a9..babbae998b48 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_or.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_or.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/bit_xor.carbon b/toolchain/check/testdata/operators/overloaded/bit_xor.carbon index 7133ae5608fd..49c2be362355 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_xor.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_xor.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/dec.carbon b/toolchain/check/testdata/operators/overloaded/dec.carbon index 257e30c8f206..71d67cc3581c 100644 --- a/toolchain/check/testdata/operators/overloaded/dec.carbon +++ b/toolchain/check/testdata/operators/overloaded/dec.carbon @@ -133,3 +133,8 @@ fn TestOp() { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %.2 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/div.carbon b/toolchain/check/testdata/operators/overloaded/div.carbon index f5b768b157d5..0a22e1b2c3c7 100644 --- a/toolchain/check/testdata/operators/overloaded/div.carbon +++ b/toolchain/check/testdata/operators/overloaded/div.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/eq.carbon b/toolchain/check/testdata/operators/overloaded/eq.carbon index 4bd1d10e958b..581f0fe4c816 100644 --- a/toolchain/check/testdata/operators/overloaded/eq.carbon +++ b/toolchain/check/testdata/operators/overloaded/eq.carbon @@ -260,6 +260,14 @@ fn TestLhsBad(a: D, b: C) -> bool { // CHECK:STDOUT: return %.loc16_16.2 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Equal.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @NotEqual.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_no_impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -384,6 +392,14 @@ fn TestLhsBad(a: D, b: C) -> bool { // CHECK:STDOUT: fn[%self: @NotEqual.%Self (%Self)](%other: @NotEqual.%Self (%Self)) -> bool; // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Equal(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @NotEqual(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_no_impl_for_args.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -568,3 +584,11 @@ fn TestLhsBad(a: D, b: C) -> bool { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Equal.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @NotEqual.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon b/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon index 99273ae7698b..5d25bc6cdb21 100644 --- a/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon +++ b/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon @@ -221,3 +221,13 @@ fn TestAddAssignNonRef(a: C, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: %.2 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon b/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon index 44e67a9bebc7..5e9b408f7f4d 100644 --- a/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon +++ b/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon @@ -240,3 +240,21 @@ fn TestRef(b: C) { // CHECK:STDOUT: fn[addr %self: @Op.4.%.2 (%.15)](); // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.1(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.3(constants.%Self.3) { +// CHECK:STDOUT: %Self => constants.%Self.3 +// CHECK:STDOUT: %.2 => constants.%.11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.4) { +// CHECK:STDOUT: %Self => constants.%Self.4 +// CHECK:STDOUT: %.2 => constants.%.15 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon b/toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon index e3283a50b893..61c12042bbd5 100644 --- a/toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon +++ b/toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon @@ -245,3 +245,12 @@ fn TestAssign(b: D) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.7 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/inc.carbon b/toolchain/check/testdata/operators/overloaded/inc.carbon index 0825cfbc1b8d..2d1e5f8eb337 100644 --- a/toolchain/check/testdata/operators/overloaded/inc.carbon +++ b/toolchain/check/testdata/operators/overloaded/inc.carbon @@ -133,3 +133,8 @@ fn TestOp() { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %.2 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/left_shift.carbon b/toolchain/check/testdata/operators/overloaded/left_shift.carbon index 45c1d8280fbd..65197f608e17 100644 --- a/toolchain/check/testdata/operators/overloaded/left_shift.carbon +++ b/toolchain/check/testdata/operators/overloaded/left_shift.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/mod.carbon b/toolchain/check/testdata/operators/overloaded/mod.carbon index ebbb87349721..98eae6d413b2 100644 --- a/toolchain/check/testdata/operators/overloaded/mod.carbon +++ b/toolchain/check/testdata/operators/overloaded/mod.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/mul.carbon b/toolchain/check/testdata/operators/overloaded/mul.carbon index 6711e2f71c77..1cccbdd384c6 100644 --- a/toolchain/check/testdata/operators/overloaded/mul.carbon +++ b/toolchain/check/testdata/operators/overloaded/mul.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/negate.carbon b/toolchain/check/testdata/operators/overloaded/negate.carbon index 01368abd3deb..f8701099b899 100644 --- a/toolchain/check/testdata/operators/overloaded/negate.carbon +++ b/toolchain/check/testdata/operators/overloaded/negate.carbon @@ -136,3 +136,7 @@ fn TestOp(a: C) -> C { // CHECK:STDOUT: return %Op.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/ordered.carbon b/toolchain/check/testdata/operators/overloaded/ordered.carbon index a8248b8a96a9..2e5f27a3cd0c 100644 --- a/toolchain/check/testdata/operators/overloaded/ordered.carbon +++ b/toolchain/check/testdata/operators/overloaded/ordered.carbon @@ -371,6 +371,22 @@ fn TestGreaterEqual(a: D, b: D) -> bool { // CHECK:STDOUT: return %.loc26_16.2 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Less.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @LessOrEquivalent.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Greater.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GreaterOrEquivalent.2(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_no_impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -567,3 +583,19 @@ fn TestGreaterEqual(a: D, b: D) -> bool { // CHECK:STDOUT: fn[%self: @GreaterOrEquivalent.%Self (%Self)](%other: @GreaterOrEquivalent.%Self (%Self)) -> bool; // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Less(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @LessOrEquivalent(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Greater(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GreaterOrEquivalent(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/right_shift.carbon b/toolchain/check/testdata/operators/overloaded/right_shift.carbon index 976b1686955c..f1bdd0957962 100644 --- a/toolchain/check/testdata/operators/overloaded/right_shift.carbon +++ b/toolchain/check/testdata/operators/overloaded/right_shift.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/sub.carbon b/toolchain/check/testdata/operators/overloaded/sub.carbon index 3a7a096185ba..31693af5ad99 100644 --- a/toolchain/check/testdata/operators/overloaded/sub.carbon +++ b/toolchain/check/testdata/operators/overloaded/sub.carbon @@ -233,3 +233,12 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.2(constants.%Self.1) { +// CHECK:STDOUT: %Self => constants.%Self.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.4(constants.%Self.2) { +// CHECK:STDOUT: %Self => constants.%Self.2 +// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index ac90c6503ae9..14641af8aa4b 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -320,8 +320,9 @@ class FormatterImpl { out_ << "!" << region_name << ":\n"; } for (auto [generic_inst_id, specific_inst_id] : llvm::zip_longest( - sem_ir_.inst_blocks().Get(generic.GetEvalBlock(region)), - sem_ir_.inst_blocks().Get(specific.GetValueBlock(region)))) { + sem_ir_.inst_blocks().GetOrEmpty(generic.GetEvalBlock(region)), + sem_ir_.inst_blocks().GetOrEmpty( + specific.GetValueBlock(region)))) { if (generic_inst_id && specific_inst_id && sem_ir_.insts().Is(*generic_inst_id) && sem_ir_.insts().Is(*specific_inst_id)) { diff --git a/toolchain/sem_ir/generic.cpp b/toolchain/sem_ir/generic.cpp index 5cc71765a793..96860521be82 100644 --- a/toolchain/sem_ir/generic.cpp +++ b/toolchain/sem_ir/generic.cpp @@ -82,7 +82,9 @@ auto GetConstantInSpecific(const File& sem_ir, SpecificId specific_id, auto value_block_id = specific.GetValueBlock(symbolic.index.region()); CARBON_CHECK(value_block_id.is_valid()) - << "Queried region of " << specific_id << " before it was resolved."; + << "Queried " << symbolic.index << " in " << specific_id << " for " + << sem_ir.insts().Get(sem_ir.generics().Get(specific.generic_id).decl_id) + << " before it was resolved."; return sem_ir.constant_values().Get( sem_ir.inst_blocks().Get(value_block_id)[symbolic.index.index()]); }