From 3c8fc714a8e9caab386f93d8f87daa210472a7ce Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 31 Jul 2024 16:53:14 -0700 Subject: [PATCH] Import support for generics and specifics (#4179) Import generics and specifics when they are referenced by imported entities. When importing a generic, we import the symbolic constants required by its eval block, and then rebuild the eval block itself given the list of constants it needs to compute. This is likely a bit less efficient than directly importing the contents of the eval block, but avoids needing to either extend the importer code to be able to import the instructions that can appear in the eval block or extend the evaluator to cope with instructions from a different `SemIR::File`. Importing a symbolic constant is unaffected, and does not yet preserve the associated generic and index within that generic, so uses of a generic from an imported IR still don't pick up values from the specific, but the improved functionality can be seen in the changes to the SemIR in the testcases. --- toolchain/check/generic.cpp | 99 +++-- toolchain/check/generic.h | 8 + toolchain/check/import_ref.cpp | 239 ++++++++++-- .../testdata/class/generic/import.carbon | 356 +++++++++++++----- .../class/syntactic_merge_literal.carbon | 176 ++++++--- .../no_prelude/call_from_operator.carbon | 6 +- .../check/testdata/impl/lookup/import.carbon | 5 +- .../impl/lookup/no_prelude/import.carbon | 5 +- .../impl/no_prelude/import_self.carbon | 6 +- .../index/fail_negative_indexing.carbon | 6 +- .../no_prelude/generic_import.carbon | 74 ++-- .../interface/no_prelude/import.carbon | 10 +- .../builtin/fail_type_mismatch_once.carbon | 6 +- .../builtin/fail_unimplemented_op.carbon | 6 +- .../testdata/operators/overloaded/add.carbon | 13 +- .../operators/overloaded/bit_and.carbon | 13 +- .../overloaded/bit_complement.carbon | 6 +- .../operators/overloaded/bit_or.carbon | 13 +- .../operators/overloaded/bit_xor.carbon | 13 +- .../testdata/operators/overloaded/dec.carbon | 7 +- .../testdata/operators/overloaded/div.carbon | 13 +- .../testdata/operators/overloaded/eq.carbon | 36 +- .../overloaded/fail_assign_non_ref.carbon | 14 +- .../operators/overloaded/fail_no_impl.carbon | 26 +- .../overloaded/fail_no_impl_for_arg.carbon | 13 +- .../testdata/operators/overloaded/inc.carbon | 7 +- .../operators/overloaded/left_shift.carbon | 13 +- .../testdata/operators/overloaded/mod.carbon | 13 +- .../testdata/operators/overloaded/mul.carbon | 13 +- .../operators/overloaded/negate.carbon | 6 +- .../operators/overloaded/ordered.carbon | 48 ++- .../operators/overloaded/right_shift.carbon | 13 +- .../testdata/operators/overloaded/sub.carbon | 13 +- .../no_prelude/fail_export_name_params.carbon | 24 +- toolchain/check/testdata/struct/import.carbon | 86 +++-- toolchain/check/testdata/tuples/import.carbon | 86 +++-- toolchain/sem_ir/generic.cpp | 1 + 37 files changed, 1156 insertions(+), 336 deletions(-) diff --git a/toolchain/check/generic.cpp b/toolchain/check/generic.cpp index d1048531084a..f38045abe027 100644 --- a/toolchain/check/generic.cpp +++ b/toolchain/check/generic.cpp @@ -44,6 +44,14 @@ static auto AddGenericConstantInstToEvalBlock( } namespace { +// A map from an instruction ID representing a canonical symbolic constant to an +// instruction within an eval block of the generic that computes the specific +// value for that constant. +// +// We arbitrarily use a small size of 256 bytes for the map. +// TODO: Determine a better number based on measurements. +using ConstantsInGenericMap = Map; + // Substitution callbacks to rebuild a generic constant in the eval block for a // generic region. class RebuildGenericConstantInEvalBlockCallbacks final @@ -52,7 +60,7 @@ class RebuildGenericConstantInEvalBlockCallbacks final RebuildGenericConstantInEvalBlockCallbacks( Context& context, SemIR::GenericId generic_id, SemIR::GenericInstIndex::Region region, - Map& constants_in_generic) + ConstantsInGenericMap& constants_in_generic) : context_(context), generic_id_(generic_id), region_(region), @@ -62,6 +70,14 @@ class RebuildGenericConstantInEvalBlockCallbacks final // block, and substitute them for the instructions in the eval block. auto Subst(SemIR::InstId& inst_id) const -> bool override { auto const_id = context_.constant_values().Get(inst_id); + if (!const_id.is_valid()) { + // An unloaded import ref should never contain anything we need to + // substitute into. Don't trigger loading it here. + CARBON_CHECK(context_.insts().Is(inst_id)) + << "Substituting into instruction with invalid constant ID: " + << context_.insts().Get(inst_id); + return true; + } if (!const_id.is_symbolic()) { // This instruction doesn't have a symbolic constant value, so can't // contain any bindings that need to be substituted. @@ -104,6 +120,8 @@ class RebuildGenericConstantInEvalBlockCallbacks final // TODO: Add a function on `Context` to add the instruction without // inserting it into the dependent instructions list or computing a // constant value for it. + // TODO: Provide a location based on the location of the instruction + // that uses the constant. auto inst_id = context_.sem_ir().insts().AddInNoBlock( SemIR::LocIdAndInst::NoLoc(new_inst)); auto const_id = AddGenericConstantInstToEvalBlock( @@ -118,7 +136,7 @@ class RebuildGenericConstantInEvalBlockCallbacks final Context& context_; SemIR::GenericId generic_id_; SemIR::GenericInstIndex::Region region_; - Map& constants_in_generic_; + ConstantsInGenericMap& constants_in_generic_; }; } // namespace @@ -129,8 +147,8 @@ class RebuildGenericConstantInEvalBlockCallbacks final static auto AddGenericTypeToEvalBlock( Context& context, SemIR::GenericId generic_id, SemIR::GenericInstIndex::Region region, - Map& constants_in_generic, - SemIR::TypeId type_id) -> SemIR::TypeId { + ConstantsInGenericMap& constants_in_generic, SemIR::TypeId type_id) + -> SemIR::TypeId { // Substitute into the type's constant instruction and rebuild it in the eval // block. auto type_inst_id = @@ -147,8 +165,8 @@ static auto AddGenericTypeToEvalBlock( static auto AddGenericConstantToEvalBlock( Context& context, SemIR::GenericId generic_id, SemIR::GenericInstIndex::Region region, - Map& constants_in_generic, - SemIR::InstId inst_id) -> SemIR::ConstantId { + ConstantsInGenericMap& constants_in_generic, SemIR::InstId inst_id) + -> SemIR::ConstantId { // Substitute into the constant value and rebuild it in the eval block if // we've not encountered it before. auto const_inst_id = context.constant_values().GetConstantInstId(inst_id); @@ -162,6 +180,24 @@ static auto AddGenericConstantToEvalBlock( return context.constant_values().Get(new_inst_id); } +// Populates a map of constants in a generic from the constants in the +// declaration region, in preparation for building the definition region. +static auto PopulateConstantsFromDeclaration( + Context& context, SemIR::GenericId generic_id, + ConstantsInGenericMap& constants_in_generic) { + // For the definition region, populate constants from the declaration. + auto decl_eval_block = context.inst_blocks().Get( + context.generics().Get(generic_id).decl_block_id); + constants_in_generic.GrowForInsertCount(decl_eval_block.size()); + for (auto inst_id : decl_eval_block) { + auto const_inst_id = context.constant_values().GetConstantInstId(inst_id); + auto result = constants_in_generic.Insert(const_inst_id, inst_id); + CARBON_CHECK(result.is_inserted()) + << "Duplicate constant in generic decl eval block: " + << context.insts().Get(const_inst_id); + } +} + // Builds and returns a block of instructions whose constant values need to be // evaluated in order to resolve a generic to a specific. static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id, @@ -169,16 +205,11 @@ static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id, -> SemIR::InstBlockId { context.inst_block_stack().Push(); - Map constants_in_generic; + ConstantsInGenericMap constants_in_generic; // For the definition region, populate constants from the declaration. if (region == SemIR::GenericInstIndex::Region::Definition) { - auto decl_eval_block = context.inst_blocks().Get( - context.generics().Get(generic_id).decl_block_id); - for (auto inst_id : decl_eval_block) { - constants_in_generic.Insert( - context.constant_values().GetConstantInstId(inst_id), inst_id); - } + PopulateConstantsFromDeclaration(context, generic_id, constants_in_generic); } // The work done in this loop might invalidate iterators into the generic @@ -231,6 +262,37 @@ static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id, return context.inst_block_stack().Pop(); } +// Builds and returns an eval block, given the list of canonical symbolic +// constants that the instructions in the eval block should produce. This is +// used when importing a generic. +auto RebuildGenericEvalBlock(Context& context, SemIR::GenericId generic_id, + SemIR::GenericInstIndex::Region region, + llvm::ArrayRef const_ids) + -> SemIR::InstBlockId { + context.inst_block_stack().Push(); + + ConstantsInGenericMap constants_in_generic; + + // For the definition region, populate constants from the declaration. + if (region == SemIR::GenericInstIndex::Region::Definition) { + PopulateConstantsFromDeclaration(context, generic_id, constants_in_generic); + } + + constants_in_generic.GrowForInsertCount(const_ids.size()); + for (auto [i, inst_id] : llvm::enumerate(const_ids)) { + // Build a constant in the inst block. + AddGenericConstantToEvalBlock(context, generic_id, region, + constants_in_generic, inst_id); + CARBON_CHECK(context.inst_block_stack().PeekCurrentBlockContents().size() == + i + 1) + << "Produced " + << (context.inst_block_stack().PeekCurrentBlockContents().size() - i) + << " instructions when importing " << context.insts().Get(inst_id); + } + + return context.inst_block_stack().Pop(); +} + auto FinishGenericDecl(Context& context, SemIR::InstId decl_id) -> SemIR::GenericId { auto all_bindings = @@ -293,11 +355,6 @@ auto MakeSpecific(Context& context, SemIR::GenericId generic_id, SemIR::InstBlockId args_id) -> SemIR::SpecificId { auto specific_id = context.specifics().GetOrAdd(generic_id, args_id); - // TODO: Remove this once we import generics properly. - if (!generic_id.is_valid()) { - return specific_id; - } - // If this is the first time we've formed this specific, evaluate its decl // block to form information about the specific. if (!context.specifics().Get(specific_id).decl_block_id.is_valid()) { @@ -339,11 +396,7 @@ auto ResolveSpecificDefinition(Context& context, SemIR::SpecificId specific_id) -> bool { auto& specific = context.specifics().Get(specific_id); auto generic_id = specific.generic_id; - - // TODO: Remove this once we import generics properly. - if (!generic_id.is_valid()) { - return true; - } + CARBON_CHECK(generic_id.is_valid()) << "Specific with no generic ID"; if (!specific.definition_block_id.is_valid()) { // Evaluate the eval block for the definition of the generic. diff --git a/toolchain/check/generic.h b/toolchain/check/generic.h index 63424681977a..4008bd1f1746 100644 --- a/toolchain/check/generic.h +++ b/toolchain/check/generic.h @@ -31,6 +31,14 @@ auto FinishGenericRedecl(Context& context, SemIR::InstId decl_id, auto FinishGenericDefinition(Context& context, SemIR::GenericId generic_id) -> void; +// Builds and returns an eval block, given the list of canonical symbolic +// constants that the instructions in the eval block should produce. This is +// used when importing a generic. +auto RebuildGenericEvalBlock(Context& context, SemIR::GenericId generic_id, + SemIR::GenericInstIndex::Region region, + llvm::ArrayRef const_ids) + -> SemIR::InstBlockId; + // Builds a new specific, or finds an existing one if this generic has already // been referenced with these arguments. Performs substitution into the // declaration, but not the definition, of the generic. diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 1334d1433b82..2e07c156bbd3 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -267,6 +267,22 @@ class ImportRefResolver { llvm::SmallVector indirect_insts = {}; }; + // 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; + }; + // Looks to see if an instruction has been resolved. If a constant is only // found indirectly, sets the constant for any indirect steps that don't // already have the constant. If a constant isn't found, returns the indirect @@ -397,6 +413,18 @@ class ImportRefResolver { return inst_ids; } + // Gets a local instruction block ID corresponding to an imported inst block + // whose contents were already imported, for example by + // GetLocalInstBlockContents. + auto GetLocalInstBlockId(SemIR::InstBlockId import_block_id, + llvm::ArrayRef contents) + -> SemIR::InstBlockId { + if (!import_block_id.is_valid()) { + return SemIR::InstBlockId::Invalid; + } + return context_.inst_blocks().Add(contents); + } + // Gets a local canonical instruction block ID corresponding to an imported // inst block whose contents were already imported, for example by // GetLocalInstBlockContents. @@ -409,43 +437,153 @@ class ImportRefResolver { return context_.inst_blocks().AddCanonical(contents); } - // Gets a local version of an imported generic. - auto GetLocalGeneric(SemIR::GenericId generic_id) -> SemIR::GenericId { + // Gets an incomplete local version of an imported generic. Most fields are + // set in the second pass. + auto MakeIncompleteGeneric(SemIR::InstId decl_id, SemIR::GenericId generic_id) + -> SemIR::GenericId { if (!generic_id.is_valid()) { return SemIR::GenericId::Invalid; } - // TODO: Support importing generics. Note that this comes up in the prelude, - // so for now we fall back to producing `Invalid` and treating imported - // generics as non-generic. - return SemIR::GenericId::Invalid; + return context_.generics().Add( + {.decl_id = decl_id, + .bindings_id = SemIR::InstBlockId::Invalid, + .self_specific_id = SemIR::SpecificId::Invalid}); } - // Gets a local argument list corresponding to the arguments of an imported - // specific. - auto GetLocalSpecificArgs(SemIR::SpecificId specific_id) - -> llvm::SmallVector { - if (!specific_id.is_valid()) { - return {}; + // Gets a local version of the data associated with a generic. + auto GetLocalGenericData(SemIR::GenericId generic_id) -> GenericData { + if (!generic_id.is_valid()) { + return GenericData(); } - return GetLocalInstBlockContents( - import_ir_.specifics().Get(specific_id).args_id); + + 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), + }; } - // Gets a local specific whose arguments were already imported by - // GetLocalSpecificArgs. Does not add any new work. - auto GetLocalSpecific(SemIR::SpecificId specific_id, - llvm::ArrayRef args) - -> SemIR::SpecificId { + // 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); + } + + // Adds the given local generic data to the given generic. + auto SetGenericData(SemIR::GenericId import_generic_id, + SemIR::GenericId new_generic_id, + const GenericData& generic_data) -> void { + if (!import_generic_id.is_valid()) { + return; + } + + const auto& import_generic = import_ir_.generics().Get(import_generic_id); + 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); + } + + // Gets a local constant value corresponding to an imported generic ID. May + // add work to the work stack and return `Invalid`. + auto GetLocalConstantId(SemIR::GenericId generic_id) -> SemIR::ConstantId { + if (!generic_id.is_valid()) { + return SemIR::ConstantId::Invalid; + } + return GetLocalConstantId( + import_ir_.insts() + .Get(import_ir_.generics().Get(generic_id).decl_id) + .type_id()); + } + + // Gets a local generic ID given the corresponding local constant ID returned + // by GetLocalConstantId for the imported generic. Does not add any new work. + auto GetLocalGenericId(SemIR::ConstantId local_const_id) -> SemIR::GenericId { + if (!local_const_id.is_valid()) { + return SemIR::GenericId::Invalid; + } + auto type = context_.insts().Get( + context_.constant_values().GetInstId(local_const_id)); + CARBON_KIND_SWITCH(type) { + case CARBON_KIND(SemIR::FunctionType fn_type): { + return context_.functions().Get(fn_type.function_id).generic_id; + } + case CARBON_KIND(SemIR::GenericClassType class_type): { + return context_.classes().Get(class_type.class_id).generic_id; + } + case CARBON_KIND(SemIR::GenericInterfaceType interface_type): { + return context_.interfaces() + .Get(interface_type.interface_id) + .generic_id; + } + default: { + CARBON_FATAL() << "Unexpected type for generic declaration: " << type; + } + } + } + + // Gets local information about an imported specific. + auto GetLocalSpecificData(SemIR::SpecificId specific_id) -> SpecificData { if (!specific_id.is_valid()) { + return {.generic_const_id = SemIR::ConstantId::Invalid, .args = {}}; + } + + const auto& specific = import_ir_.specifics().Get(specific_id); + 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), + }; + } + + // Gets a local specific whose data was already imported by + // GetLocalSpecificData. Does not add any new work. + auto GetOrAddLocalSpecific(SemIR::SpecificId import_specific_id, + const SpecificData& data) -> SemIR::SpecificId { + if (!import_specific_id.is_valid()) { return SemIR::SpecificId::Invalid; } - const auto& specific = import_ir_.specifics().Get(specific_id); - // TODO: Import the generic. - auto generic_id = SemIR::GenericId::Invalid; - auto args_id = GetLocalCanonicalInstBlockId(specific.args_id, args); - // TODO: Also import the specific. - return context_.specifics().GetOrAdd(generic_id, args_id); + + // Form a corresponding local specific ID. + const auto& import_specific = + import_ir_.specifics().Get(import_specific_id); + auto generic_id = GetLocalGenericId(data.generic_const_id); + 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. + auto specific_id = context_.specifics().GetOrAdd(generic_id, args_id); + 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); + } + return specific_id; } // Returns the ConstantId for each parameter's type. Adds unresolved constants @@ -653,7 +791,7 @@ class ImportRefResolver { return { .name_id = GetLocalNameId(import_base.name_id), .parent_scope_id = SemIR::NameScopeId::Invalid, - .generic_id = GetLocalGeneric(import_base.generic_id), + .generic_id = MakeIncompleteGeneric(decl_id, import_base.generic_id), .first_param_node_id = Parse::NodeId::Invalid, .last_param_node_id = Parse::NodeId::Invalid, .implicit_param_refs_id = import_base.implicit_param_refs_id.is_valid() @@ -854,11 +992,22 @@ class ImportRefResolver { return ResolveResult::Retry(); } + // TODO: Track an interface type, not an interface ID, on + // AssociatedEntityType. + auto interface_inst = context_.insts().Get(interface_inst_id); + SemIR::InterfaceId interface_id = SemIR::InterfaceId::Invalid; + if (interface_inst.Is()) { + interface_id = interface_inst.As().interface_id; + } else { + interface_id = + context_.types() + .GetAs(interface_inst.type_id()) + .interface_id; + } + return ResolveAs( {.type_id = SemIR::TypeId::TypeType, - .interface_id = context_.insts() - .GetAs(interface_inst_id) - .interface_id, + .interface_id = interface_id, .entity_type_id = context_.GetTypeIdForTypeConstant(entity_type_const_id)}); } @@ -1009,6 +1158,7 @@ class ImportRefResolver { GetLocalParamConstantIds(import_class.implicit_param_refs_id); llvm::SmallVector param_const_ids = GetLocalParamConstantIds(import_class.param_refs_id); + auto generic_data = GetLocalGenericData(import_class.generic_id); auto self_const_id = GetLocalConstantId(import_class.self_type_id); auto object_repr_const_id = import_class.object_repr_id.is_valid() @@ -1028,6 +1178,7 @@ class ImportRefResolver { import_class.implicit_param_refs_id, implicit_param_const_ids); new_class.param_refs_id = GetLocalParamRefsId(import_class.param_refs_id, param_const_ids); + SetGenericData(import_class.generic_id, new_class.generic_id, generic_data); new_class.self_type_id = context_.GetTypeIdForTypeConstant(self_const_id); if (import_class.is_defined()) { @@ -1043,7 +1194,7 @@ class ImportRefResolver { CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); auto class_const_id = GetLocalConstantId(import_ir_.classes().Get(inst.class_id).decl_id); - auto args = GetLocalSpecificArgs(inst.specific_id); + auto specific_data = GetLocalSpecificData(inst.specific_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } @@ -1058,7 +1209,7 @@ class ImportRefResolver { } else { auto generic_class_type = context_.types().GetAs( class_const_inst.type_id()); - auto specific_id = GetLocalSpecific(inst.specific_id, args); + auto specific_id = GetOrAddLocalSpecific(inst.specific_id, specific_data); return ResolveAs( {.type_id = SemIR::TypeId::TypeType, .class_id = generic_class_type.class_id, @@ -1116,6 +1267,7 @@ class ImportRefResolver { GetLocalParamConstantIds(function.implicit_param_refs_id); llvm::SmallVector param_const_ids = GetLocalParamConstantIds(function.param_refs_id); + auto generic_data = GetLocalGenericData(function.generic_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); @@ -1130,7 +1282,9 @@ class ImportRefResolver { auto function_decl_id = context_.AddPlaceholderInstInNoBlock( SemIR::LocIdAndInst(import_ir_inst_id, function_decl)); // TODO: Implement import for generics. - auto generic_id = GetLocalGeneric(function.generic_id); + auto generic_id = + MakeIncompleteGeneric(function_decl_id, function.generic_id); + SetGenericData(function.generic_id, generic_id, generic_data); auto new_return_storage = SemIR::InstId::Invalid; if (function.return_storage_id.is_valid()) { @@ -1173,14 +1327,18 @@ class ImportRefResolver { CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); auto fn_val_id = GetLocalConstantInstId( import_ir_.functions().Get(inst.function_id).decl_id); + auto specific_data = GetLocalSpecificData(inst.specific_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } - auto fn_val = context_.insts().Get(fn_val_id); - CARBON_CHECK(context_.types().Is(fn_val.type_id())); - // TODO: Import the correct specific and build a function type constant - // using it. - return {.const_id = context_.types().GetConstantId(fn_val.type_id())}; + auto fn_type_id = context_.insts().Get(fn_val_id).type_id(); + return ResolveAs( + {.type_id = SemIR::TypeId::TypeType, + .function_id = context_.types() + .GetAs(fn_type_id) + .function_id, + .specific_id = + GetOrAddLocalSpecific(inst.specific_id, specific_data)}); } auto TryResolveTypedInst(SemIR::GenericClassType inst) -> ResolveResult { @@ -1322,6 +1480,7 @@ class ImportRefResolver { GetLocalParamConstantIds(import_interface.implicit_param_refs_id); llvm::SmallVector param_const_ids = GetLocalParamConstantIds(import_interface.param_refs_id); + auto generic_data = GetLocalGenericData(import_interface.generic_id); std::optional self_param_id; if (import_interface.is_defined()) { @@ -1338,6 +1497,8 @@ class ImportRefResolver { import_interface.implicit_param_refs_id, implicit_param_const_ids); new_interface.param_refs_id = GetLocalParamRefsId(import_interface.param_refs_id, param_const_ids); + SetGenericData(import_interface.generic_id, new_interface.generic_id, + generic_data); if (import_interface.is_defined()) { CARBON_CHECK(self_param_id); @@ -1351,7 +1512,7 @@ class ImportRefResolver { CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); auto interface_const_id = GetLocalConstantId( import_ir_.interfaces().Get(inst.interface_id).decl_id); - auto args = GetLocalSpecificArgs(inst.specific_id); + auto specific_data = GetLocalSpecificData(inst.specific_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } @@ -1368,7 +1529,7 @@ class ImportRefResolver { auto generic_interface_type = context_.types().GetAs( interface_const_inst.type_id()); - auto specific_id = GetLocalSpecific(inst.specific_id, args); + auto specific_id = GetOrAddLocalSpecific(inst.specific_id, specific_data); return ResolveAs( {.type_id = SemIR::TypeId::TypeType, .interface_id = generic_interface_type.interface_id, diff --git a/toolchain/check/testdata/class/generic/import.carbon b/toolchain/check/testdata/class/generic/import.carbon index 7df195a06898..30976b38b9bc 100644 --- a/toolchain/check/testdata/class/generic/import.carbon +++ b/toolchain/check/testdata/class/generic/import.carbon @@ -231,27 +231,35 @@ class Class(U:! type) { // CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template] // CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template] -// CHECK:STDOUT: %Class.2: type = class_type @Class, invalid(%T) [symbolic] +// CHECK:STDOUT: %Class.2: type = class_type @Class, @Class(%T) [symbolic] // CHECK:STDOUT: %.2: type = unbound_element_type %Class.2, %T [symbolic] // CHECK:STDOUT: %.3: type = struct_type {.x: %T} [symbolic] // CHECK:STDOUT: %CompleteClass.type: type = generic_class_type @CompleteClass [template] // 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, invalid(%T) [symbolic] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass, @CompleteClass(%T) [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, invalid(i32) [template] -// CHECK:STDOUT: %F.type: type = fn_type @F [template] -// CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %.5: type = ptr_type %.4 [template] -// CHECK:STDOUT: %.6: i32 = int_literal 1 [template] -// CHECK:STDOUT: %struct: %CompleteClass.3 = struct_value (%.6) [template] +// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, @CompleteClass(i32) [template] +// CHECK:STDOUT: %F.type.3: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] +// CHECK:STDOUT: %.6: type = unbound_element_type %CompleteClass.3, i32 [template] +// CHECK:STDOUT: %F.type.4: type = fn_type @F.1, @CompleteClass(i32) [template] +// CHECK:STDOUT: %F.4: %F.type.4 = struct_value () [template] +// CHECK:STDOUT: %.7: type = ptr_type %.4 [template] +// CHECK:STDOUT: %.8: i32 = int_literal 1 [template] +// CHECK:STDOUT: %struct: %CompleteClass.3 = struct_value (%.8) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %import_ref.1: %Class.type = import_ref Main//foo, inst+6, loaded [template = constants.%Class.1] // CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref Main//foo, inst+14, loaded [template = constants.%CompleteClass.1] -// CHECK:STDOUT: %import_ref.3: %F.type = import_ref Main//foo, inst+55, loaded [template = constants.%F] +// CHECK:STDOUT: %import_ref.3: %F.type.3 = import_ref Main//foo, inst+55, loaded [template = constants.%F.3] // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: .Int32 = %import_ref.7 // CHECK:STDOUT: import Core//prelude @@ -282,7 +290,7 @@ class Class(U:! type) { // CHECK:STDOUT: %T.loc4_13.1: type = param T // CHECK:STDOUT: %T.loc4_13.2: type = bind_symbolic_name T 0, %T.loc4_13.1 [symbolic = constants.%T] // CHECK:STDOUT: } -// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %F.decl: %F.type.3 = fn_decl @F.2 [template = constants.%F.3] { // CHECK:STDOUT: %CompleteClass.ref: %CompleteClass.type = name_ref CompleteClass, imports.%import_ref.2 [template = constants.%CompleteClass.1] // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] // CHECK:STDOUT: %.loc8_24.1: type = value_of_initializer %int.make_type_32 [template = i32] @@ -290,42 +298,88 @@ class Class(U:! type) { // CHECK:STDOUT: %.loc8_24.3: init type = call %CompleteClass.ref(%.loc8_24.2) [template = constants.%CompleteClass.3] // CHECK:STDOUT: %.loc8_28.1: type = value_of_initializer %.loc8_24.3 [template = constants.%CompleteClass.3] // CHECK:STDOUT: %.loc8_28.2: type = converted %.loc8_24.3, %.loc8_28.1 [template = constants.%CompleteClass.3] -// CHECK:STDOUT: @F.%return: ref %CompleteClass.3 = var +// CHECK:STDOUT: @F.2.%return: ref %CompleteClass.3 = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @Class { -// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc4_13.2 [symbolic = constants.%T] -// CHECK:STDOUT: %.loc5: %.2 = field_decl x, element0 [template] +// CHECK:STDOUT: generic class @Class(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] // CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%Class.2 -// CHECK:STDOUT: .x = %.loc5 +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Class: type = class_type @Class, @Class(%T) [symbolic = %Class (constants.%Class.2)] +// CHECK:STDOUT: %.1: type = unbound_element_type @Class.%Class (%Class.2), @Class.%T (%T) [symbolic = %.1 (constants.%.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc4_13.2 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %.loc5: @Class.%.1 (%.2) = field_decl x, element0 [template] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Class.2 +// CHECK:STDOUT: .x = %.loc5 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @CompleteClass { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.4 -// CHECK:STDOUT: .n = imports.%import_ref.5 -// CHECK:STDOUT: .F = imports.%import_ref.6 +// CHECK:STDOUT: generic class @CompleteClass(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, @CompleteClass(%T) [symbolic = %CompleteClass (constants.%CompleteClass.2)] +// CHECK:STDOUT: %.1: type = unbound_element_type @CompleteClass.%CompleteClass (%CompleteClass.2), i32 [symbolic = %.1 (constants.%.5)] +// CHECK:STDOUT: %F.type: type = fn_type @F.1, @CompleteClass(%T) [symbolic = %F.type (constants.%F.type.2)] +// CHECK:STDOUT: %F: @CompleteClass.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.4 +// CHECK:STDOUT: .n = imports.%import_ref.5 +// CHECK:STDOUT: .F = imports.%import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F.1(constants.%T: type) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn() -> i32; // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F() -> %return: %CompleteClass.3 { +// CHECK:STDOUT: fn @F.2() -> %return: %CompleteClass.3 { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc9_16: i32 = int_literal 1 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_16: i32 = int_literal 1 [template = constants.%.8] // CHECK:STDOUT: %.loc9_17.1: %.4 = struct_literal (%.loc9_16) // CHECK:STDOUT: %.loc9_17.2: ref i32 = class_element_access %return, element0 -// CHECK:STDOUT: %.loc9_17.3: init i32 = initialize_from %.loc9_16 to %.loc9_17.2 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_17.3: init i32 = initialize_from %.loc9_16 to %.loc9_17.2 [template = constants.%.8] // CHECK:STDOUT: %.loc9_17.4: init %CompleteClass.3 = class_init (%.loc9_17.3), %return [template = constants.%struct] // CHECK:STDOUT: %.loc9_18: init %CompleteClass.3 = converted %.loc9_17.1, %.loc9_17.4 [template = constants.%struct] // CHECK:STDOUT: return %.loc9_18 to %return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%T); +// CHECK:STDOUT: specific @Class(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(i32); +// CHECK:STDOUT: specific @Class(@Class.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(@CompleteClass.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(i32) { +// CHECK:STDOUT: %T => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass => constants.%CompleteClass.3 +// CHECK:STDOUT: %.1 => constants.%.6 +// CHECK:STDOUT: %F.type => constants.%F.type.4 +// CHECK:STDOUT: %F => constants.%F.4 +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- use_foo.carbon // CHECK:STDOUT: @@ -339,19 +393,25 @@ class Class(U:! type) { // CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] // 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, invalid(%T) [symbolic] -// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, invalid(i32) [template] -// CHECK:STDOUT: %.3: type = ptr_type %.2 [template] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass, @CompleteClass(%T) [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.2 [template] -// CHECK:STDOUT: %F.2: %F.type.2 = 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] +// CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] +// CHECK:STDOUT: %.5: type = ptr_type %.2 [template] +// CHECK:STDOUT: %F.type.4: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.4: %F.type.4 = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %import_ref.1 = import_ref Main//foo, inst+6, unloaded // CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref Main//foo, inst+14, loaded [template = constants.%CompleteClass.1] -// CHECK:STDOUT: %import_ref.3: %F.type.1 = import_ref Main//foo, inst+55, loaded [template = constants.%F.1] +// CHECK:STDOUT: %import_ref.3: %F.type.4 = import_ref Main//foo, inst+55, loaded [template = constants.%F.4] // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: .Int32 = %import_ref.4 // CHECK:STDOUT: import Core//prelude @@ -365,7 +425,7 @@ class Class(U:! type) { // CHECK:STDOUT: %import_ref.4: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] // CHECK:STDOUT: %import_ref.5 = import_ref Main//foo, inst+18, unloaded // CHECK:STDOUT: %import_ref.6 = import_ref Main//foo, inst+28, unloaded -// CHECK:STDOUT: %import_ref.7: %F.type.2 = import_ref Main//foo, inst+35, loaded [template = constants.%F.2] +// CHECK:STDOUT: %import_ref.7: %F.type.2 = import_ref Main//foo, inst+35, loaded [template = constants.%F.1] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -386,11 +446,21 @@ class Class(U:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @CompleteClass { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.5 -// CHECK:STDOUT: .n = imports.%import_ref.6 -// CHECK:STDOUT: .F = imports.%import_ref.7 +// CHECK:STDOUT: generic class @CompleteClass(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, @CompleteClass(%T) [symbolic = %CompleteClass (constants.%CompleteClass.2)] +// CHECK:STDOUT: %.1: type = unbound_element_type @CompleteClass.%CompleteClass (%CompleteClass.2), i32 [symbolic = %.1 (constants.%.3)] +// CHECK:STDOUT: %F.type: type = fn_type @F.1, @CompleteClass(%T) [symbolic = %F.type (constants.%F.type.2)] +// CHECK:STDOUT: %F: @CompleteClass.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: .n = imports.%import_ref.6 +// CHECK:STDOUT: .F = imports.%import_ref.7 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; @@ -406,25 +476,43 @@ class Class(U:! type) { // CHECK:STDOUT: %.loc6_27.2: type = converted %.loc6_23.3, %.loc6_27.1 [template = constants.%CompleteClass.3] // CHECK:STDOUT: %v.var: ref %CompleteClass.3 = var v // CHECK:STDOUT: %v: ref %CompleteClass.3 = bind_name v, %v.var -// CHECK:STDOUT: %F.ref.loc6: %F.type.1 = name_ref F, imports.%import_ref.3 [template = constants.%F.1] +// CHECK:STDOUT: %F.ref.loc6: %F.type.4 = name_ref F, imports.%import_ref.3 [template = constants.%F.4] // CHECK:STDOUT: %.loc6_7: ref %CompleteClass.3 = splice_block %v.var {} // CHECK:STDOUT: %F.call.loc6: init %CompleteClass.3 = call %F.ref.loc6() to %.loc6_7 // CHECK:STDOUT: assign %v.var, %F.call.loc6 // CHECK:STDOUT: %v.ref: ref %CompleteClass.3 = name_ref v, %v -// CHECK:STDOUT: %F.ref.loc7: %F.type.2 = name_ref F, imports.%import_ref.7 [template = constants.%F.2] +// CHECK:STDOUT: %F.ref.loc7: %F.type.2 = name_ref F, imports.%import_ref.7 [template = constants.%F.1] // CHECK:STDOUT: %F.call.loc7: init i32 = call %F.ref.loc7() // CHECK:STDOUT: %.loc7_15.1: i32 = value_of_initializer %F.call.loc7 // CHECK:STDOUT: %.loc7_15.2: i32 = converted %F.call.loc7, %.loc7_15.1 // CHECK:STDOUT: return %.loc7_15.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1() -> %CompleteClass.3; +// CHECK:STDOUT: generic fn @F.1(constants.%T: type) { +// CHECK:STDOUT: !definition: // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2() -> i32; +// CHECK:STDOUT: fn() -> i32; +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%T); +// CHECK:STDOUT: fn @F.2() -> %CompleteClass.3; // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(i32); +// CHECK:STDOUT: specific @CompleteClass(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(@CompleteClass.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(i32) { +// CHECK:STDOUT: %T => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass => constants.%CompleteClass.3 +// CHECK:STDOUT: %.1 => constants.%.4 +// CHECK:STDOUT: %F.type => constants.%F.type.3 +// CHECK:STDOUT: %F => constants.%F.3 +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_use_foo.carbon // CHECK:STDOUT: @@ -438,18 +526,25 @@ class Class(U:! type) { // CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] // 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, invalid(%T) [symbolic] -// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, invalid(i32) [template] -// CHECK:STDOUT: %.3: type = ptr_type %.2 [template] -// CHECK:STDOUT: %F.type: type = fn_type @F [template] -// CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %.4: type = unbound_element_type %CompleteClass.2, i32 [symbolic] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass, @CompleteClass(%T) [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] +// CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] +// CHECK:STDOUT: %.5: type = ptr_type %.2 [template] +// CHECK:STDOUT: %F.type.4: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.4: %F.type.4 = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %import_ref.1 = import_ref Main//foo, inst+6, unloaded // CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref Main//foo, inst+14, loaded [template = constants.%CompleteClass.1] -// CHECK:STDOUT: %import_ref.3: %F.type = import_ref Main//foo, inst+55, loaded [template = constants.%F] +// CHECK:STDOUT: %import_ref.3: %F.type.4 = import_ref Main//foo, inst+55, loaded [template = constants.%F.4] // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: .Int32 = %import_ref.4 // CHECK:STDOUT: import Core//prelude @@ -462,7 +557,7 @@ class Class(U:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.4: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] // CHECK:STDOUT: %import_ref.5 = import_ref Main//foo, inst+18, unloaded -// CHECK:STDOUT: %import_ref.6: %.4 = import_ref Main//foo, inst+28, loaded [template = %.1] +// CHECK:STDOUT: %import_ref.6: %.3 = import_ref Main//foo, inst+28, loaded [template = %.1] // CHECK:STDOUT: %import_ref.7 = import_ref Main//foo, inst+35, unloaded // CHECK:STDOUT: } // CHECK:STDOUT: @@ -484,11 +579,21 @@ class Class(U:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @CompleteClass { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.5 -// CHECK:STDOUT: .n = imports.%import_ref.6 -// CHECK:STDOUT: .F = imports.%import_ref.7 +// CHECK:STDOUT: generic class @CompleteClass(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, @CompleteClass(%T) [symbolic = %CompleteClass (constants.%CompleteClass.2)] +// CHECK:STDOUT: %.1: type = unbound_element_type @CompleteClass.%CompleteClass (%CompleteClass.2), i32 [symbolic = %.1 (constants.%.3)] +// CHECK:STDOUT: %F.type: type = fn_type @F.1, @CompleteClass(%T) [symbolic = %F.type (constants.%F.type.2)] +// CHECK:STDOUT: %F: @CompleteClass.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: .n = imports.%import_ref.6 +// CHECK:STDOUT: .F = imports.%import_ref.7 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; @@ -504,21 +609,47 @@ class Class(U:! type) { // CHECK:STDOUT: %.loc6_27.2: type = converted %.loc6_23.3, %.loc6_27.1 [template = constants.%CompleteClass.3] // CHECK:STDOUT: %v.var: ref %CompleteClass.3 = var v // CHECK:STDOUT: %v: ref %CompleteClass.3 = bind_name v, %v.var -// CHECK:STDOUT: %F.ref: %F.type = name_ref F, imports.%import_ref.3 [template = constants.%F] +// CHECK:STDOUT: %F.ref: %F.type.4 = name_ref F, imports.%import_ref.3 [template = constants.%F.4] // CHECK:STDOUT: %.loc6_7: ref %CompleteClass.3 = splice_block %v.var {} // CHECK:STDOUT: %F.call: init %CompleteClass.3 = call %F.ref() to %.loc6_7 // CHECK:STDOUT: assign %v.var, %F.call // CHECK:STDOUT: %v.ref: ref %CompleteClass.3 = name_ref v, %v -// CHECK:STDOUT: %n.ref: %.4 = name_ref n, imports.%import_ref.6 [template = imports.%.1] +// CHECK:STDOUT: %n.ref: %.3 = name_ref n, imports.%import_ref.6 [template = imports.%.1] // CHECK:STDOUT: %.loc12: i32 = class_element_access , element0 [template = ] // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F() -> %CompleteClass.3; +// CHECK:STDOUT: generic fn @F.1(constants.%T: type) { +// CHECK:STDOUT: !definition: // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%T); +// CHECK:STDOUT: fn() -> i32; +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(i32); +// CHECK:STDOUT: fn @F.2() -> %CompleteClass.3; +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass => constants.%CompleteClass.2 +// CHECK:STDOUT: %.1 => constants.%.3 +// CHECK:STDOUT: %F.type => constants.%F.type.2 +// CHECK:STDOUT: %F => constants.%F.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(@CompleteClass.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(i32) { +// CHECK:STDOUT: %T => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass => constants.%CompleteClass.3 +// CHECK:STDOUT: %.1 => constants.%.4 +// CHECK:STDOUT: %F.type => constants.%F.type.3 +// CHECK:STDOUT: %F => constants.%F.3 +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_generic_arg_mismatch.carbon // CHECK:STDOUT: @@ -530,21 +661,32 @@ class Class(U:! type) { // CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] // 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, invalid(%T) [symbolic] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass, @CompleteClass(%T) [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: %.3: type = ptr_type i32 [template] -// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, invalid(%.3) [template] -// CHECK:STDOUT: %.4: type = ptr_type %.2 [template] -// CHECK:STDOUT: %CompleteClass.4: type = class_type @CompleteClass, invalid(i32) [template] -// CHECK:STDOUT: %F.type: type = fn_type @F [template] -// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type i32 [template] +// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, @CompleteClass(%.4) [template] +// CHECK:STDOUT: %.5: type = unbound_element_type %CompleteClass.3, i32 [template] +// CHECK:STDOUT: %F.type.3: type = fn_type @F.1, @CompleteClass(%.4) [template] +// CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] +// CHECK:STDOUT: %.6: type = ptr_type %.2 [template] +// CHECK:STDOUT: %CompleteClass.4: type = class_type @CompleteClass, @CompleteClass(i32) [template] +// CHECK:STDOUT: %F.type.4: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.4: %F.type.4 = struct_value () [template] +// CHECK:STDOUT: %.7: type = unbound_element_type %CompleteClass.4, i32 [template] +// CHECK:STDOUT: %F.type.5: type = fn_type @F.1, @CompleteClass(i32) [template] +// CHECK:STDOUT: %F.5: %F.type.5 = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %import_ref.1 = import_ref Main//foo, inst+6, unloaded // CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref Main//foo, inst+14, loaded [template = constants.%CompleteClass.1] -// CHECK:STDOUT: %import_ref.3: %F.type = import_ref Main//foo, inst+55, loaded [template = constants.%F] +// CHECK:STDOUT: %import_ref.3: %F.type.4 = import_ref Main//foo, inst+55, loaded [template = constants.%F.4] // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: .Int32 = %import_ref.7 // CHECK:STDOUT: import Core//prelude @@ -574,11 +716,21 @@ class Class(U:! type) { // CHECK:STDOUT: %Use.decl: %Use.type = fn_decl @Use [template = constants.%Use] {} // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @CompleteClass { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.4 -// CHECK:STDOUT: .n = imports.%import_ref.5 -// CHECK:STDOUT: .F = imports.%import_ref.6 +// CHECK:STDOUT: generic class @CompleteClass(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, @CompleteClass(%T) [symbolic = %CompleteClass (constants.%CompleteClass.2)] +// CHECK:STDOUT: %.1: type = unbound_element_type @CompleteClass.%CompleteClass (%CompleteClass.2), i32 [symbolic = %.1 (constants.%.3)] +// CHECK:STDOUT: %F.type: type = fn_type @F.1, @CompleteClass(%T) [symbolic = %F.type (constants.%F.type.2)] +// CHECK:STDOUT: %F: @CompleteClass.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.4 +// CHECK:STDOUT: .n = imports.%import_ref.5 +// CHECK:STDOUT: .F = imports.%import_ref.6 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Use() { @@ -587,28 +739,56 @@ class Class(U:! type) { // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] // CHECK:STDOUT: %.loc11_27.1: type = value_of_initializer %int.make_type_32 [template = i32] // CHECK:STDOUT: %.loc11_27.2: type = converted %int.make_type_32, %.loc11_27.1 [template = i32] -// CHECK:STDOUT: %.loc11_27.3: type = ptr_type i32 [template = constants.%.3] +// CHECK:STDOUT: %.loc11_27.3: type = ptr_type i32 [template = constants.%.4] // CHECK:STDOUT: %.loc11_23: init type = call %CompleteClass.ref(%.loc11_27.3) [template = constants.%CompleteClass.3] // CHECK:STDOUT: %.loc11_28.1: type = value_of_initializer %.loc11_23 [template = constants.%CompleteClass.3] // CHECK:STDOUT: %.loc11_28.2: type = converted %.loc11_23, %.loc11_28.1 [template = constants.%CompleteClass.3] // CHECK:STDOUT: %v.var: ref %CompleteClass.3 = var v // CHECK:STDOUT: %v: ref %CompleteClass.3 = bind_name v, %v.var -// CHECK:STDOUT: %F.ref: %F.type = name_ref F, imports.%import_ref.3 [template = constants.%F] +// CHECK:STDOUT: %F.ref: %F.type.4 = name_ref F, imports.%import_ref.3 [template = constants.%F.4] // CHECK:STDOUT: %.loc11_33: ref %CompleteClass.4 = temporary_storage // CHECK:STDOUT: %F.call: init %CompleteClass.4 = call %F.ref() to %.loc11_33 // CHECK:STDOUT: assign %v.var, // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F.1(constants.%T: type) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn() -> i32; +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F() -> %CompleteClass.4; +// CHECK:STDOUT: fn @F.2() -> %CompleteClass.4; // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%T); +// CHECK:STDOUT: specific @CompleteClass(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%.3); +// CHECK:STDOUT: specific @CompleteClass(@CompleteClass.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(i32); +// CHECK:STDOUT: specific @CompleteClass(constants.%.4) { +// CHECK:STDOUT: %T => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass => constants.%CompleteClass.3 +// CHECK:STDOUT: %.1 => constants.%.5 +// CHECK:STDOUT: %F.type => constants.%F.type.3 +// CHECK:STDOUT: %F => constants.%F.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CompleteClass(i32) { +// CHECK:STDOUT: %T => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %CompleteClass => constants.%CompleteClass.4 +// CHECK:STDOUT: %.1 => constants.%.7 +// CHECK:STDOUT: %F.type => constants.%F.type.5 +// CHECK:STDOUT: %F => constants.%F.5 +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_bad_foo.impl.carbon // CHECK:STDOUT: @@ -618,7 +798,7 @@ class Class(U:! type) { // CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template] // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %Class.2: type = class_type @Class, invalid(%T) [symbolic] +// CHECK:STDOUT: %Class.2: type = class_type @Class, @Class(%T) [symbolic] // CHECK:STDOUT: %.type: type = generic_class_type @.1 [template] // CHECK:STDOUT: %.2: %.type = struct_value () [template] // CHECK:STDOUT: %.3: type = class_type @.1, @.1(%U) [symbolic] @@ -655,7 +835,11 @@ class Class(U:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @Class; +// CHECK:STDOUT: generic class @Class(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: class; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic class @.1(file.%U.loc14_13.2: type) { // CHECK:STDOUT: %U: type = bind_symbolic_name U 0 [symbolic = %U (constants.%U)] @@ -672,7 +856,9 @@ class Class(U:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%T); +// CHECK:STDOUT: specific @Class(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @.1(constants.%U) { // CHECK:STDOUT: %U => constants.%U diff --git a/toolchain/check/testdata/class/syntactic_merge_literal.carbon b/toolchain/check/testdata/class/syntactic_merge_literal.carbon index c59ebd7346af..55d4b8cf2b32 100644 --- a/toolchain/check/testdata/class/syntactic_merge_literal.carbon +++ b/toolchain/check/testdata/class/syntactic_merge_literal.carbon @@ -12,21 +12,21 @@ // --- int_match.carbon -class C(a: i32) {} -class D(b: C(1_000)); -class D(b: C(1_000)) {} +class C(a:! i32) {} +class D(b:! C(1_000)); +class D(b:! C(1_000)) {} // --- fail_int_mismatch.carbon -class C(a: i32) {} -class D(b: C(1000)); -// CHECK:STDERR: fail_int_mismatch.carbon:[[@LINE+6]]:14: ERROR: Redeclaration syntax differs here. -// CHECK:STDERR: class D(b: C(1_000)) {} -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: fail_int_mismatch.carbon:[[@LINE-4]]:14: Comparing with previous declaration here. -// CHECK:STDERR: class D(b: C(1000)); -// CHECK:STDERR: ^~~~ -class D(b: C(1_000)) {} +class C(a:! i32) {} +class D(b:! C(1000)); +// CHECK:STDERR: fail_int_mismatch.carbon:[[@LINE+6]]:15: ERROR: Redeclaration syntax differs here. +// CHECK:STDERR: class D(b:! C(1_000)) {} +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: fail_int_mismatch.carbon:[[@LINE-4]]:15: Comparing with previous declaration here. +// CHECK:STDERR: class D(b:! C(1000)); +// CHECK:STDERR: ^~~~ +class D(b:! C(1_000)) {} // CHECK:STDOUT: --- int_match.carbon // CHECK:STDOUT: @@ -34,15 +34,17 @@ class D(b: C(1_000)) {} // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] // CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %a: i32 = bind_symbolic_name a 0 [symbolic] // CHECK:STDOUT: %C.type: type = generic_class_type @C [template] // CHECK:STDOUT: %C.1: %C.type = struct_value () [template] -// CHECK:STDOUT: %C.2: type = class_type @C [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%a) [symbolic] // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: i32 = int_literal 1000 [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%.3) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%.3) [template] +// CHECK:STDOUT: %b: %C.3 = bind_symbolic_name b 0 [symbolic] // CHECK:STDOUT: %D.type: type = generic_class_type @D [template] // CHECK:STDOUT: %D.1: %D.type = struct_value () [template] -// CHECK:STDOUT: %D.2: type = class_type @D [template] +// CHECK:STDOUT: %D.2: type = class_type @D, @D(%b) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -68,44 +70,66 @@ class D(b: C(1_000)) {} // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %C.decl: %C.type = class_decl @C [template = constants.%C.1] { // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] -// CHECK:STDOUT: %.loc2_12.1: type = value_of_initializer %int.make_type_32 [template = i32] -// CHECK:STDOUT: %.loc2_12.2: type = converted %int.make_type_32, %.loc2_12.1 [template = i32] +// CHECK:STDOUT: %.loc2_13.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc2_13.2: type = converted %int.make_type_32, %.loc2_13.1 [template = i32] // CHECK:STDOUT: %a.loc2_9.1: i32 = param a -// CHECK:STDOUT: %a.loc2_9.2: i32 = bind_name a, %a.loc2_9.1 +// CHECK:STDOUT: %a.loc2_9.2: i32 = bind_symbolic_name a 0, %a.loc2_9.1 [symbolic = @C.%a (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %D.decl.loc3: %D.type = class_decl @D [template = constants.%D.1] { // CHECK:STDOUT: %C.ref.loc3: %C.type = name_ref C, %C.decl [template = constants.%C.1] -// CHECK:STDOUT: %.loc3_14: i32 = int_literal 1000 [template = constants.%.3] -// CHECK:STDOUT: %.loc3_13: init type = call %C.ref.loc3(%.loc3_14) [template = constants.%C.3] -// CHECK:STDOUT: %.loc3_19.1: type = value_of_initializer %.loc3_13 [template = constants.%C.3] -// CHECK:STDOUT: %.loc3_19.2: type = converted %.loc3_13, %.loc3_19.1 [template = constants.%C.3] +// CHECK:STDOUT: %.loc3_15: i32 = int_literal 1000 [template = constants.%.3] +// CHECK:STDOUT: %.loc3_14: init type = call %C.ref.loc3(%.loc3_15) [template = constants.%C.3] +// CHECK:STDOUT: %.loc3_20.1: type = value_of_initializer %.loc3_14 [template = constants.%C.3] +// CHECK:STDOUT: %.loc3_20.2: type = converted %.loc3_14, %.loc3_20.1 [template = constants.%C.3] // CHECK:STDOUT: %b.loc3_9.1: %C.3 = param b -// CHECK:STDOUT: %b.loc3_9.2: %C.3 = bind_name b, %b.loc3_9.1 +// CHECK:STDOUT: %b.loc3_9.2: %C.3 = bind_symbolic_name b 0, %b.loc3_9.1 [symbolic = @D.%b (constants.%b)] // CHECK:STDOUT: } // CHECK:STDOUT: %D.decl.loc4: %D.type = class_decl @D [template = constants.%D.1] { // CHECK:STDOUT: %C.ref.loc4: %C.type = name_ref C, %C.decl [template = constants.%C.1] -// CHECK:STDOUT: %.loc4_14: i32 = int_literal 1000 [template = constants.%.3] -// CHECK:STDOUT: %.loc4_13: init type = call %C.ref.loc4(%.loc4_14) [template = constants.%C.3] -// CHECK:STDOUT: %.loc4_19.1: type = value_of_initializer %.loc4_13 [template = constants.%C.3] -// CHECK:STDOUT: %.loc4_19.2: type = converted %.loc4_13, %.loc4_19.1 [template = constants.%C.3] +// CHECK:STDOUT: %.loc4_15: i32 = int_literal 1000 [template = constants.%.3] +// CHECK:STDOUT: %.loc4_14: init type = call %C.ref.loc4(%.loc4_15) [template = constants.%C.3] +// CHECK:STDOUT: %.loc4_20.1: type = value_of_initializer %.loc4_14 [template = constants.%C.3] +// CHECK:STDOUT: %.loc4_20.2: type = converted %.loc4_14, %.loc4_20.1 [template = constants.%C.3] // CHECK:STDOUT: %b.loc4_9.1: %C.3 = param b -// CHECK:STDOUT: %b.loc4_9.2: %C.3 = bind_name b, %b.loc4_9.1 +// CHECK:STDOUT: %b.loc4_9.2: %C.3 = bind_symbolic_name b 0, %b.loc4_9.1 [symbolic = constants.%b] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%C.2 +// CHECK:STDOUT: generic class @C(file.%a.loc2_9.2: i32) { +// CHECK:STDOUT: %a: i32 = bind_symbolic_name a 0 [symbolic = %a (constants.%a)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @D { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%D.2 +// CHECK:STDOUT: generic class @D(file.%b.loc3_9.2: %C.3) { +// CHECK:STDOUT: %b: %C.3 = bind_symbolic_name b 0 [symbolic = %b (constants.%b)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%D.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%.3); +// CHECK:STDOUT: specific @C(constants.%a) { +// CHECK:STDOUT: %a => constants.%a +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%.3) { +// CHECK:STDOUT: %a => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @D(constants.%b) { +// CHECK:STDOUT: %b => constants.%b +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_int_mismatch.carbon // CHECK:STDOUT: @@ -113,18 +137,20 @@ class D(b: C(1_000)) {} // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] // CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %a: i32 = bind_symbolic_name a 0 [symbolic] // CHECK:STDOUT: %C.type: type = generic_class_type @C [template] // CHECK:STDOUT: %C.1: %C.type = struct_value () [template] -// CHECK:STDOUT: %C.2: type = class_type @C [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%a) [symbolic] // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: i32 = int_literal 1000 [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%.3) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%.3) [template] +// CHECK:STDOUT: %b: %C.3 = bind_symbolic_name b 0 [symbolic] // CHECK:STDOUT: %D.type: type = generic_class_type @D [template] // CHECK:STDOUT: %D.1: %D.type = struct_value () [template] -// CHECK:STDOUT: %D.2: type = class_type @D [template] +// CHECK:STDOUT: %D.2: type = class_type @D, @D(%b) [symbolic] // CHECK:STDOUT: %.type: type = generic_class_type @.1 [template] // CHECK:STDOUT: %.4: %.type = struct_value () [template] -// CHECK:STDOUT: %.5: type = class_type @.1 [template] +// CHECK:STDOUT: %.5: type = class_type @.1, @.1(%b) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -150,44 +176,74 @@ class D(b: C(1_000)) {} // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %C.decl: %C.type = class_decl @C [template = constants.%C.1] { // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] -// CHECK:STDOUT: %.loc2_12.1: type = value_of_initializer %int.make_type_32 [template = i32] -// CHECK:STDOUT: %.loc2_12.2: type = converted %int.make_type_32, %.loc2_12.1 [template = i32] +// CHECK:STDOUT: %.loc2_13.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc2_13.2: type = converted %int.make_type_32, %.loc2_13.1 [template = i32] // CHECK:STDOUT: %a.loc2_9.1: i32 = param a -// CHECK:STDOUT: %a.loc2_9.2: i32 = bind_name a, %a.loc2_9.1 +// CHECK:STDOUT: %a.loc2_9.2: i32 = bind_symbolic_name a 0, %a.loc2_9.1 [symbolic = @C.%a (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %D.decl: %D.type = class_decl @D [template = constants.%D.1] { // CHECK:STDOUT: %C.ref.loc3: %C.type = name_ref C, %C.decl [template = constants.%C.1] -// CHECK:STDOUT: %.loc3_14: i32 = int_literal 1000 [template = constants.%.3] -// CHECK:STDOUT: %.loc3_13: init type = call %C.ref.loc3(%.loc3_14) [template = constants.%C.3] -// CHECK:STDOUT: %.loc3_18.1: type = value_of_initializer %.loc3_13 [template = constants.%C.3] -// CHECK:STDOUT: %.loc3_18.2: type = converted %.loc3_13, %.loc3_18.1 [template = constants.%C.3] +// CHECK:STDOUT: %.loc3_15: i32 = int_literal 1000 [template = constants.%.3] +// CHECK:STDOUT: %.loc3_14: init type = call %C.ref.loc3(%.loc3_15) [template = constants.%C.3] +// CHECK:STDOUT: %.loc3_19.1: type = value_of_initializer %.loc3_14 [template = constants.%C.3] +// CHECK:STDOUT: %.loc3_19.2: type = converted %.loc3_14, %.loc3_19.1 [template = constants.%C.3] // CHECK:STDOUT: %b.loc3_9.1: %C.3 = param b -// CHECK:STDOUT: %b.loc3_9.2: %C.3 = bind_name b, %b.loc3_9.1 +// CHECK:STDOUT: %b.loc3_9.2: %C.3 = bind_symbolic_name b 0, %b.loc3_9.1 [symbolic = @D.%b (constants.%b)] // CHECK:STDOUT: } // CHECK:STDOUT: %.decl: %.type = class_decl @.1 [template = constants.%.4] { // CHECK:STDOUT: %C.ref.loc10: %C.type = name_ref C, %C.decl [template = constants.%C.1] -// CHECK:STDOUT: %.loc10_14: i32 = int_literal 1000 [template = constants.%.3] -// CHECK:STDOUT: %.loc10_13: init type = call %C.ref.loc10(%.loc10_14) [template = constants.%C.3] -// CHECK:STDOUT: %.loc10_19.1: type = value_of_initializer %.loc10_13 [template = constants.%C.3] -// CHECK:STDOUT: %.loc10_19.2: type = converted %.loc10_13, %.loc10_19.1 [template = constants.%C.3] +// CHECK:STDOUT: %.loc10_15: i32 = int_literal 1000 [template = constants.%.3] +// CHECK:STDOUT: %.loc10_14: init type = call %C.ref.loc10(%.loc10_15) [template = constants.%C.3] +// CHECK:STDOUT: %.loc10_20.1: type = value_of_initializer %.loc10_14 [template = constants.%C.3] +// CHECK:STDOUT: %.loc10_20.2: type = converted %.loc10_14, %.loc10_20.1 [template = constants.%C.3] // CHECK:STDOUT: %b.loc10_9.1: %C.3 = param b -// CHECK:STDOUT: %b.loc10_9.2: %C.3 = bind_name b, %b.loc10_9.1 +// CHECK:STDOUT: %b.loc10_9.2: %C.3 = bind_symbolic_name b 0, %b.loc10_9.1 [symbolic = @.1.%b (constants.%b)] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%C.2 +// CHECK:STDOUT: generic class @C(file.%a.loc2_9.2: i32) { +// CHECK:STDOUT: %a: i32 = bind_symbolic_name a 0 [symbolic = %a (constants.%a)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @D; +// CHECK:STDOUT: generic class @D(file.%b.loc3_9.2: %C.3) { +// CHECK:STDOUT: %b: %C.3 = bind_symbolic_name b 0 [symbolic = %b (constants.%b)] // CHECK:STDOUT: -// CHECK:STDOUT: class @.1 { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%.5 +// CHECK:STDOUT: class; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @.1(file.%b.loc10_9.2: %C.3) { +// CHECK:STDOUT: %b: %C.3 = bind_symbolic_name b 0 [symbolic = %b (constants.%b)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%.5 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%.3); +// CHECK:STDOUT: specific @C(constants.%a) { +// CHECK:STDOUT: %a => constants.%a +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%.3) { +// CHECK:STDOUT: %a => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @D(constants.%b) { +// CHECK:STDOUT: %b => constants.%b +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @.1(constants.%b) { +// CHECK:STDOUT: %b => constants.%b +// CHECK:STDOUT: } // 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 53bfbfd84f45..50011b20ffb2 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 @@ -191,7 +191,11 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4); // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.1[@impl.%self.loc7_9.2: i32](@impl.%other.loc7_21.2: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self](%other: %Self) -> %Self; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> %Self; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/lookup/import.carbon b/toolchain/check/testdata/impl/lookup/import.carbon index de2e241014e9..36919722e9b5 100644 --- a/toolchain/check/testdata/impl/lookup/import.carbon +++ b/toolchain/check/testdata/impl/lookup/import.carbon @@ -197,7 +197,10 @@ fn G(c: Impl.C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: generic fn @F.1(constants.%Self: %.2) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2(); // 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 d4426f6d087d..e9afabf5dff2 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon @@ -172,7 +172,10 @@ fn G(c: Impl.C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: generic fn @F.1(constants.%Self: %.2) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2(); // 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 b0ad6b59ea54..081b1639f01d 100644 --- a/toolchain/check/testdata/impl/no_prelude/import_self.carbon +++ b/toolchain/check/testdata/impl/no_prelude/import_self.carbon @@ -170,7 +170,11 @@ fn F(x: (), y: ()) -> () { // CHECK:STDOUT: return %.loc7_53 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self](%other: %Self) -> %Self; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> %Self; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F(%x: %.1, %y: %.1) -> %.1 { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/index/fail_negative_indexing.carbon b/toolchain/check/testdata/index/fail_negative_indexing.carbon index ea26db0649c4..f80850f9b200 100644 --- a/toolchain/check/testdata/index/fail_negative_indexing.carbon +++ b/toolchain/check/testdata/index/fail_negative_indexing.carbon @@ -88,7 +88,11 @@ var b: i32 = a[-10]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op[%self: %Self]() -> %Self; +// CHECK:STDOUT: generic fn @Op(constants.%Self: %.8) { +// CHECK:STDOUT: %Self: %.8 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self]() -> %Self; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/interface/no_prelude/generic_import.carbon b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon index f8dfa7d9cc3f..9fd2cdd0f2ea 100644 --- a/toolchain/check/testdata/interface/no_prelude/generic_import.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon @@ -99,21 +99,26 @@ impl C as AddWith(C) { // CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %AddWith: %AddWith.type = struct_value () [template] // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %.3: type = interface_type @AddWith, invalid(%T) [symbolic] +// CHECK:STDOUT: %.3: type = interface_type @AddWith, @AddWith(%T) [symbolic] // CHECK:STDOUT: %Self: %.3 = bind_symbolic_name Self 1 [symbolic] -// CHECK:STDOUT: %.4: type = interface_type @AddWith, invalid(%C) [template] // 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.2 [template] -// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template] -// CHECK:STDOUT: %.5: = interface_witness (%F.1) [template] +// CHECK:STDOUT: %F.type.2: type = fn_type @F.1, @AddWith(%T) [symbolic] +// CHECK:STDOUT: %.4: type = assoc_entity_type @AddWith, %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: %.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] +// CHECK:STDOUT: %.7: = interface_witness (%F.3) [template] // CHECK:STDOUT: } // 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+10, unloaded -// CHECK:STDOUT: %import_ref.3 = import_ref Main//a, inst+16, unloaded -// CHECK:STDOUT: %import_ref.4: %F.type.2 = import_ref Main//a, inst+12, loaded [template = constants.%F.2] +// 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: %F.type.2 = import_ref Main//a, inst+12, loaded [template = constants.%F.1] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -123,26 +128,38 @@ impl C as AddWith(C) { // CHECK:STDOUT: } // CHECK:STDOUT: %default.import = import // CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} -// CHECK:STDOUT: %.loc7_20.1: type = value_of_initializer %.loc7_18 [template = constants.%.4] -// CHECK:STDOUT: %.loc7_20.2: type = converted %.loc7_18, %.loc7_20.1 [template = constants.%.4] +// CHECK:STDOUT: %.loc7_20.1: type = value_of_initializer %.loc7_18 [template = constants.%.6] +// CHECK:STDOUT: %.loc7_20.2: type = converted %.loc7_18, %.loc7_20.1 [template = constants.%.6] // CHECK:STDOUT: impl_decl @impl { // CHECK:STDOUT: %C.ref.loc7_6: type = name_ref C, %C.decl [template = constants.%C] // CHECK:STDOUT: %AddWith.ref: %AddWith.type = name_ref AddWith, imports.%import_ref.1 [template = constants.%AddWith] // CHECK:STDOUT: %C.ref.loc7_19: type = name_ref C, %C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc7_18: init type = call %AddWith.ref(%C.ref.loc7_19) [template = constants.%.4] +// CHECK:STDOUT: %.loc7_18: init type = call %AddWith.ref(%C.ref.loc7_19) [template = constants.%.6] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: interface @AddWith { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.2 -// CHECK:STDOUT: .F = imports.%import_ref.3 -// CHECK:STDOUT: witness = (imports.%import_ref.4) +// CHECK:STDOUT: generic interface @AddWith(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.1: type = interface_type @AddWith, @AddWith(%T) [symbolic = %.1 (constants.%.3)] +// CHECK:STDOUT: %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)] +// 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, @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: +// 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: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl: %C as %.4 { -// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} -// CHECK:STDOUT: %.1: = interface_witness (%F.decl) [template = constants.%.5] +// CHECK:STDOUT: impl @impl: %C as %.6 { +// CHECK:STDOUT: %F.decl: %F.type.3 = fn_decl @F.2 [template = constants.%F.3] {} +// CHECK:STDOUT: %.1: = interface_witness (%F.decl) [template = constants.%.7] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .F = %F.decl @@ -154,14 +171,25 @@ impl C as AddWith(C) { // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1() { +// CHECK:STDOUT: generic fn @F.1(constants.%T: type, constants.%Self: %.3) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(); +// CHECK:STDOUT: specific @AddWith(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%T); +// CHECK:STDOUT: specific @AddWith(@AddWith.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%C); +// CHECK:STDOUT: specific @AddWith(constants.%C) { +// CHECK:STDOUT: %T => constants.%C +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/import.carbon b/toolchain/check/testdata/interface/no_prelude/import.carbon index 33e82e4e3aca..11bc5f8beb28 100644 --- a/toolchain/check/testdata/interface/no_prelude/import.carbon +++ b/toolchain/check/testdata/interface/no_prelude/import.carbon @@ -281,9 +281,15 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: generic fn @F.1(constants.%Self.2: %.3) { // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(); +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F.2(constants.%Self.3: %.4) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: 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 b4c5d2e3ab9a..cfd9f513c320 100644 --- a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon @@ -90,5 +90,9 @@ fn Main() -> i32 { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op[%self: %Self](%other: %Self) -> %Self; +// CHECK:STDOUT: generic fn @Op(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> %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 df5159403f38..4656fa1abacc 100644 --- a/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon @@ -83,5 +83,9 @@ fn Main() -> i32 { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op[%self: %Self](%other: %Self) -> %Self; +// CHECK:STDOUT: generic fn @Op(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> %Self; +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/add.carbon b/toolchain/check/testdata/operators/overloaded/add.carbon index ab84fb10ed2e..4f672f53accd 100644 --- a/toolchain/check/testdata/operators/overloaded/add.carbon +++ b/toolchain/check/testdata/operators/overloaded/add.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/bit_and.carbon b/toolchain/check/testdata/operators/overloaded/bit_and.carbon index 9412cc774225..f24cb300430b 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_and.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_and.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/bit_complement.carbon b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon index df7a9f91a4b5..97449423a9b1 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_complement.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon @@ -120,7 +120,11 @@ fn TestOp(a: C) -> C { // CHECK:STDOUT: return %.loc19_14 to @impl.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self]() -> %Self; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self]() -> %Self; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/bit_or.carbon b/toolchain/check/testdata/operators/overloaded/bit_or.carbon index 383fad1100ce..b0272dbe820f 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_or.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_or.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/bit_xor.carbon b/toolchain/check/testdata/operators/overloaded/bit_xor.carbon index ae06be9bc1c6..10a5918591ef 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_xor.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_xor.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/dec.carbon b/toolchain/check/testdata/operators/overloaded/dec.carbon index 3d92dd6848d8..ae6fbe9ccbe8 100644 --- a/toolchain/check/testdata/operators/overloaded/dec.carbon +++ b/toolchain/check/testdata/operators/overloaded/dec.carbon @@ -109,7 +109,12 @@ fn TestOp() { // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.1[addr @impl.%self.loc18_14.3: %.3](); // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[addr %self: %.5](); +// CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.2.%Self (%Self) [symbolic = %.2 (constants.%.5)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.5](); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/div.carbon b/toolchain/check/testdata/operators/overloaded/div.carbon index 41c4adddae85..c121c27c4688 100644 --- a/toolchain/check/testdata/operators/overloaded/div.carbon +++ b/toolchain/check/testdata/operators/overloaded/div.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/eq.carbon b/toolchain/check/testdata/operators/overloaded/eq.carbon index 8fca3f1762df..288cfc035172 100644 --- a/toolchain/check/testdata/operators/overloaded/eq.carbon +++ b/toolchain/check/testdata/operators/overloaded/eq.carbon @@ -224,9 +224,17 @@ fn TestLhsBad(a: D, b: C) -> bool { // CHECK:STDOUT: // CHECK:STDOUT: fn @NotEqual.1[@impl.%self.loc8_15.2: %C](@impl.%other.loc8_24.2: %C) -> bool; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Equal.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @Equal.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] // CHECK:STDOUT: -// CHECK:STDOUT: fn @NotEqual.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @NotEqual.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestEqual(%a: %C, %b: %C) -> bool { // CHECK:STDOUT: !entry: @@ -357,7 +365,11 @@ fn TestLhsBad(a: D, b: C) -> bool { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Equal[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @Equal(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestNotEqual(%a: %D, %b: %D) -> bool { // CHECK:STDOUT: !entry: @@ -366,7 +378,11 @@ fn TestLhsBad(a: D, b: C) -> bool { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @NotEqual[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @NotEqual(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_no_impl_for_args.carbon // CHECK:STDOUT: @@ -521,9 +537,17 @@ fn TestLhsBad(a: D, b: C) -> bool { // CHECK:STDOUT: // CHECK:STDOUT: fn @NotEqual.1[@impl.%self.loc9_15.2: %C](@impl.%other.loc9_24.2: %C) -> bool; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Equal.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @Equal.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] // CHECK:STDOUT: -// CHECK:STDOUT: fn @NotEqual.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @NotEqual.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestRhsBad(%a: %C, %b: %D) -> bool { // CHECK:STDOUT: !entry: 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 57d2211edf0c..a8634cc25aec 100644 --- a/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon +++ b/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon @@ -186,11 +186,21 @@ fn TestAddAssignNonRef(a: C, b: C) { // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.1[addr @impl.1.%self.loc16_14.3: %.3](); // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[addr %self: %.5](); +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.2.%Self (%Self.1) [symbolic = %.2 (constants.%.5)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.5](); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc19_14.3: %.3](@impl.2.%other.loc19_24.2: %C); // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.7) { +// CHECK:STDOUT: %Self: %.7 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestIncNonRef(%a: %C) { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon b/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon index c72e746f8b40..57bb9d4eae84 100644 --- a/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon +++ b/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon @@ -192,7 +192,11 @@ fn TestRef(b: C) { // CHECK:STDOUT: return to %return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.1[%self: %Self.1]() -> %Self.1; +// CHECK:STDOUT: generic fn @Op.1(constants.%Self.1: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1]() -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestBinary(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: @@ -201,7 +205,11 @@ fn TestRef(b: C) { // CHECK:STDOUT: return to %return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.2](%other: %Self.2) -> %Self.2; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.2: %.7) { +// CHECK:STDOUT: %Self: %.7 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.2](%other: %Self.2) -> %Self.2; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestRef(%b: %C) { // CHECK:STDOUT: !entry: @@ -218,7 +226,17 @@ fn TestRef(b: C) { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.3[addr %self: %.11](%other: %Self.3); +// CHECK:STDOUT: generic fn @Op.3(constants.%Self.3: %.10) { +// CHECK:STDOUT: %Self: %.10 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.3)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.3.%Self (%Self.3) [symbolic = %.2 (constants.%.11)] // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.15](); +// CHECK:STDOUT: fn[addr %self: %.11](%other: %Self.3); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.4: %.14) { +// CHECK:STDOUT: %Self: %.14 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.4)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.4) [symbolic = %.2 (constants.%.15)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.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 91052af2288d..a2298d865e9e 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 @@ -201,11 +201,20 @@ fn TestAssign(b: D) { // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc17_9.2: %C](@impl.1.%other.loc17_18.2: %C) -> %C; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc20_14.3: %.6](@impl.2.%other.loc20_24.2: %C); // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.7](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.5) { +// CHECK:STDOUT: %Self: %.5 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.7)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.7](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Test(%a: %C, %b: %D) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/inc.carbon b/toolchain/check/testdata/operators/overloaded/inc.carbon index 67ff265a7895..1caaf7119230 100644 --- a/toolchain/check/testdata/operators/overloaded/inc.carbon +++ b/toolchain/check/testdata/operators/overloaded/inc.carbon @@ -109,7 +109,12 @@ fn TestOp() { // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.1[addr @impl.%self.loc18_14.3: %.3](); // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[addr %self: %.5](); +// CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.2.%Self (%Self) [symbolic = %.2 (constants.%.5)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.5](); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/left_shift.carbon b/toolchain/check/testdata/operators/overloaded/left_shift.carbon index 41a3a268d2b2..7fcec7dff794 100644 --- a/toolchain/check/testdata/operators/overloaded/left_shift.carbon +++ b/toolchain/check/testdata/operators/overloaded/left_shift.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/mod.carbon b/toolchain/check/testdata/operators/overloaded/mod.carbon index 56d611c839f6..b399cbc84435 100644 --- a/toolchain/check/testdata/operators/overloaded/mod.carbon +++ b/toolchain/check/testdata/operators/overloaded/mod.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/mul.carbon b/toolchain/check/testdata/operators/overloaded/mul.carbon index 422348232bf5..0cf4d35d18ab 100644 --- a/toolchain/check/testdata/operators/overloaded/mul.carbon +++ b/toolchain/check/testdata/operators/overloaded/mul.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/negate.carbon b/toolchain/check/testdata/operators/overloaded/negate.carbon index 3a2e0f8dc5e3..846bf2a1ad18 100644 --- a/toolchain/check/testdata/operators/overloaded/negate.carbon +++ b/toolchain/check/testdata/operators/overloaded/negate.carbon @@ -120,7 +120,11 @@ fn TestOp(a: C) -> C { // CHECK:STDOUT: return %.loc19_14 to @impl.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self]() -> %Self; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self]() -> %Self; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/ordered.carbon b/toolchain/check/testdata/operators/overloaded/ordered.carbon index c48daa37cc73..af1d4a6ae839 100644 --- a/toolchain/check/testdata/operators/overloaded/ordered.carbon +++ b/toolchain/check/testdata/operators/overloaded/ordered.carbon @@ -299,13 +299,29 @@ fn TestGreaterEqual(a: D, b: D) -> bool { // CHECK:STDOUT: // CHECK:STDOUT: fn @GreaterOrEquivalent.1[@impl.%self.loc10_26.2: %C](@impl.%other.loc10_35.2: %C) -> bool; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Less.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @Less.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] // CHECK:STDOUT: -// CHECK:STDOUT: fn @LessOrEquivalent.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Greater.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @LessOrEquivalent.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] // CHECK:STDOUT: -// CHECK:STDOUT: fn @GreaterOrEquivalent.2[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @Greater.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @GreaterOrEquivalent.2(constants.%Self: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestLess(%a: %C, %b: %C) -> bool { // CHECK:STDOUT: !entry: @@ -506,7 +522,11 @@ fn TestGreaterEqual(a: D, b: D) -> bool { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Less[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @Less(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestLessEqual(%a: %D, %b: %D) -> bool { // CHECK:STDOUT: !entry: @@ -515,7 +535,11 @@ fn TestGreaterEqual(a: D, b: D) -> bool { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @LessOrEquivalent[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @LessOrEquivalent(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestGreater(%a: %D, %b: %D) -> bool { // CHECK:STDOUT: !entry: @@ -524,7 +548,11 @@ fn TestGreaterEqual(a: D, b: D) -> bool { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Greater[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @Greater(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestGreaterEqual(%a: %D, %b: %D) -> bool { // CHECK:STDOUT: !entry: @@ -533,5 +561,9 @@ fn TestGreaterEqual(a: D, b: D) -> bool { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @GreaterOrEquivalent[%self: %Self](%other: %Self) -> bool; +// CHECK:STDOUT: generic fn @GreaterOrEquivalent(constants.%Self: %.4) { +// CHECK:STDOUT: %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self](%other: %Self) -> bool; +// 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 4eb473d1e18c..5a9d0fab1af9 100644 --- a/toolchain/check/testdata/operators/overloaded/right_shift.carbon +++ b/toolchain/check/testdata/operators/overloaded/right_shift.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/operators/overloaded/sub.carbon b/toolchain/check/testdata/operators/overloaded/sub.carbon index bf196ee0c051..428224cd4a20 100644 --- a/toolchain/check/testdata/operators/overloaded/sub.carbon +++ b/toolchain/check/testdata/operators/overloaded/sub.carbon @@ -192,14 +192,23 @@ fn TestAssign(a: C*, b: C) { // CHECK:STDOUT: return %.loc19_14 to @impl.1.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.2[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) { +// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self: %Self.1](%other: %Self.1) -> %Self.1; +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.4[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: generic fn @Op.4(constants.%Self.2: %.6) { +// CHECK:STDOUT: %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)] +// CHECK:STDOUT: %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[addr %self: %.8](%other: %Self.2); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/packages/no_prelude/fail_export_name_params.carbon b/toolchain/check/testdata/packages/no_prelude/fail_export_name_params.carbon index 451c3d3b4660..6e62138da2dd 100644 --- a/toolchain/check/testdata/packages/no_prelude/fail_export_name_params.carbon +++ b/toolchain/check/testdata/packages/no_prelude/fail_export_name_params.carbon @@ -83,10 +83,10 @@ export C2(T:! type); // CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %C1.1: %C1.type = struct_value () [template] // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %C1.2: type = class_type @C1, invalid(%T) [symbolic] +// CHECK:STDOUT: %C1.2: type = class_type @C1, @C1(%T) [symbolic] // CHECK:STDOUT: %C2.type: type = generic_class_type @C2 [template] // CHECK:STDOUT: %C2.1: %C2.type = struct_value () [template] -// CHECK:STDOUT: %C2.2: type = class_type @C2, invalid(%T) [symbolic] +// CHECK:STDOUT: %C2.2: type = class_type @C2, @C2(%T) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -106,9 +106,23 @@ export C2(T:! type); // CHECK:STDOUT: %C2: %C2.type = export C2, imports.%import_ref.2 [template = constants.%C2.1] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C1; +// CHECK:STDOUT: generic class @C1(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] // CHECK:STDOUT: -// CHECK:STDOUT: class @C2; +// CHECK:STDOUT: class; +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%T); +// CHECK:STDOUT: generic class @C2(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: class; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C1(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C2(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/struct/import.carbon b/toolchain/check/testdata/struct/import.carbon index 19ed5422e84e..86ea05b7f85d 100644 --- a/toolchain/check/testdata/struct/import.carbon +++ b/toolchain/check/testdata/struct/import.carbon @@ -225,12 +225,12 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %.10: type = struct_type {} [template] // CHECK:STDOUT: %.11: type = struct_type {.a: i32, .b: i32} [template] // CHECK:STDOUT: %S: %.11 = bind_symbolic_name S 0 [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, invalid(%S) [symbolic] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%S) [symbolic] // CHECK:STDOUT: %.12: i32 = int_literal 1 [template] // CHECK:STDOUT: %.13: i32 = int_literal 2 [template] // CHECK:STDOUT: %.14: type = ptr_type %.11 [template] // CHECK:STDOUT: %struct: %.11 = struct_value (%.12, %.13) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%struct) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%struct) [template] // CHECK:STDOUT: %.15: type = ptr_type %.10 [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] @@ -303,9 +303,15 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %c: ref %C.3 = bind_name c, %c.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.6 +// CHECK:STDOUT: generic class @C(constants.%S: %.11) { +// CHECK:STDOUT: %S: %.11 = bind_symbolic_name S 0 [symbolic = %S (constants.%S)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.6 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; @@ -350,9 +356,15 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%S); +// CHECK:STDOUT: specific @C(constants.%S) { +// CHECK:STDOUT: %S => constants.%S +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%struct); +// CHECK:STDOUT: specific @C(constants.%struct) { +// CHECK:STDOUT: %S => constants.%struct +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_bad_type.impl.carbon // CHECK:STDOUT: @@ -363,13 +375,13 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: type = struct_type {.a: i32, .b: i32} [template] // CHECK:STDOUT: %S: %.3 = bind_symbolic_name S 0 [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, invalid(%S) [symbolic] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%S) [symbolic] // CHECK:STDOUT: %.4: i32 = int_literal 1 [template] // CHECK:STDOUT: %.5: i32 = int_literal 2 [template] // CHECK:STDOUT: %.6: type = struct_type {.c: i32, .d: i32} [template] // CHECK:STDOUT: %.7: type = ptr_type %.3 [template] // CHECK:STDOUT: %struct: %.3 = struct_value (%.4, %.5) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%struct) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%struct) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: %.8: type = ptr_type %.2 [template] @@ -415,9 +427,15 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %c_bad: ref = bind_name c_bad, %c_bad.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: generic class @C(constants.%S: %.3) { +// CHECK:STDOUT: %S: %.3 = bind_symbolic_name S 0 [symbolic = %S (constants.%S)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() -> %C.3; @@ -431,9 +449,15 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%S); +// CHECK:STDOUT: specific @C(constants.%S) { +// CHECK:STDOUT: %S => constants.%S +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%struct); +// CHECK:STDOUT: specific @C(constants.%struct) { +// CHECK:STDOUT: %S => constants.%struct +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_bad_value.impl.carbon // CHECK:STDOUT: @@ -444,17 +468,17 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: type = struct_type {.a: i32, .b: i32} [template] // CHECK:STDOUT: %S: %.3 = bind_symbolic_name S 0 [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, invalid(%S) [symbolic] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%S) [symbolic] // CHECK:STDOUT: %.4: i32 = int_literal 3 [template] // CHECK:STDOUT: %.5: i32 = int_literal 4 [template] // CHECK:STDOUT: %.6: type = ptr_type %.3 [template] // CHECK:STDOUT: %struct.1: %.3 = struct_value (%.4, %.5) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%struct.1) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%struct.1) [template] // CHECK:STDOUT: %.7: type = ptr_type %.2 [template] // CHECK:STDOUT: %.8: i32 = int_literal 2 [template] // CHECK:STDOUT: %.9: i32 = int_literal 1 [template] // CHECK:STDOUT: %struct.2: %.3 = struct_value (%.9, %.8) [template] -// CHECK:STDOUT: %C.4: type = class_type @C, invalid(%struct.2) [template] +// CHECK:STDOUT: %C.4: type = class_type @C, @C(%struct.2) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: } @@ -501,9 +525,15 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %c_bad: ref %C.3 = bind_name c_bad, %c_bad.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: generic class @C(constants.%S: %.3) { +// CHECK:STDOUT: %S: %.3 = bind_symbolic_name S 0 [symbolic = %S (constants.%S)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() -> %C.4; @@ -517,9 +547,19 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%S); +// CHECK:STDOUT: specific @C(constants.%S) { +// CHECK:STDOUT: %S => constants.%S +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%struct.1); +// CHECK:STDOUT: specific @C(constants.%struct.1) { +// CHECK:STDOUT: %S => constants.%struct.1 // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%struct.2); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%struct.2) { +// CHECK:STDOUT: %S => constants.%struct.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/tuples/import.carbon b/toolchain/check/testdata/tuples/import.carbon index 73190a46f35f..ce160f8c773b 100644 --- a/toolchain/check/testdata/tuples/import.carbon +++ b/toolchain/check/testdata/tuples/import.carbon @@ -249,11 +249,11 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %C.1: %C.type = struct_value () [template] // CHECK:STDOUT: %.14: type = struct_type {} [template] // CHECK:STDOUT: %X: %.8 = bind_symbolic_name X 0 [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, invalid(%X) [symbolic] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%X) [symbolic] // CHECK:STDOUT: %.15: i32 = int_literal 1 [template] // CHECK:STDOUT: %.16: i32 = int_literal 2 [template] // CHECK:STDOUT: %tuple: %.8 = tuple_value (%.15, %.16) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%tuple) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%tuple) [template] // CHECK:STDOUT: %.17: type = ptr_type %.14 [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] @@ -334,9 +334,15 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %c: ref %C.3 = bind_name c, %c.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.6 +// CHECK:STDOUT: generic class @C(constants.%X: %.8) { +// CHECK:STDOUT: %X: %.8 = bind_symbolic_name X 0 [symbolic = %X (constants.%X)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.6 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; @@ -389,9 +395,15 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%X); +// CHECK:STDOUT: specific @C(constants.%X) { +// CHECK:STDOUT: %X => constants.%X +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%tuple); +// CHECK:STDOUT: specific @C(constants.%tuple) { +// CHECK:STDOUT: %X => constants.%tuple +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_bad_type.impl.carbon // CHECK:STDOUT: @@ -402,14 +414,14 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: type = tuple_type (i32, i32) [template] // CHECK:STDOUT: %X: %.3 = bind_symbolic_name X 0 [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, invalid(%X) [symbolic] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%X) [symbolic] // CHECK:STDOUT: %.4: i32 = int_literal 1 [template] // CHECK:STDOUT: %.5: i32 = int_literal 2 [template] // CHECK:STDOUT: %.6: i32 = int_literal 3 [template] // CHECK:STDOUT: %.7: type = tuple_type (i32, i32, i32) [template] // CHECK:STDOUT: %.8: type = ptr_type %.3 [template] // CHECK:STDOUT: %tuple: %.3 = tuple_value (%.4, %.5) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%tuple) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%tuple) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: %.9: type = ptr_type %.2 [template] @@ -456,9 +468,15 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %c_bad: ref = bind_name c_bad, %c_bad.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: generic class @C(constants.%X: %.3) { +// CHECK:STDOUT: %X: %.3 = bind_symbolic_name X 0 [symbolic = %X (constants.%X)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() -> %C.3; @@ -472,9 +490,15 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%X); +// CHECK:STDOUT: specific @C(constants.%X) { +// CHECK:STDOUT: %X => constants.%X +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%tuple); +// CHECK:STDOUT: specific @C(constants.%tuple) { +// CHECK:STDOUT: %X => constants.%tuple +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_bad_value.impl.carbon // CHECK:STDOUT: @@ -485,17 +509,17 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: type = tuple_type (i32, i32) [template] // CHECK:STDOUT: %X: %.3 = bind_symbolic_name X 0 [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, invalid(%X) [symbolic] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%X) [symbolic] // CHECK:STDOUT: %.4: i32 = int_literal 3 [template] // CHECK:STDOUT: %.5: i32 = int_literal 4 [template] // CHECK:STDOUT: %.6: type = ptr_type %.3 [template] // CHECK:STDOUT: %tuple.1: %.3 = tuple_value (%.4, %.5) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, invalid(%tuple.1) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%tuple.1) [template] // CHECK:STDOUT: %.7: type = ptr_type %.2 [template] // CHECK:STDOUT: %.8: i32 = int_literal 2 [template] // CHECK:STDOUT: %.9: i32 = int_literal 1 [template] // CHECK:STDOUT: %tuple.2: %.3 = tuple_value (%.9, %.8) [template] -// CHECK:STDOUT: %C.4: type = class_type @C, invalid(%tuple.2) [template] +// CHECK:STDOUT: %C.4: type = class_type @C, @C(%tuple.2) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: } @@ -542,9 +566,15 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %c_bad: ref %C.3 = bind_name c_bad, %c_bad.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: generic class @C(constants.%X: %.3) { +// CHECK:STDOUT: %X: %.3 = bind_symbolic_name X 0 [symbolic = %X (constants.%X)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.5 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() -> %C.4; @@ -558,9 +588,19 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%X); +// CHECK:STDOUT: specific @C(constants.%X) { +// CHECK:STDOUT: %X => constants.%X +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%tuple.1); +// CHECK:STDOUT: specific @C(constants.%tuple.1) { +// CHECK:STDOUT: %X => constants.%tuple.1 // CHECK:STDOUT: -// CHECK:STDOUT: specific invalid(constants.%tuple.2); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%tuple.2) { +// CHECK:STDOUT: %X => constants.%tuple.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/sem_ir/generic.cpp b/toolchain/sem_ir/generic.cpp index b04cea6d8cba..5cc71765a793 100644 --- a/toolchain/sem_ir/generic.cpp +++ b/toolchain/sem_ir/generic.cpp @@ -32,6 +32,7 @@ class SpecificStore::KeyContext : public TranslatingKeyContext { auto SpecificStore::GetOrAdd(GenericId generic_id, InstBlockId args_id) -> SpecificId { + CARBON_CHECK(generic_id.is_valid()); return lookup_table_ .Insert( KeyContext::Key{.generic_id = generic_id, .args_id = args_id},