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.