From b2a13afb73d73ee0afba3f85ffd21e63e96111d9 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 8 Aug 2024 17:21:24 -0700 Subject: [PATCH] Defer resolving the eval blocks and value blocks of generics and specifics until we've finished other resolution work. (#4202) 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. --- toolchain/check/import_ref.cpp | 187 +++++++++++++----- .../testdata/class/generic/import.carbon | 12 +- .../no_prelude/call_from_operator.carbon | 4 + .../check/testdata/impl/lookup/import.carbon | 2 + .../impl/lookup/no_prelude/import.carbon | 2 + .../impl/no_prelude/import_self.carbon | 4 + .../impl/no_prelude/interface_args.carbon | 88 +++++---- .../index/fail_negative_indexing.carbon | 4 + .../no_prelude/generic_import.carbon | 24 +-- .../interface/no_prelude/import.carbon | 4 + .../builtin/fail_type_mismatch_once.carbon | 4 + .../builtin/fail_unimplemented_op.carbon | 4 + .../testdata/operators/overloaded/add.carbon | 9 + .../operators/overloaded/bit_and.carbon | 9 + .../overloaded/bit_complement.carbon | 4 + .../operators/overloaded/bit_or.carbon | 9 + .../operators/overloaded/bit_xor.carbon | 9 + .../testdata/operators/overloaded/dec.carbon | 5 + .../testdata/operators/overloaded/div.carbon | 9 + .../testdata/operators/overloaded/eq.carbon | 24 +++ .../overloaded/fail_assign_non_ref.carbon | 10 + .../operators/overloaded/fail_no_impl.carbon | 18 ++ .../overloaded/fail_no_impl_for_arg.carbon | 9 + .../testdata/operators/overloaded/inc.carbon | 5 + .../operators/overloaded/left_shift.carbon | 9 + .../testdata/operators/overloaded/mod.carbon | 9 + .../testdata/operators/overloaded/mul.carbon | 9 + .../operators/overloaded/negate.carbon | 4 + .../operators/overloaded/ordered.carbon | 32 +++ .../operators/overloaded/right_shift.carbon | 9 + .../testdata/operators/overloaded/sub.carbon | 9 + toolchain/sem_ir/formatter.cpp | 5 +- toolchain/sem_ir/generic.cpp | 4 +- 33 files changed, 444 insertions(+), 105 deletions(-) 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()]); }