From f772c1f5f3a1f502150cc9768d29d396523dcbb1 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 7 Jun 2024 11:24:35 -0700 Subject: [PATCH] More support for generic interfaces, aiming for parity with support for generic classes. (#4034) This is mostly mechanically duplicating work done for generic classes to also support generic interfaces. Also fix both generic interfaces and generic classes to support importing class and interface types with arguments from another file. --------- Co-authored-by: Jon Ross-Perkins Co-authored-by: Carbon Infra Bot --- toolchain/check/BUILD | 1 + toolchain/check/call.cpp | 54 ++- toolchain/check/context.cpp | 6 + toolchain/check/context.h | 6 + toolchain/check/eval.cpp | 30 +- toolchain/check/handle_class.cpp | 4 +- toolchain/check/handle_interface.cpp | 18 +- toolchain/check/import_ref.cpp | 153 ++++++- .../check/testdata/class/generic/call.carbon | 4 +- .../class/generic/fail_todo_use.carbon | 2 +- .../testdata/class/generic/import.carbon | 406 +++++++++++++++++- .../testdata/class/generic/redeclare.carbon | 3 +- .../impl/fail_extend_impl_forall.carbon | 53 ++- .../fail_generic_redeclaration.carbon | 40 +- .../fail_todo_generic_default_fn.carbon | 82 ++-- .../interface/no_prelude/generic.carbon | 291 ++++++++++++- .../no_prelude/generic_import.carbon | 134 ++++++ .../no_prelude/fail_export_name_params.carbon | 16 +- toolchain/lower/file_context.cpp | 1 + toolchain/sem_ir/file.cpp | 9 + toolchain/sem_ir/formatter.cpp | 8 + toolchain/sem_ir/inst_kind.def | 2 + toolchain/sem_ir/inst_namer.cpp | 11 + toolchain/sem_ir/interface.h | 5 + toolchain/sem_ir/typed_insts.h | 15 +- 25 files changed, 1194 insertions(+), 160 deletions(-) create mode 100644 toolchain/check/testdata/interface/no_prelude/generic_import.carbon diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 70b7b73b7dc1..4ea908128dca 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -135,6 +135,7 @@ cc_library( deps = [ ":context", "//common:check", + "//toolchain/base:kind_switch", "//toolchain/sem_ir:file", "//toolchain/sem_ir:ids", "//toolchain/sem_ir:inst", diff --git a/toolchain/check/call.cpp b/toolchain/check/call.cpp index 01639efd1715..193e3934fabb 100644 --- a/toolchain/check/call.cpp +++ b/toolchain/check/call.cpp @@ -4,6 +4,7 @@ #include "toolchain/check/call.h" +#include "toolchain/base/kind_switch.h" #include "toolchain/check/context.h" #include "toolchain/check/convert.h" #include "toolchain/check/function.h" @@ -31,24 +32,55 @@ static auto PerformCallToGenericClass(Context& context, Parse::NodeId node_id, .args_id = converted_args_id}); } +// Performs a call where the callee is the name of a generic interface, such as +// `AddWith(i32)`. +// TODO: Refactor with PerformCallToGenericClass. +static auto PerformCallToGenericInterface(Context& context, + Parse::NodeId node_id, + SemIR::InterfaceId interface_id, + llvm::ArrayRef arg_ids) + -> SemIR::InstId { + auto& interface_info = context.interfaces().Get(interface_id); + + // Convert the arguments to match the parameters. + auto converted_args_id = ConvertCallArgs( + context, node_id, /*self_id=*/SemIR::InstId::Invalid, arg_ids, + /*return_storage_id=*/SemIR::InstId::Invalid, interface_info.decl_id, + interface_info.implicit_param_refs_id, interface_info.param_refs_id); + return context.AddInst( + node_id, {.type_id = SemIR::TypeId::TypeType, + .interface_id = interface_id, + .args_id = converted_args_id}); +} + auto PerformCall(Context& context, Parse::NodeId node_id, SemIR::InstId callee_id, llvm::ArrayRef arg_ids) -> SemIR::InstId { // Identify the function we're calling. auto callee_function = GetCalleeFunction(context.sem_ir(), callee_id); if (!callee_function.function_id.is_valid()) { - if (auto generic_class = context.types().TryGetAs( - context.insts().Get(callee_id).type_id())) { - return PerformCallToGenericClass(context, node_id, - generic_class->class_id, arg_ids); + auto type_inst = + context.types().GetAsInst(context.insts().Get(callee_id).type_id()); + CARBON_KIND_SWITCH(type_inst) { + case CARBON_KIND(SemIR::GenericClassType generic_class): { + return PerformCallToGenericClass(context, node_id, + generic_class.class_id, arg_ids); + } + case CARBON_KIND(SemIR::GenericInterfaceType generic_interface): { + return PerformCallToGenericInterface( + context, node_id, generic_interface.interface_id, arg_ids); + } + default: { + if (!callee_function.is_error) { + CARBON_DIAGNOSTIC(CallToNonCallable, Error, + "Value of type `{0}` is not callable.", + SemIR::TypeId); + context.emitter().Emit(node_id, CallToNonCallable, + context.insts().Get(callee_id).type_id()); + } + return SemIR::InstId::BuiltinError; + } } - if (!callee_function.is_error) { - CARBON_DIAGNOSTIC(CallToNonCallable, Error, - "Value of type `{0}` is not callable.", SemIR::TypeId); - context.emitter().Emit(node_id, CallToNonCallable, - context.insts().Get(callee_id).type_id()); - } - return SemIR::InstId::BuiltinError; } auto& callable = context.functions().Get(callee_function.function_id); diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 5ffdeed0bffd..7b4b3cd537b0 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -982,6 +982,7 @@ class TypeCompleter { case SemIR::AssociatedEntityType::Kind: case SemIR::FunctionType::Kind: case SemIR::GenericClassType::Kind: + case SemIR::GenericInterfaceType::Kind: case SemIR::InterfaceType::Kind: case SemIR::UnboundElementType::Kind: { // These types have no runtime operations, so we use an empty value @@ -1110,6 +1111,11 @@ auto Context::GetGenericClassType(SemIR::ClassId class_id) -> SemIR::TypeId { return GetCompleteTypeImpl(*this, class_id); } +auto Context::GetGenericInterfaceType(SemIR::InterfaceId interface_id) + -> SemIR::TypeId { + return GetCompleteTypeImpl(*this, interface_id); +} + auto Context::GetPointerType(SemIR::TypeId pointee_type_id) -> SemIR::TypeId { return GetTypeImpl(*this, pointee_type_id); } diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 5847a72690a1..2523bf894cff 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -264,6 +264,12 @@ class Context { // type will be complete. auto GetGenericClassType(SemIR::ClassId class_id) -> SemIR::TypeId; + // Gets a generic interface type, which is the type of a name of a generic + // interface, such as the type of `AddWith` given + // `interface AddWith(T:! type)`. The returned type will be complete. + auto GetGenericInterfaceType(SemIR::InterfaceId interface_id) + -> SemIR::TypeId; + // Returns a pointer type whose pointee type is `pointee_type_id`. auto GetPointerType(SemIR::TypeId pointee_type_id) -> SemIR::TypeId; diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 1d71c98f030b..b051002bdd5f 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -128,6 +128,9 @@ static auto GetConstantValue(Context& context, SemIR::TypeId type_id, // corresponding block of those values. static auto GetConstantValue(Context& context, SemIR::InstBlockId inst_block_id, Phase* phase) -> SemIR::InstBlockId { + if (!inst_block_id.is_valid()) { + return SemIR::InstBlockId::Invalid; + } auto insts = context.inst_blocks().Get(inst_block_id); llvm::SmallVector const_insts; for (auto inst_id : insts) { @@ -154,6 +157,9 @@ static auto GetConstantValue(Context& context, SemIR::InstBlockId inst_block_id, // extract its phase. static auto GetConstantValue(Context& context, SemIR::TypeBlockId type_block_id, Phase* phase) -> SemIR::TypeBlockId { + if (!type_block_id.is_valid()) { + return SemIR::TypeBlockId::Invalid; + } auto types = context.type_blocks().Get(type_block_id); for (auto type_id : types) { GetConstantValue(context, type_id, phase); @@ -169,7 +175,7 @@ static auto ReplaceFieldWithConstantValue(Context& context, InstT* inst, FieldIdT InstT::*field, Phase* phase) -> bool { auto unwrapped = GetConstantValue(context, inst->*field, phase); - if (!unwrapped.is_valid()) { + if (!unwrapped.is_valid() && (inst->*field).is_valid()) { return false; } inst->*field = unwrapped; @@ -915,11 +921,11 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) &SemIR::BoundMethod::object_id, &SemIR::BoundMethod::function_id); case SemIR::ClassType::Kind: - // TODO: Look at generic arguments once they're modeled. - return MakeConstantResult(context, inst, Phase::Template); + return RebuildIfFieldsAreConstant(context, inst, + &SemIR::ClassType::args_id); case SemIR::InterfaceType::Kind: - // TODO: Look at generic arguments once they're modeled. - return MakeConstantResult(context, inst, Phase::Template); + return RebuildIfFieldsAreConstant(context, inst, + &SemIR::InterfaceType::args_id); case SemIR::InterfaceWitness::Kind: return RebuildIfFieldsAreConstant(context, inst, &SemIR::InterfaceWitness::elements_id); @@ -980,6 +986,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) case SemIR::Builtin::Kind: case SemIR::FunctionType::Kind: case SemIR::GenericClassType::Kind: + case SemIR::GenericInterfaceType::Kind: // Builtins are always template constants. return MakeConstantResult(context, inst, Phase::Template); @@ -992,7 +999,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) } case CARBON_KIND(SemIR::ClassDecl class_decl): { - // If the class has generic arguments, we don't produce a class type, but + // If the class has generic parameters, we don't produce a class type, but // a callable whose return value is a class type. if (context.classes().Get(class_decl.class_id).is_generic()) { return MakeConstantResult( @@ -1009,7 +1016,16 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) Phase::Template); } case CARBON_KIND(SemIR::InterfaceDecl interface_decl): { - // TODO: Once interfaces have generic arguments, handle them. + // If the interface has generic parameters, we don't produce an interface + // type, but a callable whose return value is an interface type. + if (context.interfaces().Get(interface_decl.interface_id).is_generic()) { + return MakeConstantResult( + context, + SemIR::StructValue{.type_id = interface_decl.type_id, + .elements_id = SemIR::InstBlockId::Empty}, + Phase::Template); + } + // A non-generic interface declaration evaluates to the interface type. return MakeConstantResult( context, SemIR::InterfaceType{.type_id = SemIR::TypeId::TypeType, diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index 8f1fefd7be15..ae550ac85bd0 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -127,7 +127,8 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id, auto prev_class_id = SemIR::ClassId::Invalid; auto prev_import_ir_id = SemIR::ImportIRId::Invalid; - CARBON_KIND_SWITCH(context.insts().Get(prev_id)) { + auto prev = context.insts().Get(prev_id); + CARBON_KIND_SWITCH(prev) { case CARBON_KIND(SemIR::ClassDecl class_decl): { prev_class_id = class_decl.class_id; break; @@ -174,6 +175,7 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id, prev_import_ir_id)) { // When merging, use the existing entity rather than adding a new one. class_decl.class_id = prev_class_id; + class_decl.type_id = prev.type_id(); // TODO: Validate that the redeclaration doesn't set an access modifier. } } diff --git a/toolchain/check/handle_interface.cpp b/toolchain/check/handle_interface.cpp index 0b38e1a52d24..24697da8a411 100644 --- a/toolchain/check/handle_interface.cpp +++ b/toolchain/check/handle_interface.cpp @@ -65,6 +65,7 @@ static auto BuildInterfaceDecl(Context& context, existing_interface_decl->interface_id)))) { // This is a redeclaration of an existing interface. interface_decl.interface_id = existing_interface_decl->interface_id; + interface_decl.type_id = existing_interface_decl->type_id; // TODO: If the new declaration is a definition, keep its parameter // and implicit parameter lists rather than the ones from the // previous declaration. @@ -81,12 +82,17 @@ static auto BuildInterfaceDecl(Context& context, // there was an error in the qualifier, we will have lost track of the // interface name here. We should keep track of it even if the name is // invalid. - interface_decl.interface_id = context.interfaces().Add( - {.name_id = name_context.name_id_for_new_inst(), - .parent_scope_id = name_context.parent_scope_id_for_new_inst(), - .implicit_param_refs_id = name.implicit_params_id, - .param_refs_id = name.params_id, - .decl_id = interface_decl_id}); + SemIR::Interface interface_info = { + .name_id = name_context.name_id_for_new_inst(), + .parent_scope_id = name_context.parent_scope_id_for_new_inst(), + .implicit_param_refs_id = name.implicit_params_id, + .param_refs_id = name.params_id, + .decl_id = interface_decl_id}; + interface_decl.interface_id = context.interfaces().Add(interface_info); + if (interface_info.is_generic()) { + interface_decl.type_id = + context.GetGenericInterfaceType(interface_decl.interface_id); + } } // TODO: For a generic interface declaration, set the `type_id` to a suitable diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index d97907ac726d..7d0fa7af4a9f 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -371,6 +371,38 @@ class ImportRefResolver { return GetLocalConstantId(import_ir_.types().GetInstId(type_id)); } + // Gets the local constant values corresponding to an imported inst block. + auto GetLocalInstBlockContents(SemIR::InstBlockId import_block_id) + -> llvm::SmallVector { + llvm::SmallVector inst_ids; + if (!import_block_id.is_valid() || + import_block_id == SemIR::InstBlockId::Empty) { + return inst_ids; + } + + // Import all the values in the block. + auto import_block = import_ir_.inst_blocks().Get(import_block_id); + inst_ids.reserve(import_block.size()); + for (auto import_inst_id : import_block) { + auto const_id = GetLocalConstantId(import_inst_id); + inst_ids.push_back(const_id.inst_id()); + } + + return inst_ids; + } + + // Gets a local canonical instruction block ID corresponding to an imported + // inst block whose contents were already imported, for example by + // GetLocalInstBlockContents. + auto GetLocalCanonicalInstBlockId(SemIR::InstBlockId import_block_id, + llvm::ArrayRef contents) + -> SemIR::InstBlockId { + if (!import_block_id.is_valid()) { + return SemIR::InstBlockId::Invalid; + } + return context_.inst_blocks().AddCanonical(contents); + } + // Returns the ConstantId for each parameter's type. Adds unresolved constants // to work_stack_. auto GetLocalParamConstantIds(SemIR::InstBlockId param_refs_id) @@ -523,13 +555,30 @@ class ImportRefResolver { case CARBON_KIND(SemIR::InterfaceType inst): { return context_.interfaces().Get(inst.interface_id).scope_id; } - default: + case SemIR::StructValue::Kind: { + auto type_inst = context_.types().GetAsInst(name_scope_inst.type_id()); + CARBON_KIND_SWITCH(type_inst) { + case CARBON_KIND(SemIR::GenericClassType inst): { + return context_.classes().Get(inst.class_id).scope_id; + } + case CARBON_KIND(SemIR::GenericInterfaceType inst): { + return context_.interfaces().Get(inst.interface_id).scope_id; + } + default: { + break; + } + } + break; + } + default: { if (const_id == SemIR::ConstantId::Error) { return SemIR::NameScopeId::Invalid; } - CARBON_FATAL() << "Unexpected instruction kind for name scope: " - << name_scope_inst; + break; + } } + CARBON_FATAL() << "Unexpected instruction kind for name scope: " + << name_scope_inst; } // Adds ImportRefUnloaded entries for members of the imported scope, for name @@ -628,6 +677,9 @@ class ImportRefResolver { case CARBON_KIND(SemIR::GenericClassType inst): { return TryResolveTypedInst(inst); } + case CARBON_KIND(SemIR::GenericInterfaceType inst): { + return TryResolveTypedInst(inst); + } case CARBON_KIND(SemIR::ImportRefLoaded inst): { return TryResolveTypedInst(inst, inst_id); } @@ -900,9 +952,26 @@ 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 = GetLocalInstBlockContents(inst.args_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } + + // Find the corresponding class type. For a non-generic class, this is the + // type of the class declaration. For a generic class, build a class type + // referencing this specialization of the generic class. + auto class_const_inst = context_.insts().Get(class_const_id.inst_id()); + if (!class_const_inst.Is()) { + auto generic_class_type = context_.types().GetAs( + class_const_inst.type_id()); + auto args_id = GetLocalCanonicalInstBlockId(inst.args_id, args); + class_const_id = + TryEvalInst(context_, SemIR::InstId::Invalid, + SemIR::ClassType{.type_id = SemIR::TypeId::TypeType, + .class_id = generic_class_type.class_id, + .args_id = args_id}); + } + return {.const_id = class_const_id}; } @@ -1038,6 +1107,21 @@ class ImportRefResolver { return {.const_id = context_.types().GetConstantId(class_val.type_id())}; } + auto TryResolveTypedInst(SemIR::GenericInterfaceType inst) -> ResolveResult { + auto initial_work = work_stack_.size(); + CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); + auto interface_const_id = GetLocalConstantId( + import_ir_.interfaces().Get(inst.interface_id).decl_id); + if (HasNewWork(initial_work)) { + return ResolveResult::Retry(); + } + auto interface_val = context_.insts().Get(interface_const_id.inst_id()); + CARBON_CHECK(context_.types().Is( + interface_val.type_id())); + return {.const_id = + context_.types().GetConstantId(interface_val.type_id())}; + } + auto TryResolveTypedInst(SemIR::ImportRefLoaded /*inst*/, SemIR::InstId inst_id) -> ResolveResult { auto initial_work = work_stack_.size(); @@ -1063,7 +1147,7 @@ class ImportRefResolver { // Make a declaration of an interface. This is done as a separate step from // importing the interface definition in order to resolve cycles. auto MakeInterfaceDecl(const SemIR::Interface& import_interface) - -> SemIR::ConstantId { + -> std::pair { SemIR::InterfaceDecl interface_decl = { .type_id = SemIR::TypeId::TypeType, .interface_id = SemIR::InterfaceId::Invalid, @@ -1073,7 +1157,7 @@ class ImportRefResolver { AddImportIRInst(import_interface.decl_id), interface_decl)); // Start with an incomplete interface. - SemIR::Interface new_interface = { + interface_decl.interface_id = context_.interfaces().Add({ .name_id = GetLocalNameId(import_interface.name_id), // These are set in the second pass once we've imported them. Import // enough of the parameter lists that we know whether this interface is @@ -1089,14 +1173,17 @@ class ImportRefResolver { ? SemIR::InstBlockId::Empty : SemIR::InstBlockId::Invalid, .decl_id = interface_decl_id, - }; + }); + + if (import_interface.is_generic()) { + interface_decl.type_id = + context_.GetGenericInterfaceType(interface_decl.interface_id); + } // Write the interface ID into the InterfaceDecl. - interface_decl.interface_id = context_.interfaces().Add(new_interface); context_.ReplaceInstBeforeConstantUse(interface_decl_id, interface_decl); - - // Set the constant value for the imported interface. - return context_.constant_values().Get(interface_decl_id); + return {interface_decl.interface_id, + context_.constant_values().Get(interface_decl_id)}; } // Imports the definition for an interface that has been imported as a forward @@ -1129,9 +1216,25 @@ class ImportRefResolver { const auto& import_interface = import_ir_.interfaces().Get(inst.interface_id); - // On the first pass, create a forward declaration of the interface. + SemIR::InterfaceId interface_id = SemIR::InterfaceId::Invalid; if (!interface_const_id.is_valid()) { - interface_const_id = MakeInterfaceDecl(import_interface); + // On the first pass, create a forward declaration of the interface. + std::tie(interface_id, interface_const_id) = + MakeInterfaceDecl(import_interface); + } else { + // On the second pass, compute the interface ID from the constant value of + // the declaration. + auto interface_const_inst = + context_.insts().Get(interface_const_id.inst_id()); + if (auto interface_type = + interface_const_inst.TryAs()) { + interface_id = interface_type->interface_id; + } else { + auto generic_interface_type = + context_.types().GetAs( + interface_const_inst.type_id()); + interface_id = generic_interface_type.interface_id; + } } auto initial_work = work_stack_.size(); @@ -1148,10 +1251,7 @@ class ImportRefResolver { return ResolveResult::Retry(interface_const_id); } - auto& new_interface = context_.interfaces().Get( - context_.insts() - .GetAs(interface_const_id.inst_id()) - .interface_id); + auto& new_interface = context_.interfaces().Get(interface_id); new_interface.parent_scope_id = parent_scope_id; new_interface.implicit_param_refs_id = GetLocalParamRefsId( import_interface.implicit_param_refs_id, implicit_param_const_ids); @@ -1169,9 +1269,30 @@ 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 = GetLocalInstBlockContents(inst.args_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } + + // Find the corresponding interface type. For a non-generic interface, this + // is the type of the interface declaration. For a generic interface, build + // a interface type referencing this specialization of the generic + // interface. + auto interface_const_inst = + context_.insts().Get(interface_const_id.inst_id()); + if (!interface_const_inst.Is()) { + auto generic_interface_type = + context_.types().GetAs( + interface_const_inst.type_id()); + auto args_id = GetLocalCanonicalInstBlockId(inst.args_id, args); + interface_const_id = + TryEvalInst(context_, SemIR::InstId::Invalid, + SemIR::InterfaceType{ + .type_id = SemIR::TypeId::TypeType, + .interface_id = generic_interface_type.interface_id, + .args_id = args_id}); + } + return {.const_id = interface_const_id}; } diff --git a/toolchain/check/testdata/class/generic/call.carbon b/toolchain/check/testdata/class/generic/call.carbon index cbd4e3807089..9bf466b5f817 100644 --- a/toolchain/check/testdata/class/generic/call.carbon +++ b/toolchain/check/testdata/class/generic/call.carbon @@ -77,10 +77,10 @@ var a: Class(5, i32*); // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: type = ptr_type i32 [template] // CHECK:STDOUT: %.4: i32 = int_literal 5 [template] -// CHECK:STDOUT: %Class.3: type = class_type @Class, (file.%.loc6_17.3, file.%.loc6_20) [template] +// CHECK:STDOUT: %Class.3: type = class_type @Class, (%.3, %.4) [template] // CHECK:STDOUT: %.5: type = ptr_type %.2 [template] // CHECK:STDOUT: %.6: i32 = int_literal 0 [template] -// CHECK:STDOUT: %Class.4: type = class_type @Class, (file.%.loc9_13, file.%.loc9_18) [template] +// CHECK:STDOUT: %Class.4: type = class_type @Class, (%.1, %.6) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/testdata/class/generic/fail_todo_use.carbon b/toolchain/check/testdata/class/generic/fail_todo_use.carbon index 490c7db77da3..3d69f0907f99 100644 --- a/toolchain/check/testdata/class/generic/fail_todo_use.carbon +++ b/toolchain/check/testdata/class/generic/fail_todo_use.carbon @@ -55,7 +55,7 @@ fn Run() -> i32 { // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] // CHECK:STDOUT: %Run.type: type = fn_type @Run [template] // CHECK:STDOUT: %Run: %Run.type = struct_value () [template] -// CHECK:STDOUT: %Class.3: type = class_type @Class, (@Run.%.loc25_15.2) [template] +// CHECK:STDOUT: %Class.3: type = class_type @Class, (i32) [template] // CHECK:STDOUT: %.7: i32 = int_literal 0 [template] // CHECK:STDOUT: %.8: type = struct_type {.k: i32} [template] // CHECK:STDOUT: %.9: type = ptr_type %Class.3 [template] diff --git a/toolchain/check/testdata/class/generic/import.carbon b/toolchain/check/testdata/class/generic/import.carbon index d4ce2518b841..098688567518 100644 --- a/toolchain/check/testdata/class/generic/import.carbon +++ b/toolchain/check/testdata/class/generic/import.carbon @@ -14,6 +14,13 @@ library "foo"; class Class(T:! type); +class CompleteClass(T:! type) { + var n: i32; + fn F() -> i32 { return 0; } +} + +fn F() -> CompleteClass(i32); + // --- foo.impl.carbon impl library "foo"; @@ -22,6 +29,49 @@ class Class(T:! type) { var x: T; } +fn F() -> CompleteClass(i32) { + return {.n = 1}; +} + +// --- use_foo.carbon + +library "use_foo"; +import library "foo"; + +fn Use() -> i32 { + var v: CompleteClass(i32) = F(); + return v.F(); +} + +// --- fail_todo_use_foo.carbon + +library "fail_todo_use_foo"; +import library "foo"; + +fn Use() -> i32 { + var v: CompleteClass(i32) = F(); + // TODO: This should be accepted. + // CHECK:STDERR: fail_todo_use_foo.carbon:[[@LINE+4]]:10: ERROR: Cannot implicitly convert from `CompleteClass` to `CompleteClass`. + // CHECK:STDERR: return v.n; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + return v.n; +} + +// --- fail_generic_arg_mismatch.carbon + +library "fail_generic_arg_mismatch"; +import library "foo"; + +fn Use() { + // TODO: Include the generic arguments in the formatted type name. + // CHECK:STDERR: fail_generic_arg_mismatch.carbon:[[@LINE+4]]:3: ERROR: Cannot implicitly convert from `CompleteClass` to `CompleteClass`. + // CHECK:STDERR: var v: CompleteClass(i32*) = F(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var v: CompleteClass(i32*) = F(); +} + // --- fail_bad_foo.impl.carbon impl library "foo"; @@ -46,45 +96,131 @@ class Class(U:! type) { // CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template] // CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %CompleteClass.type: type = generic_class_type @CompleteClass [template] +// CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass [template] +// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] +// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %.2: type = unbound_element_type %CompleteClass.2, i32 [template] +// CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] +// CHECK:STDOUT: %.3: type = struct_type {.n: i32} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 0 [template] +// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, (i32) [template] +// CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .Core = %Core // CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: .CompleteClass = %CompleteClass.decl +// CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } // CHECK:STDOUT: %Core: = namespace [template] {} // CHECK:STDOUT: %Class.decl: %Class.type = class_decl @Class [template = constants.%Class.1] { // 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: %CompleteClass.decl: %CompleteClass.type = class_decl @CompleteClass [template = constants.%CompleteClass.1] { +// CHECK:STDOUT: %T.loc6_21.1: type = param T +// CHECK:STDOUT: %T.loc6_21.2: type = bind_symbolic_name T 0, %T.loc6_21.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: %Int32.type = import_ref ir3, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: %import_ref.2: %Int32.type = import_ref ir3, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: %import_ref.3: %Int32.type = import_ref ir3, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] { +// CHECK:STDOUT: %CompleteClass.ref: %CompleteClass.type = name_ref CompleteClass, %CompleteClass.decl [template = constants.%CompleteClass.1] +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc11_24.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc11_24.2: type = converted %int.make_type_32, %.loc11_24.1 [template = i32] +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, (%.loc11_24.2) [template = constants.%CompleteClass.3] +// CHECK:STDOUT: @F.2.%return: ref %CompleteClass.3 = var +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @Class; // CHECK:STDOUT: +// CHECK:STDOUT: class @CompleteClass { +// CHECK:STDOUT: %int.make_type_32.loc7: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc7_10.1: type = value_of_initializer %int.make_type_32.loc7 [template = i32] +// CHECK:STDOUT: %.loc7_10.2: type = converted %int.make_type_32.loc7, %.loc7_10.1 [template = i32] +// CHECK:STDOUT: %.loc7_8: %.2 = field_decl n, element0 [template] +// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] { +// CHECK:STDOUT: %int.make_type_32.loc8: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc8_13.1: type = value_of_initializer %int.make_type_32.loc8 [template = i32] +// CHECK:STDOUT: %.loc8_13.2: type = converted %int.make_type_32.loc8, %.loc8_13.1 [template = i32] +// CHECK:STDOUT: %return.var: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%CompleteClass.2 +// CHECK:STDOUT: .n = %.loc7_8 +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.1() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc8: i32 = int_literal 0 [template = constants.%.4] +// CHECK:STDOUT: return %.loc8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2() -> %CompleteClass.3; +// CHECK:STDOUT: // CHECK:STDOUT: --- foo.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] // CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template] // CHECK:STDOUT: %.1: type = tuple_type () [template] -// CHECK:STDOUT: %Class: %Class.type = struct_value () [template] -// CHECK:STDOUT: %struct: type = struct_value () [template] -// CHECK:STDOUT: %.2: type = unbound_element_type %Class, %T [symbolic] +// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// 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 [template] +// 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, (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: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .CompleteClass = %import_ref.2 // CHECK:STDOUT: .Core = %Core // CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref: %Class.type = import_ref ir0, inst+5, loaded [template = constants.%Class] +// CHECK:STDOUT: %import_ref.1: %Class.type = import_ref ir0, inst+5, loaded [template = constants.%Class.1] +// CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref ir0, inst+12, loaded [template = constants.%CompleteClass.1] +// CHECK:STDOUT: %import_ref.3: %F.type = import_ref ir0, inst+48, loaded [template = constants.%F] // CHECK:STDOUT: %Core: = namespace [template] {} -// CHECK:STDOUT: %Class.decl: type = class_decl @Class [template = constants.%struct] { +// CHECK:STDOUT: %Class.decl: %Class.type = class_decl @Class [template = constants.%Class.1] { // 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: %import_ref.4 = import_ref ir0, inst+15, unloaded +// CHECK:STDOUT: %import_ref.5 = import_ref ir0, inst+25, unloaded +// CHECK:STDOUT: %import_ref.6 = import_ref ir0, inst+33, unloaded +// CHECK:STDOUT: %import_ref.7: %Int32.type = import_ref ir3, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %CompleteClass.ref: %CompleteClass.type = name_ref CompleteClass, %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] +// CHECK:STDOUT: %.loc8_24.2: type = converted %int.make_type_32, %.loc8_24.1 [template = i32] +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, (%.loc8_24.2) [template = constants.%CompleteClass.3] +// CHECK:STDOUT: @F.%return: ref %CompleteClass.3 = var +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @Class { @@ -92,18 +228,262 @@ class Class(U:! type) { // CHECK:STDOUT: %.loc5: %.2 = field_decl x, element0 [template] // CHECK:STDOUT: // CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%Class +// CHECK:STDOUT: .Self = constants.%Class.2 // CHECK:STDOUT: .x = %.loc5 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: class @CompleteClass { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = file.%import_ref.4 +// CHECK:STDOUT: .n = file.%import_ref.5 +// CHECK:STDOUT: .F = file.%import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() -> %return: %CompleteClass.3 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc9_16: i32 = int_literal 1 [template = constants.%.6] +// 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.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: --- use_foo.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// 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: %Use.type: type = fn_type @Use [template] +// CHECK:STDOUT: %Use: %Use.type = struct_value () [template] +// CHECK:STDOUT: %CompleteClass.type: type = generic_class_type @CompleteClass [template] +// CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {.n: i32} [template] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] +// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, (i32) [template] +// CHECK:STDOUT: %.3: type = ptr_type %.2 [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: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Class = %import_ref.1 +// CHECK:STDOUT: .CompleteClass = %import_ref.2 +// CHECK:STDOUT: .F = %import_ref.3 +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Use = %Use.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+5, unloaded +// CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref ir1, inst+12, loaded [template = constants.%CompleteClass.1] +// CHECK:STDOUT: %import_ref.3: %F.type.1 = import_ref ir1, inst+48, loaded [template = constants.%F.1] +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %import_ref.4: %Int32.type = import_ref ir4, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: %Use.decl: %Use.type = fn_decl @Use [template = constants.%Use] { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc5_13.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc5_13.2: type = converted %int.make_type_32, %.loc5_13.1 [template = i32] +// CHECK:STDOUT: @Use.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+15, unloaded +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+25, unloaded +// CHECK:STDOUT: %import_ref.7: %F.type.2 = import_ref ir1, inst+33, loaded [template = constants.%F.2] +// CHECK:STDOUT: %import_ref.8: %Int32.type = import_ref ir4, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @CompleteClass { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = file.%import_ref.5 +// CHECK:STDOUT: .n = file.%import_ref.6 +// CHECK:STDOUT: .F = file.%import_ref.7 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Use() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %CompleteClass.ref: %CompleteClass.type = name_ref CompleteClass, file.%import_ref.2 [template = constants.%CompleteClass.1] +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc6_23.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc6_23.2: type = converted %int.make_type_32, %.loc6_23.1 [template = i32] +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, (%.loc6_23.2) [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, file.%import_ref.3 [template = constants.%F.1] +// 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, file.%import_ref.7 [template = constants.%F.2] +// 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: +// CHECK:STDOUT: fn @F.2() -> i32; +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_use_foo.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// 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: %Use.type: type = fn_type @Use [template] +// CHECK:STDOUT: %Use: %Use.type = struct_value () [template] +// CHECK:STDOUT: %CompleteClass.type: type = generic_class_type @CompleteClass [template] +// CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {.n: i32} [template] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] +// CHECK:STDOUT: %CompleteClass.3: type = class_type @CompleteClass, (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 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Class = %import_ref.1 +// CHECK:STDOUT: .CompleteClass = %import_ref.2 +// CHECK:STDOUT: .F = %import_ref.3 +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Use = %Use.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+5, unloaded +// CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref ir1, inst+12, loaded [template = constants.%CompleteClass.1] +// CHECK:STDOUT: %import_ref.3: %F.type = import_ref ir1, inst+48, loaded [template = constants.%F] +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %import_ref.4: %Int32.type = import_ref ir4, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: %Use.decl: %Use.type = fn_decl @Use [template = constants.%Use] { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc5_13.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc5_13.2: type = converted %int.make_type_32, %.loc5_13.1 [template = i32] +// CHECK:STDOUT: @Use.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+15, unloaded +// CHECK:STDOUT: %import_ref.6: %.4 = import_ref ir1, inst+25, loaded [template = imports.%.1] +// CHECK:STDOUT: %import_ref.7 = import_ref ir1, inst+33, unloaded +// CHECK:STDOUT: %import_ref.8: %Int32.type = import_ref ir4, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @CompleteClass { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = file.%import_ref.5 +// CHECK:STDOUT: .n = file.%import_ref.6 +// CHECK:STDOUT: .F = file.%import_ref.7 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Use() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %CompleteClass.ref: %CompleteClass.type = name_ref CompleteClass, file.%import_ref.2 [template = constants.%CompleteClass.1] +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc6_23.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc6_23.2: type = converted %int.make_type_32, %.loc6_23.1 [template = i32] +// CHECK:STDOUT: %CompleteClass: type = class_type @CompleteClass, (%.loc6_23.2) [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, file.%import_ref.3 [template = constants.%F] +// 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, file.%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: +// CHECK:STDOUT: --- fail_generic_arg_mismatch.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Use.type: type = fn_type @Use [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Use: %Use.type = struct_value () [template] +// CHECK:STDOUT: %CompleteClass.type: type = generic_class_type @CompleteClass [template] +// CHECK:STDOUT: %CompleteClass.1: %CompleteClass.type = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {.n: i32} [template] +// CHECK:STDOUT: %CompleteClass.2: type = class_type @CompleteClass [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [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, (%.3) [template] +// CHECK:STDOUT: %.4: type = ptr_type %.2 [template] +// CHECK:STDOUT: %CompleteClass.4: type = class_type @CompleteClass, (i32) [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Class = %import_ref.1 +// CHECK:STDOUT: .CompleteClass = %import_ref.2 +// CHECK:STDOUT: .F = %import_ref.3 +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Use = %Use.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+5, unloaded +// CHECK:STDOUT: %import_ref.2: %CompleteClass.type = import_ref ir1, inst+12, loaded [template = constants.%CompleteClass.1] +// CHECK:STDOUT: %import_ref.3: %F.type = import_ref ir1, inst+48, loaded [template = constants.%F] +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Use.decl: %Use.type = fn_decl @Use [template = constants.%Use] {} +// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+15, unloaded +// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+25, unloaded +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+33, unloaded +// CHECK:STDOUT: %import_ref.7: %Int32.type = import_ref ir4, inst+3, loaded [template = constants.%Int32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @CompleteClass { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = file.%import_ref.4 +// CHECK:STDOUT: .n = file.%import_ref.5 +// CHECK:STDOUT: .F = file.%import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Use() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %CompleteClass.ref: %CompleteClass.type = name_ref CompleteClass, file.%import_ref.2 [template = constants.%CompleteClass.1] +// 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: %CompleteClass: type = class_type @CompleteClass, (%.loc11_27.3) [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, file.%import_ref.3 [template = constants.%F] +// 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: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() -> %CompleteClass.4; +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_bad_foo.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %U: type = bind_symbolic_name U 0 [symbolic] // CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template] // CHECK:STDOUT: %.1: type = tuple_type () [template] -// CHECK:STDOUT: %Class: %Class.type = struct_value () [template] -// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] +// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] // CHECK:STDOUT: %.type: type = generic_class_type @.1 [template] // CHECK:STDOUT: %.2: %.type = struct_value () [template] // CHECK:STDOUT: %.3: type = class_type @.1 [template] @@ -111,10 +491,14 @@ class Class(U:! type) { // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .Class = %import_ref +// CHECK:STDOUT: .Class = %import_ref.1 +// CHECK:STDOUT: .CompleteClass = %import_ref.2 +// CHECK:STDOUT: .F = %import_ref.3 // CHECK:STDOUT: .Core = %Core // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref: %Class.type = import_ref ir0, inst+5, loaded [template = constants.%Class] +// CHECK:STDOUT: %import_ref.1: %Class.type = import_ref ir0, inst+5, loaded [template = constants.%Class.1] +// CHECK:STDOUT: %import_ref.2 = import_ref ir0, inst+12, unloaded +// CHECK:STDOUT: %import_ref.3 = import_ref ir0, inst+48, unloaded // CHECK:STDOUT: %Core: = namespace [template] {} // CHECK:STDOUT: %.decl: %.type = class_decl @.1 [template = constants.%.2] { // CHECK:STDOUT: %U.loc9_13.1: type = param U diff --git a/toolchain/check/testdata/class/generic/redeclare.carbon b/toolchain/check/testdata/class/generic/redeclare.carbon index 91e051729028..9971523b8201 100644 --- a/toolchain/check/testdata/class/generic/redeclare.carbon +++ b/toolchain/check/testdata/class/generic/redeclare.carbon @@ -94,7 +94,6 @@ class E(U:! type) {} // CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %Generic.1: %Generic.type = struct_value () [template] // CHECK:STDOUT: %Generic.2: type = class_type @Generic [template] -// CHECK:STDOUT: %struct: type = struct_value () [template] // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -108,7 +107,7 @@ class E(U:! type) {} // CHECK:STDOUT: %T.loc4_15.1: type = param T // CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T 0, %T.loc4_15.1 [symbolic = constants.%T] // CHECK:STDOUT: } -// CHECK:STDOUT: %Generic.decl.loc6: type = class_decl @Generic [template = constants.%struct] { +// CHECK:STDOUT: %Generic.decl.loc6: %Generic.type = class_decl @Generic [template = constants.%Generic.1] { // CHECK:STDOUT: %T.loc6_15.1: type = param T // CHECK:STDOUT: %T.loc6_15.2: type = bind_symbolic_name T 0, %T.loc6_15.1 [symbolic = constants.%T] // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon b/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon index f44dddf2b6de..8a3367fba12e 100644 --- a/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon +++ b/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon @@ -13,17 +13,9 @@ interface GenericInterface(T:! type) { } class C { - // CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+11]]:3: ERROR: Cannot `extend` a parameterized `impl`. + // CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+3]]:3: ERROR: Cannot `extend` a parameterized `impl`. // CHECK:STDERR: extend impl forall [T:! type] as GenericInterface(T) { // CHECK:STDERR: ^~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+7]]:3: ERROR: Semantics TODO: `impl as non-interface`. - // CHECK:STDERR: extend impl forall [T:! type] as GenericInterface(T) { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+3]]:36: ERROR: Value of type `type` is not callable. - // CHECK:STDERR: extend impl forall [T:! type] as GenericInterface(T) { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ extend impl forall [T:! type] as GenericInterface(T) { fn F(x: T) {} } @@ -33,17 +25,20 @@ class C { // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %.1: type = interface_type @GenericInterface [template] -// CHECK:STDOUT: %Self: %.1 = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %GenericInterface.type: type = generic_interface_type @GenericInterface [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %GenericInterface: %GenericInterface.type = struct_value () [template] +// CHECK:STDOUT: %Self: %GenericInterface = bind_symbolic_name Self 1 [symbolic] // CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] -// CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] -// CHECK:STDOUT: %.3: type = assoc_entity_type @GenericInterface, %F.type.1 [template] -// CHECK:STDOUT: %.4: %.3 = assoc_entity element0, @GenericInterface.%F.decl [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @GenericInterface, %F.type.1 [template] +// CHECK:STDOUT: %.3: %.2 = assoc_entity element0, @GenericInterface.%F.decl [template] // CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.4: type = interface_type @GenericInterface, (%T) [symbolic] // CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template] // CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template] -// CHECK:STDOUT: %.5: type = struct_type {} [template] +// CHECK:STDOUT: %.5: = interface_witness (%F.2) [template] +// CHECK:STDOUT: %.6: type = struct_type {} [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -53,7 +48,7 @@ class C { // CHECK:STDOUT: .C = %C.decl // CHECK:STDOUT: } // CHECK:STDOUT: %Core: = namespace [template] {} -// CHECK:STDOUT: %GenericInterface.decl: type = interface_decl @GenericInterface [template = constants.%.1] { +// CHECK:STDOUT: %GenericInterface.decl: %GenericInterface.type = interface_decl @GenericInterface [template = constants.%GenericInterface] { // CHECK:STDOUT: %T.loc11_28.1: type = param T // CHECK:STDOUT: %T.loc11_28.2: type = bind_symbolic_name T 0, %T.loc11_28.1 [symbolic = constants.%T] // CHECK:STDOUT: } @@ -61,13 +56,13 @@ class C { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @GenericInterface { -// CHECK:STDOUT: %Self: %.1 = bind_symbolic_name Self 1 [symbolic = constants.%Self] +// CHECK:STDOUT: %Self: %GenericInterface = bind_symbolic_name Self 1 [symbolic = constants.%Self] // CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] { // CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc11_28.2 [symbolic = constants.%T] // CHECK:STDOUT: %x.loc12_8.1: %T = param x // CHECK:STDOUT: %x.loc12_8.2: %T = bind_name x, %x.loc12_8.1 // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc12: %.3 = assoc_entity element0, %F.decl [template = constants.%.4] +// CHECK:STDOUT: %.loc12: %.2 = assoc_entity element0, %F.decl [template = constants.%.3] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self @@ -75,24 +70,26 @@ class C { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl: %C as { +// CHECK:STDOUT: impl @impl: %C as %.4 { // CHECK:STDOUT: %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] { -// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc27_23.2 [symbolic = constants.%T] -// CHECK:STDOUT: %x.loc28_10.1: %T = param x -// CHECK:STDOUT: %x.loc28_10.2: %T = bind_name x, %x.loc28_10.1 +// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc19_23.2 [symbolic = constants.%T] +// CHECK:STDOUT: %x.loc20_10.1: %T = param x +// CHECK:STDOUT: %x.loc20_10.2: %T = bind_name x, %x.loc20_10.1 // CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%F.decl) [template = constants.%.5] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .F = %F.decl -// CHECK:STDOUT: witness = +// CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @C { // CHECK:STDOUT: impl_decl @impl { -// CHECK:STDOUT: %T.loc27_23.1: type = param T -// CHECK:STDOUT: %T.loc27_23.2: type = bind_symbolic_name T 0, %T.loc27_23.1 [symbolic = constants.%T] -// CHECK:STDOUT: %GenericInterface.ref: type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%.1] -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc27_23.2 [symbolic = constants.%T] +// CHECK:STDOUT: %T.loc19_23.1: type = param T +// CHECK:STDOUT: %T.loc19_23.2: type = bind_symbolic_name T 0, %T.loc19_23.1 [symbolic = constants.%T] +// CHECK:STDOUT: %GenericInterface.ref: %GenericInterface.type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%GenericInterface] +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc19_23.2 [symbolic = constants.%T] +// CHECK:STDOUT: %.loc19: type = interface_type @GenericInterface, (%T.ref) [symbolic = constants.%.4] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -102,7 +99,7 @@ class C { // CHECK:STDOUT: // CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc12_8.2: %T); // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(@impl.%x.loc28_10.2: %T) { +// CHECK:STDOUT: fn @F.2(@impl.%x.loc20_10.2: %T) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon b/toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon index 114af56486b2..e3e85c69f2ff 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon @@ -42,16 +42,20 @@ interface DifferentParams(T:! ()) {} // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: type = interface_type @NotGeneric [template] // CHECK:STDOUT: %T.1: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %.2: type = interface_type @.1 [template] -// CHECK:STDOUT: %Self.1: %.2 = bind_symbolic_name Self 1 [symbolic] -// CHECK:STDOUT: %.3: type = interface_type @Generic [template] +// CHECK:STDOUT: %.type.1: type = generic_interface_type @.1 [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: %.type.1 = struct_value () [template] +// CHECK:STDOUT: %Self.1: %.3 = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %Generic.type: type = generic_interface_type @Generic [template] +// CHECK:STDOUT: %Generic: %Generic.type = struct_value () [template] // CHECK:STDOUT: %.4: type = interface_type @.2 [template] // CHECK:STDOUT: %Self.2: %.4 = bind_symbolic_name Self 0 [symbolic] -// CHECK:STDOUT: %.5: type = interface_type @DifferentParams [template] -// CHECK:STDOUT: %.6: type = tuple_type () [template] -// CHECK:STDOUT: %T.2: %.6 = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %.7: type = interface_type @.3 [template] -// CHECK:STDOUT: %Self.3: %.7 = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %DifferentParams.type: type = generic_interface_type @DifferentParams [template] +// CHECK:STDOUT: %DifferentParams: %DifferentParams.type = struct_value () [template] +// CHECK:STDOUT: %T.2: %.2 = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %.type.2: type = generic_interface_type @.3 [template] +// CHECK:STDOUT: %.5: %.type.2 = struct_value () [template] +// CHECK:STDOUT: %Self.3: %.5 = bind_symbolic_name Self 1 [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -61,31 +65,31 @@ interface DifferentParams(T:! ()) {} // CHECK:STDOUT: .DifferentParams = %DifferentParams.decl // CHECK:STDOUT: } // CHECK:STDOUT: %NotGeneric.decl: type = interface_decl @NotGeneric [template = constants.%.1] {} -// CHECK:STDOUT: %.decl.loc19: type = interface_decl @.1 [template = constants.%.2] { +// CHECK:STDOUT: %.decl.loc19: %.type.1 = interface_decl @.1 [template = constants.%.3] { // CHECK:STDOUT: %T.loc19_22.1: type = param T // CHECK:STDOUT: %T.loc19_22.2: type = bind_symbolic_name T 0, %T.loc19_22.1 [symbolic = constants.%T.1] // CHECK:STDOUT: } -// CHECK:STDOUT: %Generic.decl: type = interface_decl @Generic [template = constants.%.3] { +// CHECK:STDOUT: %Generic.decl: %Generic.type = interface_decl @Generic [template = constants.%Generic] { // CHECK:STDOUT: %T.loc21_19.1: type = param T // CHECK:STDOUT: %T.loc21_19.2: type = bind_symbolic_name T 0, %T.loc21_19.1 [symbolic = constants.%T.1] // CHECK:STDOUT: } // CHECK:STDOUT: %.decl.loc29: type = interface_decl @.2 [template = constants.%.4] {} -// CHECK:STDOUT: %DifferentParams.decl: type = interface_decl @DifferentParams [template = constants.%.5] { +// CHECK:STDOUT: %DifferentParams.decl: %DifferentParams.type = interface_decl @DifferentParams [template = constants.%DifferentParams] { // CHECK:STDOUT: %T.loc31_27.1: type = param T // CHECK:STDOUT: %T.loc31_27.2: type = bind_symbolic_name T 0, %T.loc31_27.1 [symbolic = constants.%T.1] // CHECK:STDOUT: } -// CHECK:STDOUT: %.decl.loc38: type = interface_decl @.3 [template = constants.%.7] { -// CHECK:STDOUT: %.loc38_32.1: %.6 = tuple_literal () -// CHECK:STDOUT: %.loc38_32.2: type = converted %.loc38_32.1, constants.%.6 [template = constants.%.6] -// CHECK:STDOUT: %T.loc38_27.1: %.6 = param T -// CHECK:STDOUT: %T.loc38_27.2: %.6 = bind_symbolic_name T 0, %T.loc38_27.1 [symbolic = constants.%T.2] +// CHECK:STDOUT: %.decl.loc38: %.type.2 = interface_decl @.3 [template = constants.%.5] { +// CHECK:STDOUT: %.loc38_32.1: %.2 = tuple_literal () +// CHECK:STDOUT: %.loc38_32.2: type = converted %.loc38_32.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: %T.loc38_27.1: %.2 = param T +// CHECK:STDOUT: %T.loc38_27.2: %.2 = bind_symbolic_name T 0, %T.loc38_27.1 [symbolic = constants.%T.2] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @NotGeneric; // CHECK:STDOUT: // CHECK:STDOUT: interface @.1 { -// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 1 [symbolic = constants.%Self.1] +// CHECK:STDOUT: %Self: %.3 = bind_symbolic_name Self 1 [symbolic = constants.%Self.1] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self @@ -105,7 +109,7 @@ interface DifferentParams(T:! ()) {} // CHECK:STDOUT: interface @DifferentParams; // CHECK:STDOUT: // CHECK:STDOUT: interface @.3 { -// CHECK:STDOUT: %Self: %.7 = bind_symbolic_name Self 1 [symbolic = constants.%Self.3] +// CHECK:STDOUT: %Self: %.5 = bind_symbolic_name Self 1 [symbolic = constants.%Self.3] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self diff --git a/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon b/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon index d39193af8e60..fcbe183c4c9f 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon @@ -9,82 +9,92 @@ // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon interface I(T:! type) { + // TODO: Declare `Self` as having type `I(T)` instead of `I`. // TODO: Use `default` here. + // CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+8]]:14: ERROR: Cannot implicitly convert from `` to `type`. + // CHECK:STDERR: fn F[self: Self]() -> Self; + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+4]]:25: ERROR: Cannot implicitly convert from `` to `type`. + // CHECK:STDERR: fn F[self: Self]() -> Self; + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fn F[self: Self]() -> Self; } -// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+6]]:1: ERROR: Duplicate name being declared in the same scope. +// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+14]]:1: ERROR: Duplicate name being declared in the same scope. // CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; } // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE-6]]:3: Name is previously declared here. // CHECK:STDERR: fn F[self: Self]() -> Self; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+7]]:24: ERROR: Cannot implicitly convert from `` to `type`. +// CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; } +// CHECK:STDERR: ^~~~ +// CHECK:STDERR: +// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+3]]:35: ERROR: Cannot implicitly convert from `` to `type`. +// CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; } +// CHECK:STDERR: ^~~~ fn I(T:! type).F[self: Self]() -> Self { return self; } // CHECK:STDOUT: --- fail_todo_generic_default_fn.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %.1: type = interface_type @I [template] -// CHECK:STDOUT: %Self: %.1 = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %I.type: type = generic_interface_type @I [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %I: %I.type = struct_value () [template] +// CHECK:STDOUT: %Self: %I = bind_symbolic_name Self 1 [symbolic] // CHECK:STDOUT: %F.type: type = fn_type @F [template] -// CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %.3: type = assoc_entity_type @I, %F.type [template] -// CHECK:STDOUT: %.4: %.3 = assoc_entity element0, @I.%F.decl [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @I, %F.type [template] +// CHECK:STDOUT: %.3: %.2 = assoc_entity element0, @I.%F.decl [template] // CHECK:STDOUT: %.type: type = fn_type @.1 [template] -// CHECK:STDOUT: %.5: %.type = struct_value () [template] +// CHECK:STDOUT: %.4: %.type = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .I = %I.decl // CHECK:STDOUT: } -// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] { +// CHECK:STDOUT: %I.decl: %I.type = interface_decl @I [template = constants.%I] { // CHECK:STDOUT: %T.loc11_13.1: type = param T // CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T] // CHECK:STDOUT: } -// CHECK:STDOUT: %.decl: %.type = fn_decl @.1 [template = constants.%.5] { -// CHECK:STDOUT: %T.loc22_6.1: type = param T -// CHECK:STDOUT: %T.loc22_6.2: type = bind_symbolic_name T 0, %T.loc22_6.1 [symbolic = constants.%T] -// CHECK:STDOUT: %Self.ref.loc22_24: %.1 = name_ref Self, @I.%Self [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc22_24.1: type = facet_type_access %Self.ref.loc22_24 [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc22_24.2: type = converted %Self.ref.loc22_24, %.loc22_24.1 [symbolic = constants.%Self] -// CHECK:STDOUT: %self.loc22_18.1: %Self = param self -// CHECK:STDOUT: @.1.%self: %Self = bind_name self, %self.loc22_18.1 -// CHECK:STDOUT: %Self.ref.loc22_35: %.1 = name_ref Self, @I.%Self [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc22_35.1: type = facet_type_access %Self.ref.loc22_35 [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc22_35.2: type = converted %Self.ref.loc22_35, %.loc22_35.1 [symbolic = constants.%Self] -// CHECK:STDOUT: @.1.%return: ref %Self = var +// CHECK:STDOUT: %.decl: %.type = fn_decl @.1 [template = constants.%.4] { +// CHECK:STDOUT: %T.loc39_6.1: type = param T +// CHECK:STDOUT: %T.loc39_6.2: type = bind_symbolic_name T 0, %T.loc39_6.1 [symbolic = constants.%T] +// CHECK:STDOUT: %Self.ref.loc39_24: %I = name_ref Self, @I.%Self [symbolic = constants.%Self] +// CHECK:STDOUT: %self.loc39_18.1: = param self +// CHECK:STDOUT: @.1.%self: = bind_name self, %self.loc39_18.1 +// CHECK:STDOUT: %Self.ref.loc39_35: %I = name_ref Self, @I.%Self [symbolic = constants.%Self] +// CHECK:STDOUT: @.1.%return: ref = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @I { -// CHECK:STDOUT: %Self: %.1 = bind_symbolic_name Self 1 [symbolic = constants.%Self] +// CHECK:STDOUT: %Self: %I = bind_symbolic_name Self 1 [symbolic = constants.%Self] // CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { -// CHECK:STDOUT: %Self.ref.loc13_14: %.1 = name_ref Self, %Self [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc13_14.1: type = facet_type_access %Self.ref.loc13_14 [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc13_14.2: type = converted %Self.ref.loc13_14, %.loc13_14.1 [symbolic = constants.%Self] -// CHECK:STDOUT: %self.loc13_8.1: %Self = param self -// CHECK:STDOUT: %self.loc13_8.2: %Self = bind_name self, %self.loc13_8.1 -// CHECK:STDOUT: %Self.ref.loc13_25: %.1 = name_ref Self, %Self [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc13_25.1: type = facet_type_access %Self.ref.loc13_25 [symbolic = constants.%Self] -// CHECK:STDOUT: %.loc13_25.2: type = converted %Self.ref.loc13_25, %.loc13_25.1 [symbolic = constants.%Self] -// CHECK:STDOUT: %return.var: ref %Self = var +// CHECK:STDOUT: %Self.ref.loc22_14: %I = name_ref Self, %Self [symbolic = constants.%Self] +// CHECK:STDOUT: %self.loc22_8.1: = param self +// CHECK:STDOUT: %self.loc22_8.2: = bind_name self, %self.loc22_8.1 +// CHECK:STDOUT: %Self.ref.loc22_25: %I = name_ref Self, %Self [symbolic = constants.%Self] +// CHECK:STDOUT: %return.var: ref = var // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc13_29: %.3 = assoc_entity element0, %F.decl [template = constants.%.4] +// CHECK:STDOUT: %.loc22: %.2 = assoc_entity element0, %F.decl [template = constants.%.3] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self -// CHECK:STDOUT: .F = %.loc13_29 +// CHECK:STDOUT: .F = %.loc22 // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F[@I.%self.loc13_8.2: %Self]() -> %Self; +// CHECK:STDOUT: fn @F[@I.%self.loc22_8.2: ]() -> ; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1[%self: %Self]() -> %Self { +// CHECK:STDOUT: fn @.1[%self: ]() -> { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %self.ref: %Self = name_ref self, %self -// CHECK:STDOUT: return %self.ref +// CHECK:STDOUT: %self.ref: = name_ref self, %self +// CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/generic.carbon b/toolchain/check/testdata/interface/no_prelude/generic.carbon index 1ffc2a696b11..c863c33e8bda 100644 --- a/toolchain/check/testdata/interface/no_prelude/generic.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic.carbon @@ -8,28 +8,295 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/generic.carbon -interface I[T:! type](N:! T); +// --- generic.carbon + +library "generic"; + +interface Simple(T:! type) {} + +class X {} + +interface WithAssocFn(T:! type) { + // TODO: Take `Self`, return `T`, once that works. + fn F() -> X; +} + +class C { + impl as Simple(C) {} + impl as WithAssocFn(C) { + fn F() -> X { + return {}; + } + } +} + +interface WithImplicitArgs[T:! type](N:! T); + +fn Receive(T:! Simple(C)); +fn Pass(T:! Simple(C)) { + Receive(T); +} + +// --- fail_mismatched_args.carbon + +library "fail_mismatched_args"; + +interface Generic(T:! type) {} + +class A {} +class B {} + +fn F(T:! Generic(A)); +fn G(T:! Generic(B)) { + // TODO: Include generic arguments in the type name. + // CHECK:STDERR: fail_mismatched_args.carbon:[[@LINE+6]]:3: ERROR: Cannot implicitly convert from `Generic` to `Generic`. + // CHECK:STDERR: F(T); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_mismatched_args.carbon:[[@LINE-6]]:1: Initializing parameter 1 of function declared here. + // CHECK:STDERR: fn F(T:! Generic(A)); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~ + F(T); +} // CHECK:STDOUT: --- generic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %N: %T = bind_symbolic_name N 1 [symbolic] -// CHECK:STDOUT: %.1: type = interface_type @I [template] +// CHECK:STDOUT: %T.1: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Simple.type: type = generic_interface_type @Simple [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Simple: %Simple.type = struct_value () [template] +// CHECK:STDOUT: %Self.1: %Simple = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %X: type = class_type @X [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %WithAssocFn.type: type = generic_interface_type @WithAssocFn [template] +// CHECK:STDOUT: %WithAssocFn: %WithAssocFn.type = struct_value () [template] +// CHECK:STDOUT: %Self.2: %WithAssocFn = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] +// CHECK:STDOUT: %.3: type = assoc_entity_type @WithAssocFn, %F.type.1 [template] +// CHECK:STDOUT: %.4: %.3 = assoc_entity element0, @WithAssocFn.%F.decl [template] +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.5: type = interface_type @Simple, (%C) [template] +// CHECK:STDOUT: %.6: = interface_witness () [template] +// CHECK:STDOUT: %.7: type = interface_type @WithAssocFn, (%C) [template] +// CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template] +// CHECK:STDOUT: %.8: = interface_witness (%F.2) [template] +// CHECK:STDOUT: %.9: type = ptr_type %.2 [template] +// CHECK:STDOUT: %struct: %X = struct_value () [template] +// CHECK:STDOUT: %N: %T.1 = bind_symbolic_name N 1 [symbolic] +// CHECK:STDOUT: %WithImplicitArgs.type: type = generic_interface_type @WithImplicitArgs [template] +// CHECK:STDOUT: %WithImplicitArgs: %WithImplicitArgs.type = struct_value () [template] +// CHECK:STDOUT: %T.2: %.5 = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Receive.type: type = fn_type @Receive [template] +// CHECK:STDOUT: %Receive: %Receive.type = struct_value () [template] +// CHECK:STDOUT: %Pass.type: type = fn_type @Pass [template] +// CHECK:STDOUT: %Pass: %Pass.type = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: .Simple = %Simple.decl +// CHECK:STDOUT: .X = %X.decl +// CHECK:STDOUT: .WithAssocFn = %WithAssocFn.decl +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .WithImplicitArgs = %WithImplicitArgs.decl +// CHECK:STDOUT: .Receive = %Receive.decl +// CHECK:STDOUT: .Pass = %Pass.decl // CHECK:STDOUT: } -// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] { -// CHECK:STDOUT: %T.loc11_13.1: type = param T -// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T] -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc11_13.2 [symbolic = constants.%T] -// CHECK:STDOUT: %N.loc11_23.1: %T = param N -// CHECK:STDOUT: %N.loc11_23.2: %T = bind_symbolic_name N 1, %N.loc11_23.1 [symbolic = constants.%N] +// CHECK:STDOUT: %Simple.decl: %Simple.type = interface_decl @Simple [template = constants.%Simple] { +// CHECK:STDOUT: %T.loc4_18.1: type = param T +// CHECK:STDOUT: %T.loc4_18.2: type = bind_symbolic_name T 0, %T.loc4_18.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %X.decl: type = class_decl @X [template = constants.%X] {} +// CHECK:STDOUT: %WithAssocFn.decl: %WithAssocFn.type = interface_decl @WithAssocFn [template = constants.%WithAssocFn] { +// CHECK:STDOUT: %T.loc8_23.1: type = param T +// CHECK:STDOUT: %T.loc8_23.2: type = bind_symbolic_name T 0, %T.loc8_23.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: %WithImplicitArgs.decl: %WithImplicitArgs.type = interface_decl @WithImplicitArgs [template = constants.%WithImplicitArgs] { +// CHECK:STDOUT: %T.loc22_28.1: type = param T +// CHECK:STDOUT: %T.loc22_28.2: type = bind_symbolic_name T 0, %T.loc22_28.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc22_28.2 [symbolic = constants.%T.1] +// CHECK:STDOUT: %N.loc22_38.1: %T.1 = param N +// CHECK:STDOUT: %N.loc22_38.2: %T.1 = bind_symbolic_name N 1, %N.loc22_38.1 [symbolic = constants.%N] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Receive.decl: %Receive.type = fn_decl @Receive [template = constants.%Receive] { +// CHECK:STDOUT: %Simple.ref.loc24: %Simple.type = name_ref Simple, %Simple.decl [template = constants.%Simple] +// CHECK:STDOUT: %C.ref.loc24: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc24: type = interface_type @Simple, (%C.ref.loc24) [template = constants.%.5] +// CHECK:STDOUT: %T.loc24_12.1: %.5 = param T +// CHECK:STDOUT: @Receive.%T: %.5 = bind_symbolic_name T 0, %T.loc24_12.1 [symbolic = constants.%T.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Pass.decl: %Pass.type = fn_decl @Pass [template = constants.%Pass] { +// CHECK:STDOUT: %Simple.ref.loc25: %Simple.type = name_ref Simple, %Simple.decl [template = constants.%Simple] +// CHECK:STDOUT: %C.ref.loc25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc25: type = interface_type @Simple, (%C.ref.loc25) [template = constants.%.5] +// CHECK:STDOUT: %T.loc25_9.1: %.5 = param T +// CHECK:STDOUT: @Pass.%T: %.5 = bind_symbolic_name T 0, %T.loc25_9.1 [symbolic = constants.%T.2] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: interface @I; +// CHECK:STDOUT: interface @Simple { +// CHECK:STDOUT: %Self: %Simple = bind_symbolic_name Self 1 [symbolic = constants.%Self.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @WithAssocFn { +// CHECK:STDOUT: %Self: %WithAssocFn = bind_symbolic_name Self 1 [symbolic = constants.%Self.2] +// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] { +// CHECK:STDOUT: %X.ref: type = name_ref X, file.%X.decl [template = constants.%X] +// CHECK:STDOUT: %return.var: ref %X = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc10: %.3 = assoc_entity element0, %F.decl [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %.loc10 +// CHECK:STDOUT: witness = (%F.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @WithImplicitArgs; +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: %C as %.5 { +// CHECK:STDOUT: %.1: = interface_witness () [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: %C as %.7 { +// CHECK:STDOUT: %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] { +// CHECK:STDOUT: %X.ref: type = name_ref X, file.%X.decl [template = constants.%X] +// CHECK:STDOUT: %return.var: ref %X = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%F.decl) [template = constants.%.8] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @X { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%X +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %Simple.ref: %Simple.type = name_ref Simple, file.%Simple.decl [template = constants.%Simple] +// CHECK:STDOUT: %C.ref.loc14: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14: type = interface_type @Simple, (%C.ref.loc14) [template = constants.%.5] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %WithAssocFn.ref: %WithAssocFn.type = name_ref WithAssocFn, file.%WithAssocFn.decl [template = constants.%WithAssocFn] +// CHECK:STDOUT: %C.ref.loc15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc15: type = interface_type @WithAssocFn, (%C.ref.loc15) [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.1() -> %X; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2() -> @impl.2.%return.var: %X { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc17_15.1: %.2 = struct_literal () +// CHECK:STDOUT: %.loc17_15.2: init %X = class_init (), @impl.2.%return.var [template = constants.%struct] +// CHECK:STDOUT: %.loc17_16: init %X = converted %.loc17_15.1, %.loc17_15.2 [template = constants.%struct] +// CHECK:STDOUT: return %.loc17_16 to @impl.2.%return.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Receive(%T: %.5); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Pass(%T: %.5) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Receive.ref: %Receive.type = name_ref Receive, file.%Receive.decl [template = constants.%Receive] +// CHECK:STDOUT: %T.ref: %.5 = name_ref T, %T [symbolic = constants.%T.2] +// CHECK:STDOUT: %Receive.call: init %.1 = call %Receive.ref(%T.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_mismatched_args.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T.1: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Generic.type: type = generic_interface_type @Generic [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Generic: %Generic.type = struct_value () [template] +// CHECK:STDOUT: %Self: %Generic = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %A: type = class_type @A [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %B: type = class_type @B [template] +// CHECK:STDOUT: %.3: type = interface_type @Generic, (%A) [template] +// CHECK:STDOUT: %T.2: %.3 = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = interface_type @Generic, (%B) [template] +// CHECK:STDOUT: %T.3: %.4 = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %G.type: type = fn_type @G [template] +// CHECK:STDOUT: %G: %G.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Generic = %Generic.decl +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: .B = %B.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .G = %G.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Generic.decl: %Generic.type = interface_decl @Generic [template = constants.%Generic] { +// CHECK:STDOUT: %T.loc4_19.1: type = param T +// CHECK:STDOUT: %T.loc4_19.2: type = bind_symbolic_name T 0, %T.loc4_19.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %A.decl: type = class_decl @A [template = constants.%A] {} +// CHECK:STDOUT: %B.decl: type = class_decl @B [template = constants.%B] {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %Generic.ref.loc9: %Generic.type = name_ref Generic, %Generic.decl [template = constants.%Generic] +// CHECK:STDOUT: %A.ref: type = name_ref A, %A.decl [template = constants.%A] +// CHECK:STDOUT: %.loc9: type = interface_type @Generic, (%A.ref) [template = constants.%.3] +// CHECK:STDOUT: %T.loc9_6.1: %.3 = param T +// CHECK:STDOUT: @F.%T: %.3 = bind_symbolic_name T 0, %T.loc9_6.1 [symbolic = constants.%T.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { +// CHECK:STDOUT: %Generic.ref.loc10: %Generic.type = name_ref Generic, %Generic.decl [template = constants.%Generic] +// CHECK:STDOUT: %B.ref: type = name_ref B, %B.decl [template = constants.%B] +// CHECK:STDOUT: %.loc10: type = interface_type @Generic, (%B.ref) [template = constants.%.4] +// CHECK:STDOUT: %T.loc10_6.1: %.4 = param T +// CHECK:STDOUT: @G.%T: %.4 = bind_symbolic_name T 0, %T.loc10_6.1 [symbolic = constants.%T.3] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Generic { +// CHECK:STDOUT: %Self: %Generic = bind_symbolic_name Self 1 [symbolic = constants.%Self] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @A { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%A +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @B { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%B +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%T: %.3); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G(%T: %.4) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %T.ref: %.4 = name_ref T, %T [symbolic = constants.%T.3] +// CHECK:STDOUT: %F.call: init %.1 = call %F.ref() [template = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/generic_import.carbon b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon new file mode 100644 index 000000000000..4e5d16afa7a0 --- /dev/null +++ b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon @@ -0,0 +1,134 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/generic_import.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/generic_import.carbon + +// --- a.carbon + +library "a"; + +interface AddWith(T:! type) { + fn F(); +} + +// --- fail_todo_b.carbon + +library "b"; +// CHECK:STDERR: fail_todo_b.carbon:[[@LINE+4]]:1: In import. +// CHECK:STDERR: import library "a"; +// CHECK:STDERR: ^~~~~~ +// CHECK:STDERR: a.carbon: ERROR: Semantics TODO: `TryResolveInst on StructValue`. +import library "a"; + +class C {} + +impl C as AddWith(C) { + fn F() {} +} + +// CHECK:STDOUT: --- a.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %AddWith.type: type = generic_interface_type @AddWith [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %AddWith: %AddWith.type = struct_value () [template] +// CHECK:STDOUT: %Self: %AddWith = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @AddWith, %F.type [template] +// CHECK:STDOUT: %.3: %.2 = assoc_entity element0, @AddWith.%F.decl [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .AddWith = %AddWith.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %AddWith.decl: %AddWith.type = interface_decl @AddWith [template = constants.%AddWith] { +// CHECK:STDOUT: %T.loc4_19.1: type = param T +// CHECK:STDOUT: %T.loc4_19.2: type = bind_symbolic_name T 0, %T.loc4_19.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddWith { +// CHECK:STDOUT: %Self: %AddWith = bind_symbolic_name Self 1 [symbolic = constants.%Self] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} +// CHECK:STDOUT: %.loc5: %.2 = assoc_entity element0, %F.decl [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %.loc5 +// CHECK:STDOUT: witness = (%F.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_b.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %AddWith.type: type = generic_interface_type @AddWith [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %AddWith: %AddWith.type = struct_value () [template] +// CHECK:STDOUT: %Self: = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] +// CHECK:STDOUT: %.3: type = interface_type @AddWith, (%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: %.4: = interface_witness (%F.1) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .AddWith = %import_ref.1 +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: %AddWith.type = import_ref ir1, inst+4, loaded [template = constants.%AddWith] +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+8, unloaded +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+14, unloaded +// CHECK:STDOUT: %import_ref.4: %F.type.2 = import_ref ir1, inst+10, loaded [template = constants.%F.2] +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref.loc11_6: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %AddWith.ref: %AddWith.type = name_ref AddWith, %import_ref.1 [template = constants.%AddWith] +// CHECK:STDOUT: %C.ref.loc11_19: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc11: type = interface_type @AddWith, (%C.ref.loc11_19) [template = constants.%.3] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddWith { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = file.%import_ref.2 +// CHECK:STDOUT: .F = file.%import_ref.3 +// CHECK:STDOUT: witness = (file.%import_ref.4) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: %C as %.3 { +// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} +// CHECK:STDOUT: %.1: = interface_witness (%F.decl) [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2(); +// CHECK:STDOUT: 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 f0780ebf0d2d..b4ae264825cb 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 @@ -65,10 +65,12 @@ export C2(T:! type); // CHECK:STDOUT: constants { // CHECK:STDOUT: %C1.type: type = generic_class_type @C1 [template] // CHECK:STDOUT: %.1: type = tuple_type () [template] -// CHECK:STDOUT: %C1: %C1.type = struct_value () [template] -// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] +// CHECK:STDOUT: %C1.1: %C1.type = struct_value () [template] +// CHECK:STDOUT: %C1.2: type = class_type @C1 [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, [symbolic] // CHECK:STDOUT: %C2.type: type = generic_class_type @C2 [template] -// CHECK:STDOUT: %C2: %C2.type = struct_value () [template] +// CHECK:STDOUT: %C2.1: %C2.type = struct_value () [template] +// CHECK:STDOUT: %C2.2: type = class_type @C2 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -76,12 +78,12 @@ export C2(T:! type); // CHECK:STDOUT: .C1 = %C1 // CHECK:STDOUT: .C2 = %C2 // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref.1: %C1.type = import_ref ir1, inst+4, loaded [template = constants.%C1] -// CHECK:STDOUT: %import_ref.2: %C2.type = import_ref ir1, inst+11, loaded [template = constants.%C2] -// CHECK:STDOUT: %C1: %C1.type = export C1, %import_ref.1 [template = constants.%C1] +// CHECK:STDOUT: %import_ref.1: %C1.type = import_ref ir1, inst+4, loaded [template = constants.%C1.1] +// CHECK:STDOUT: %import_ref.2: %C2.type = import_ref ir1, inst+11, loaded [template = constants.%C2.1] +// CHECK:STDOUT: %C1: %C1.type = export C1, %import_ref.1 [template = constants.%C1.1] // CHECK:STDOUT: %T.loc11_11.1: type = param T // CHECK:STDOUT: %T.loc11_11.2: type = bind_symbolic_name T 0, %T.loc11_11.1 [symbolic = constants.%T] -// CHECK:STDOUT: %C2: %C2.type = export C2, %import_ref.2 [template = constants.%C2] +// CHECK:STDOUT: %C2: %C2.type = export C2, %import_ref.2 [template = constants.%C2.1] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @C1; diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 30b713a357a7..310cc522f019 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -387,6 +387,7 @@ auto FileContext::BuildType(SemIR::InstId inst_id) -> llvm::Type* { case SemIR::InterfaceType::Kind: case SemIR::FunctionType::Kind: case SemIR::GenericClassType::Kind: + case SemIR::GenericInterfaceType::Kind: case SemIR::UnboundElementType::Kind: { // Return an empty struct as a placeholder. // TODO: Should we model an interface as a witness table, or an associated diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 638f56abefc7..af7086d8b71e 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -180,6 +180,7 @@ static auto GetTypePrecedence(InstKind kind) -> int { case FloatType::Kind: case FunctionType::Kind: case GenericClassType::Kind: + case GenericInterfaceType::Kind: case InterfaceType::Kind: case InterfaceWitnessAccess::Kind: case IntType::Kind: @@ -327,6 +328,13 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir, out << ""; break; } + case CARBON_KIND(GenericInterfaceType inst): { + auto interface_name_id = + sem_ir.interfaces().Get(inst.interface_id).name_id; + out << ""; + break; + } case CARBON_KIND(InterfaceType inst): { auto interface_name_id = sem_ir.interfaces().Get(inst.interface_id).name_id; @@ -567,6 +575,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case FloatType::Kind: case FunctionType::Kind: case GenericClassType::Kind: + case GenericInterfaceType::Kind: case InterfaceDecl::Kind: case InterfaceType::Kind: case InterfaceWitness::Kind: diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index fe89a54c7087..a67dada82153 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -636,6 +636,14 @@ class Formatter { FormatTrailingBlock(inst.decl_block_id); } + auto FormatInstructionRHS(InterfaceType inst) -> void { + if (inst.args_id.is_valid()) { + FormatArgs(inst.interface_id, inst.args_id); + } else { + FormatArgs(inst.interface_id); + } + } + auto FormatInstructionRHS(IntLiteral inst) -> void { out_ << " "; sem_ir_.ints() diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 2d187728dff2..d2f857b1c217 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -113,6 +113,8 @@ CARBON_SEM_IR_INST_KIND_IMPL(FunctionDecl, TYPE_NEVER, CONSTANT_NEVER) CARBON_SEM_IR_INST_KIND_IMPL(FunctionType, TYPE_ALWAYS, CONSTANT_CONDITIONAL) CARBON_SEM_IR_INST_KIND_IMPL(GenericClassType, TYPE_ALWAYS, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(GenericInterfaceType, TYPE_ALWAYS, + CONSTANT_CONDITIONAL) CARBON_SEM_IR_INST_KIND_IMPL(ImplDecl, TYPE_NEVER, CONSTANT_NEVER) CARBON_SEM_IR_INST_KIND_IMPL(ImportRefUnloaded, TYPE_NEVER, CONSTANT_NEVER) CARBON_SEM_IR_INST_KIND_IMPL(ImportRefLoaded, TYPE_NEVER, CONSTANT_NEVER) diff --git a/toolchain/sem_ir/inst_namer.cpp b/toolchain/sem_ir/inst_namer.cpp index 21f9748ebd20..afc5a1919246 100644 --- a/toolchain/sem_ir/inst_namer.cpp +++ b/toolchain/sem_ir/inst_namer.cpp @@ -441,6 +441,11 @@ auto InstNamer::CollectNamesInBlock(ScopeId scope_id, add_inst_name_id(sem_ir_.classes().Get(inst.class_id).name_id, ".type"); continue; } + case CARBON_KIND(GenericInterfaceType inst): { + add_inst_name_id(sem_ir_.interfaces().Get(inst.interface_id).name_id, + ".type"); + continue; + } case CARBON_KIND(ImplDecl inst): { CollectNamesInBlock(scope_id, inst.decl_block_id); break; @@ -489,6 +494,12 @@ auto InstNamer::CollectNamesInBlock(ScopeId scope_id, inst.type_id)) { add_inst_name_id( sem_ir_.classes().Get(generic_class_ty->class_id).name_id); + } else if (auto generic_interface_ty = + sem_ir_.types().TryGetAs( + inst.type_id)) { + add_inst_name_id(sem_ir_.interfaces() + .Get(generic_interface_ty->interface_id) + .name_id); } else { add_inst_name("struct"); } diff --git a/toolchain/sem_ir/interface.h b/toolchain/sem_ir/interface.h index 9f2c8b3feee5..f8ee2a74af16 100644 --- a/toolchain/sem_ir/interface.h +++ b/toolchain/sem_ir/interface.h @@ -25,6 +25,11 @@ struct Interface : public Printable { return definition_id.is_valid() && !is_defined(); } + // Determines whether this is a generic interface. + auto is_generic() const -> bool { + return implicit_param_refs_id.is_valid() || param_refs_id.is_valid(); + } + // The following members always have values, and do not change throughout the // lifetime of the interface. diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index ef2f10f0ece2..28f5d3b67dd9 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -525,6 +525,18 @@ struct GenericClassType { ClassId class_id; }; +// The type of the name of a generic interface. The corresponding value is an +// empty `StructValue`. +struct GenericInterfaceType { + // This is only ever created as a constant, so doesn't have a location. + static constexpr auto Kind = + InstKind::GenericInterfaceType.Define( + "generic_interface_type"); + + TypeId type_id; + InterfaceId interface_id; +}; + struct ImplDecl { static constexpr auto Kind = InstKind::ImplDecl.Define("impl_decl"); @@ -602,8 +614,7 @@ struct InterfaceType { TypeId type_id; InterfaceId interface_id; - // TODO: Once we support generic interfaces, include the interface's arguments - // here. + InstBlockId args_id = InstBlockId::Invalid; }; // A witness that a type implements an interface.