diff --git a/toolchain/check/class.cpp b/toolchain/check/class.cpp index 8184d3c42954..ba2f2524f8b5 100644 --- a/toolchain/check/class.cpp +++ b/toolchain/check/class.cpp @@ -14,14 +14,6 @@ namespace Carbon::Check { -auto TryGetAsClass(Context& context, SemIR::TypeId type_id) -> SemIR::Class* { - auto class_type = context.types().TryGetAs(type_id); - if (!class_type) { - return nullptr; - } - return &context.classes().Get(class_type->class_id); -} - auto SetClassSelfType(Context& context, SemIR::ClassId class_id) -> void { auto& class_info = context.classes().Get(class_id); auto specific_id = context.generics().GetSelfSpecific(class_info.generic_id); @@ -131,10 +123,51 @@ static auto AddStructTypeFields( // Builds and returns a vtable for the current class. Assumes that the virtual // functions for the class are listed as the top element of the `vtable_stack`. -static auto BuildVtable(Context& context, SemIR::ClassId class_id, - SemIR::VtableId base_vtable_id, +static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id, + SemIR::ClassId class_id, + std::optional base_class_type, llvm::ArrayRef vtable_contents) -> SemIR::VtableId { + auto base_vtable_id = SemIR::VtableId::None; + auto base_class_specific_id = SemIR::SpecificId::None; + + // Get some base class/type/specific info. + if (base_class_type) { + auto& base_class_info = context.classes().Get(base_class_type->class_id); + auto base_vtable_ptr_inst_id = base_class_info.vtable_ptr_id; + if (base_vtable_ptr_inst_id.has_value()) { + LoadImportRef(context, base_vtable_ptr_inst_id); + auto canonical_base_vtable_inst_id = + context.constant_values().GetConstantInstId(base_vtable_ptr_inst_id); + const auto& base_vtable_ptr_inst = + context.insts().GetAs( + canonical_base_vtable_inst_id); + base_vtable_id = base_vtable_ptr_inst.vtable_id; + base_class_specific_id = base_class_type->specific_id; + } + } + + const auto& class_info = context.classes().Get(class_id); + auto class_generic_id = class_info.generic_id; + + // Wrap vtable entries in SpecificFunctions as needed/in generic classes. + auto build_specific_function = + [&](SemIR::InstId fn_decl_id) -> SemIR::InstId { + if (!class_generic_id.has_value()) { + return fn_decl_id; + } + const auto& fn_decl = + context.insts().GetAs(fn_decl_id); + const auto& function = context.functions().Get(fn_decl.function_id); + return GetOrAddInst( + context, node_id, + {.type_id = + GetSingletonType(context, SemIR::SpecificFunctionType::TypeInstId), + .callee_id = fn_decl_id, + .specific_id = + context.generics().GetSelfSpecific(function.generic_id)}); + }; + llvm::SmallVector vtable; if (base_vtable_id.has_value()) { auto base_vtable_inst_block = context.inst_blocks().Get( @@ -144,25 +177,36 @@ static auto BuildVtable(Context& context, SemIR::ClassId class_id, for (auto fn_decl_id : base_vtable_inst_block) { auto fn_decl = GetCalleeFunction(context.sem_ir(), fn_decl_id); const auto& fn = context.functions().Get(fn_decl.function_id); - for (auto override_fn_decl_id : vtable_contents) { - auto override_fn_decl = - context.insts().GetAs(override_fn_decl_id); - auto& override_fn = - context.functions().Get(override_fn_decl.function_id); - if (override_fn.virtual_modifier == - SemIR::FunctionFields::VirtualModifier::Impl && - override_fn.name_id == fn.name_id) { - // TODO: Support generic base classes, rather than passing - // `SpecificId::None`. - CheckFunctionTypeMatches(context, override_fn, fn, - SemIR::SpecificId::None, - /*check_syntax=*/false, - /*check_self=*/false); - fn_decl_id = override_fn_decl_id; - override_fn.virtual_index = vtable.size(); - CARBON_CHECK(override_fn.virtual_index == fn.virtual_index); - break; - } + const auto* i = llvm::find_if( + vtable_contents, [&](SemIR::InstId override_fn_decl_id) -> bool { + const auto& override_fn = context.functions().Get( + context.insts() + .GetAs(override_fn_decl_id) + .function_id); + return override_fn.virtual_modifier == + SemIR::FunctionFields::VirtualModifier::Impl && + override_fn.name_id == fn.name_id; + }); + if (i != vtable_contents.end()) { + auto& override_fn = context.functions().Get( + context.insts().GetAs(*i).function_id); + // TODO: Support generic base classes, rather than passing + // `SpecificId::None`. This'll need to `GetConstantValueInSpecific` for + // the base function, then extract the specific from that for use here. + CheckFunctionTypeMatches(context, override_fn, fn, + SemIR::SpecificId::None, + /*check_syntax=*/false, + /*check_self=*/false); + fn_decl_id = build_specific_function(*i); + override_fn.virtual_index = vtable.size(); + CARBON_CHECK(override_fn.virtual_index == fn.virtual_index); + } else { + // Remap the base's vtable entry to the appropriate constant usable in + // the context of the derived class (for the specific for the base + // class, for instance).. + fn_decl_id = context.sem_ir().constant_values().GetInstId( + GetConstantValueInSpecific(context.sem_ir(), base_class_specific_id, + fn_decl_id)); } vtable.push_back(fn_decl_id); } @@ -173,7 +217,7 @@ static auto BuildVtable(Context& context, SemIR::ClassId class_id, auto& fn = context.functions().Get(fn_decl.function_id); if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) { fn.virtual_index = vtable.size(); - vtable.push_back(inst_id); + vtable.push_back(build_specific_function(inst_id)); } } @@ -200,12 +244,13 @@ static auto CheckCompleteClassType( class_info.GetBaseType(context.sem_ir(), SemIR::SpecificId::None); // TODO: Use InstId from base declaration. auto base_type_inst_id = context.types().GetInstId(base_type_id); - SemIR::Class* base_class_info = nullptr; + std::optional base_class_type; if (base_type_id.has_value()) { // TODO: If the base class is template dependent, we will need to decide // whether to add a vptr as part of instantiation. - base_class_info = TryGetAsClass(context, base_type_id); - if (base_class_info && base_class_info->is_dynamic) { + base_class_type = context.types().TryGetAs(base_type_id); + if (base_class_type && + context.classes().Get(base_class_type->class_id).is_dynamic) { defining_vptr = false; } } @@ -229,35 +274,21 @@ static auto CheckCompleteClassType( } if (class_info.is_dynamic) { - SemIR::VtableId base_vtable_id = SemIR::VtableId::None; - if (base_class_info) { - auto base_vtable_ptr_inst_id = base_class_info->vtable_ptr_id; - if (base_vtable_ptr_inst_id.has_value()) { - LoadImportRef(context, base_vtable_ptr_inst_id); - auto canonical_base_vtable_inst_id = - context.constant_values().GetConstantInstId( - base_vtable_ptr_inst_id); - const auto& base_vtable_ptr_inst = - context.insts().GetAs( - canonical_base_vtable_inst_id); - base_vtable_id = base_vtable_ptr_inst.vtable_id; - // TODO: Retrieve the specific_id from the base_vtable_ptr_inst here, - // for use in BuildVtable. - } - } - auto vtable_id = - BuildVtable(context, class_id, base_vtable_id, vtable_contents); + auto vtable_id = BuildVtable(context, node_id, class_id, base_class_type, + vtable_contents); auto vptr_type_id = GetPointerType(context, SemIR::VtableType::TypeInstId); // TODO: Handle specifics here, probably passing // `context.generics().GetSelfSpecific(class_info.generic_id)` as the // specific_id here (but more work involved to get this all plumbed in and // tested). + auto generic_id = class_info.generic_id; + auto self_specific_id = context.generics().GetSelfSpecific(generic_id); class_info.vtable_ptr_id = AddInst(context, node_id, {.type_id = vptr_type_id, .vtable_id = vtable_id, - .specific_id = SemIR::SpecificId::None}); + .specific_id = self_specific_id}); } auto struct_type_inst_id = AddTypeInst( diff --git a/toolchain/check/class.h b/toolchain/check/class.h index 40bee7936024..e2e12e38ee15 100644 --- a/toolchain/check/class.h +++ b/toolchain/check/class.h @@ -9,10 +9,6 @@ namespace Carbon::Check { -// If `type_id` is a class type, get its corresponding `SemIR::Class` object. -// Otherwise returns `nullptr`. -auto TryGetAsClass(Context& context, SemIR::TypeId type_id) -> SemIR::Class*; - // Sets the `Self` type for the class. auto SetClassSelfType(Context& context, SemIR::ClassId class_id) -> void; diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index 7e5ae3461a56..4ae99ad7d449 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -589,6 +589,12 @@ static auto ConvertStructToClass( if (!dest_vtable_ptr_inst_id.has_value()) { dest_vtable_ptr_inst_id = dest_class_info.vtable_ptr_id; + if (dest_type.specific_id.has_value() && + dest_vtable_ptr_inst_id.has_value()) { + dest_vtable_ptr_inst_id = context.constant_values().GetInstId( + GetConstantValueInSpecific(context.sem_ir(), dest_type.specific_id, + dest_vtable_ptr_inst_id)); + } } if (dest_vtable_ptr_inst_id.has_value()) { diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index bccd549977cd..d0f6f711c439 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -459,10 +459,10 @@ static auto CheckBaseType(Context& context, Parse::NodeId node_id, return BaseInfo::Error; } - auto* base_class_info = TryGetAsClass(context, base_type_id); + auto class_type = context.types().TryGetAs(base_type_id); // The base must not be a final class. - if (!base_class_info) { + if (!class_type) { // For now, we treat all types that aren't introduced by a `class` // declaration as being final classes. // TODO: Once we have a better idea of which types are considered to be @@ -470,14 +470,17 @@ static auto CheckBaseType(Context& context, Parse::NodeId node_id, DiagnoseBaseIsFinal(context, node_id, base_type_inst_id); return BaseInfo::Error; } - if (base_class_info->inheritance_kind == SemIR::Class::Final) { + + const auto& base_class_info = context.classes().Get(class_type->class_id); + + if (base_class_info.inheritance_kind == SemIR::Class::Final) { DiagnoseBaseIsFinal(context, node_id, base_type_inst_id); } - CARBON_CHECK(base_class_info->scope_id.has_value(), + CARBON_CHECK(base_class_info.scope_id.has_value(), "Complete class should have a scope"); return {.type_id = base_type_id, - .scope_id = base_class_info->scope_id, + .scope_id = base_class_info.scope_id, .inst_id = base_type_inst_id}; } diff --git a/toolchain/check/testdata/class/virtual_modifiers.carbon b/toolchain/check/testdata/class/virtual_modifiers.carbon index 19086b5e3665..79e16435e65f 100644 --- a/toolchain/check/testdata/class/virtual_modifiers.carbon +++ b/toolchain/check/testdata/class/virtual_modifiers.carbon @@ -230,6 +230,22 @@ class Derived { impl fn F[self: Self]() -> T2; } +// --- fail_generic_virtual_decl.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_generic_virtual_decl.carbon:[[@LINE+3]]:1: error: use of undefined generic function [MissingGenericFunctionDefinition] +// CHECK:STDERR: base class Base(T:! type) { +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +base class Base(T:! type) { + // CHECK:STDERR: fail_generic_virtual_decl.carbon:[[@LINE+4]]:3: note: generic function declared here [MissingGenericFunctionDefinitionHere] + // CHECK:STDERR: virtual fn F[self: Self](); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + virtual fn F[self: Self](); +} + + // --- fail_todo_impl_generic_base.carbon library "[[@TEST_NAME]]"; @@ -238,19 +254,19 @@ class T1 { } base class Base(T:! type) { - virtual fn F[self: Self](t: T); + virtual fn F[self: Self](t: T) { } } class Derived { extend base: Base(T1); // CHECK:STDERR: fail_todo_impl_generic_base.carbon:[[@LINE+7]]:25: error: type `` of parameter 1 in redeclaration differs from previous parameter type `` [RedeclParamDiffersType] - // CHECK:STDERR: impl fn F[self: Self](t: T1); + // CHECK:STDERR: impl fn F[self: Self](t: T1) { } // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_todo_impl_generic_base.carbon:[[@LINE-8]]:28: note: previous declaration's corresponding parameter here [RedeclParamPrevious] - // CHECK:STDERR: virtual fn F[self: Self](t: T); + // CHECK:STDERR: virtual fn F[self: Self](t: T) { } // CHECK:STDERR: ^~~~ // CHECK:STDERR: - impl fn F[self: Self](t: T1); + impl fn F[self: Self](t: T1) { } } // --- fail_virtual_without_self.carbon @@ -328,7 +344,7 @@ base class T1(T:! type) { library "[[@TEST_NAME]]"; base class T1(T:! type) { - virtual fn F[self: Self](); + virtual fn F[self: Self]() { } } // --- with_dependent_arg.carbon @@ -336,7 +352,7 @@ base class T1(T:! type) { library "[[@TEST_NAME]]"; base class T1(T:! type) { - virtual fn F[self: Self](t: T); + virtual fn F[self: Self](t: T) { } } // --- vtable_import_unneeded.carbon @@ -347,6 +363,37 @@ import Modifiers; fn F(b: Modifiers.Base); +// --- generic_derived_from_nongeneric.carbon + +library "[[@TEST_NAME]]"; + +base class NonGenericBase { + virtual fn F1[self: Self]() { } + virtual fn F2[self: Self]() { } +} + +base class GenericDerived(T:! type) { + extend base: NonGenericBase; + impl fn F2[self: Self]() { } + virtual fn F3[self: Self]() { } +} + +// --- nongeneric_derived_from_generic.carbon + +library "[[@TEST_NAME]]"; + +base class GenericBase(T:! type) { + virtual fn F1[self: Self]() { } + virtual fn F2[self: Self]() { } +} + +class T1; + +base class NonGenericDerived { + extend base: GenericBase(T1); + impl fn F2[self: Self]() { } + virtual fn F3[self: Self]() { } +} // CHECK:STDOUT: --- modifiers.carbon // CHECK:STDOUT: @@ -1566,7 +1613,7 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @AbstractIntermediate.vtable { -// CHECK:STDOUT: @AbstractBase.%F.decl +// CHECK:STDOUT: constants.%F.6e9 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @Derived.vtable { @@ -1689,7 +1736,7 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @VirtualIntermediate.vtable { -// CHECK:STDOUT: @VirtualBase.%F.decl +// CHECK:STDOUT: constants.%F.3e7 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @Derived.vtable { @@ -1995,6 +2042,100 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: // CHECK:STDOUT: impl fn @F.2(%self.param: %Derived) -> %return.param: %T2; // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_generic_virtual_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %pattern_type.98f: type = pattern_type type [concrete] +// CHECK:STDOUT: %Base.type: type = generic_class_type @Base [concrete] +// CHECK:STDOUT: %Base.generic: %Base.type = struct_value () [concrete] +// CHECK:STDOUT: %Base: type = class_type @Base, @Base(%T) [symbolic] +// CHECK:STDOUT: %pattern_type.9f7: type = pattern_type %Base [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F, @Base(%T) [symbolic] +// CHECK:STDOUT: %F: %F.type = struct_value () [symbolic] +// CHECK:STDOUT: %ptr: type = ptr_type [concrete] +// CHECK:STDOUT: %F.specific_fn: = specific_function %F, @F(%T) [symbolic] +// CHECK:STDOUT: %Base.vtable_ptr: ref %ptr = vtable_ptr @Base.vtable, @Base(%T) [symbolic] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Base = %Base.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Base.decl: %Base.type = class_decl @Base [concrete = constants.%Base.generic] { +// CHECK:STDOUT: %T.patt: %pattern_type.98f = symbolic_binding_pattern T, 0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.loc7_17.1: type = bind_symbolic_name T, 0 [symbolic = %T.loc7_17.2 (constants.%T)] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @Base(%T.loc7_17.1: type) { +// CHECK:STDOUT: %T.loc7_17.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc7_17.2 (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %F.type: type = fn_type @F, @Base(%T.loc7_17.2) [symbolic = %F.type (constants.%F.type)] +// CHECK:STDOUT: %F: @Base.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F)] +// CHECK:STDOUT: %F.specific_fn.loc13_1.2: = specific_function %F, @F(%T.loc7_17.2) [symbolic = %F.specific_fn.loc13_1.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc13_1.2: ref %ptr = vtable_ptr @Base.vtable, @Base(%T.loc7_17.2) [symbolic = %vtable_ptr.loc13_1.2 (constants.%Base.vtable_ptr)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %F.decl: @Base.%F.type (%F.type) = fn_decl @F [symbolic = @Base.%F (constants.%F)] { +// CHECK:STDOUT: %self.patt: @F.%pattern_type (%pattern_type.9f7) = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: @F.%pattern_type (%pattern_type.9f7) = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: @F.%Base (%Base) = value_param call_param0 +// CHECK:STDOUT: %.loc12_22.1: type = splice_block %Self.ref [symbolic = %Base (constants.%Base)] { +// CHECK:STDOUT: %.loc12_22.2: type = specific_constant constants.%Base, @Base(constants.%T) [symbolic = %Base (constants.%Base)] +// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc12_22.2 [symbolic = %Base (constants.%Base)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %self: @F.%Base (%Base) = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.specific_fn.loc13_1.1: = specific_function %F.decl, @F(constants.%T) [symbolic = %F.specific_fn.loc13_1.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc13_1.1: ref %ptr = vtable_ptr @Base.vtable, @Base(constants.%T) [symbolic = %vtable_ptr.loc13_1.2 (constants.%Base.vtable_ptr)] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr} [concrete = constants.%struct_type.vptr] +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: vtable_ptr = %vtable_ptr.loc13_1.1 +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Base +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: vtable @Base.vtable { +// CHECK:STDOUT: @Base.%F.specific_fn.loc13_1.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic virtual fn @F(@Base.%T.loc7_17.1: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %Base: type = class_type @Base, @Base(%T) [symbolic = %Base (constants.%Base)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %Base [symbolic = %pattern_type (constants.%pattern_type.9f7)] +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn(%self.param: @F.%Base (%Base)); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Base(constants.%T) { +// CHECK:STDOUT: %T.loc7_17.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %Base => constants.%Base +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.9f7 +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_impl_generic_base.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -2011,21 +2152,27 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %F.type.f17: type = fn_type @F.1, @Base(%T) [symbolic] // CHECK:STDOUT: %F.e26: %F.type.f17 = struct_value () [symbolic] // CHECK:STDOUT: %ptr.454: type = ptr_type [concrete] -// CHECK:STDOUT: %Base.vtable_ptr: ref %ptr.454 = vtable_ptr @Base.vtable [concrete] +// CHECK:STDOUT: %F.specific_fn.892: = specific_function %F.e26, @F.1(%T) [symbolic] +// CHECK:STDOUT: %Base.vtable_ptr.573: ref %ptr.454 = vtable_ptr @Base.vtable, @Base(%T) [symbolic] // CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete] // CHECK:STDOUT: %complete_type.513: = complete_type_witness %struct_type.vptr [concrete] +// CHECK:STDOUT: %require_complete.97d: = require_complete_type %Base.370 [symbolic] +// CHECK:STDOUT: %require_complete.4ae: = require_complete_type %T [symbolic] // CHECK:STDOUT: %Derived: type = class_type @Derived [concrete] // CHECK:STDOUT: %Base.ea5: type = class_type @Base, @Base(%T1) [concrete] // CHECK:STDOUT: %F.type.d82: type = fn_type @F.1, @Base(%T1) [concrete] // CHECK:STDOUT: %F.d25: %F.type.d82 = struct_value () [concrete] +// CHECK:STDOUT: %pattern_type.3bf: type = pattern_type %Base.ea5 [concrete] +// CHECK:STDOUT: %pattern_type.28b: type = pattern_type %T1 [concrete] +// CHECK:STDOUT: %F.specific_fn.210: = specific_function %F.d25, @F.1(%T1) [concrete] +// CHECK:STDOUT: %Base.vtable_ptr.bfe: ref %ptr.454 = vtable_ptr @Base.vtable, @Base(%T1) [concrete] // CHECK:STDOUT: %Derived.elem: type = unbound_element_type %Derived, %Base.ea5 [concrete] // CHECK:STDOUT: %pattern_type.fb9: type = pattern_type %Derived [concrete] -// CHECK:STDOUT: %pattern_type.28b: type = pattern_type %T1 [concrete] // CHECK:STDOUT: %F.type.5da: type = fn_type @F.2 [concrete] // CHECK:STDOUT: %F.fa3: %F.type.5da = struct_value () [concrete] // CHECK:STDOUT: %Derived.vtable_ptr: ref %ptr.454 = vtable_ptr @Derived.vtable [concrete] -// CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %Base.ea5} [concrete] -// CHECK:STDOUT: %complete_type.65a: = complete_type_witness %struct_type.base [concrete] +// CHECK:STDOUT: %struct_type.base.fda: type = struct_type {.base: %Base.ea5} [concrete] +// CHECK:STDOUT: %complete_type.65a: = complete_type_witness %struct_type.base.fda [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -2067,6 +2214,8 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: !definition: // CHECK:STDOUT: %F.type: type = fn_type @F.1, @Base(%T.loc7_17.2) [symbolic = %F.type (constants.%F.type.f17)] // CHECK:STDOUT: %F: @Base.%F.type (%F.type.f17) = struct_value () [symbolic = %F (constants.%F.e26)] +// CHECK:STDOUT: %F.specific_fn.loc9_1.2: = specific_function %F, @F.1(%T.loc7_17.2) [symbolic = %F.specific_fn.loc9_1.2 (constants.%F.specific_fn.892)] +// CHECK:STDOUT: %vtable_ptr.loc9_1.2: ref %ptr.454 = vtable_ptr @Base.vtable, @Base(%T.loc7_17.2) [symbolic = %vtable_ptr.loc9_1.2 (constants.%Base.vtable_ptr.573)] // CHECK:STDOUT: // CHECK:STDOUT: class { // CHECK:STDOUT: %F.decl: @Base.%F.type (%F.type.f17) = fn_decl @F.1 [symbolic = @Base.%F (constants.%F.e26)] { @@ -2085,11 +2234,12 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %T.ref: type = name_ref T, @Base.%T.loc7_17.1 [symbolic = %T (constants.%T)] // CHECK:STDOUT: %t: @F.1.%T (%T) = bind_name t, %t.param // CHECK:STDOUT: } -// CHECK:STDOUT: %vtable_ptr: ref %ptr.454 = vtable_ptr @Base.vtable [concrete = constants.%Base.vtable_ptr] +// CHECK:STDOUT: %F.specific_fn.loc9_1.1: = specific_function %F.decl, @F.1(constants.%T) [symbolic = %F.specific_fn.loc9_1.2 (constants.%F.specific_fn.892)] +// CHECK:STDOUT: %vtable_ptr.loc9_1.1: ref %ptr.454 = vtable_ptr @Base.vtable, @Base(constants.%T) [symbolic = %vtable_ptr.loc9_1.2 (constants.%Base.vtable_ptr.573)] // CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete = constants.%struct_type.vptr] // CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete = constants.%complete_type.513] // CHECK:STDOUT: complete_type_witness = %complete_type -// CHECK:STDOUT: vtable_ptr = %vtable_ptr +// CHECK:STDOUT: vtable_ptr = %vtable_ptr.loc9_1.1 // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%Base.370 @@ -2118,7 +2268,7 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %t: %T1 = bind_name t, %t.param // CHECK:STDOUT: } // CHECK:STDOUT: %vtable_ptr: ref %ptr.454 = vtable_ptr @Derived.vtable [concrete = constants.%Derived.vtable_ptr] -// CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %Base.ea5} [concrete = constants.%struct_type.base] +// CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %Base.ea5} [concrete = constants.%struct_type.base.fda] // CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.base [concrete = constants.%complete_type.65a] // CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: vtable_ptr = %vtable_ptr @@ -2133,7 +2283,7 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @Base.vtable { -// CHECK:STDOUT: @Base.%F.decl +// CHECK:STDOUT: @Base.%F.specific_fn.loc9_1.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @Derived.vtable { @@ -2146,13 +2296,29 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %pattern_type.loc8_16: type = pattern_type %Base [symbolic = %pattern_type.loc8_16 (constants.%pattern_type.9f7)] // CHECK:STDOUT: %pattern_type.loc8_28: type = pattern_type %T [symbolic = %pattern_type.loc8_28 (constants.%pattern_type.7dc)] // CHECK:STDOUT: -// CHECK:STDOUT: virtual fn(%self.param: @F.1.%Base (%Base.370), %t.param: @F.1.%T (%T)); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete.loc8_20: = require_complete_type %Base [symbolic = %require_complete.loc8_20 (constants.%require_complete.97d)] +// CHECK:STDOUT: %require_complete.loc8_29: = require_complete_type %T [symbolic = %require_complete.loc8_29 (constants.%require_complete.4ae)] +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn(%self.param: @F.1.%Base (%Base.370), %t.param: @F.1.%T (%T)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl fn @F.2(%self.param: %Derived, %t.param: %T1); +// CHECK:STDOUT: impl fn @F.2(%self.param: %Derived, %t.param: %T1) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Base(constants.%T) { // CHECK:STDOUT: %T.loc7_17.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %F.type => constants.%F.type.f17 +// CHECK:STDOUT: %F => constants.%F.e26 +// CHECK:STDOUT: %F.specific_fn.loc9_1.2 => constants.%F.specific_fn.892 +// CHECK:STDOUT: %vtable_ptr.loc9_1.2 => constants.%Base.vtable_ptr.573 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F.1(constants.%T) { @@ -2160,6 +2326,10 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %Base => constants.%Base.370 // CHECK:STDOUT: %pattern_type.loc8_16 => constants.%pattern_type.9f7 // CHECK:STDOUT: %pattern_type.loc8_28 => constants.%pattern_type.7dc +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete.loc8_20 => constants.%require_complete.97d +// CHECK:STDOUT: %require_complete.loc8_29 => constants.%require_complete.4ae // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Base(constants.%T1) { @@ -2168,6 +2338,19 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: !definition: // CHECK:STDOUT: %F.type => constants.%F.type.d82 // CHECK:STDOUT: %F => constants.%F.d25 +// CHECK:STDOUT: %F.specific_fn.loc9_1.2 => constants.%F.specific_fn.210 +// CHECK:STDOUT: %vtable_ptr.loc9_1.2 => constants.%Base.vtable_ptr.bfe +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%T1) { +// CHECK:STDOUT: %T => constants.%T1 +// CHECK:STDOUT: %Base => constants.%Base.ea5 +// CHECK:STDOUT: %pattern_type.loc8_16 => constants.%pattern_type.3bf +// CHECK:STDOUT: %pattern_type.loc8_28 => constants.%pattern_type.28b +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete.loc8_20 => constants.%complete_type.513 +// CHECK:STDOUT: %require_complete.loc8_29 => constants.%complete_type.357 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_virtual_without_self.carbon @@ -2504,10 +2687,12 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %pattern_type.48e: type = pattern_type %T1 [symbolic] // CHECK:STDOUT: %F.type: type = fn_type @F, @T1(%T) [symbolic] // CHECK:STDOUT: %F: %F.type = struct_value () [symbolic] -// CHECK:STDOUT: %ptr: type = ptr_type [concrete] -// CHECK:STDOUT: %T1.vtable_ptr: ref %ptr = vtable_ptr @T1.vtable [concrete] -// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr} [concrete] +// CHECK:STDOUT: %ptr.454: type = ptr_type [concrete] +// CHECK:STDOUT: %F.specific_fn: = specific_function %F, @F(%T) [symbolic] +// CHECK:STDOUT: %T1.vtable_ptr: ref %ptr.454 = vtable_ptr @T1.vtable, @T1(%T) [symbolic] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete] // CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete] +// CHECK:STDOUT: %require_complete: = require_complete_type %T1 [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -2536,6 +2721,8 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: !definition: // CHECK:STDOUT: %F.type: type = fn_type @F, @T1(%T.loc4_15.2) [symbolic = %F.type (constants.%F.type)] // CHECK:STDOUT: %F: @T1.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F)] +// CHECK:STDOUT: %F.specific_fn.loc6_1.2: = specific_function %F, @F(%T.loc4_15.2) [symbolic = %F.specific_fn.loc6_1.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc6_1.2: ref %ptr.454 = vtable_ptr @T1.vtable, @T1(%T.loc4_15.2) [symbolic = %vtable_ptr.loc6_1.2 (constants.%T1.vtable_ptr)] // CHECK:STDOUT: // CHECK:STDOUT: class { // CHECK:STDOUT: %F.decl: @T1.%F.type (%F.type) = fn_decl @F [symbolic = @T1.%F (constants.%F)] { @@ -2549,11 +2736,12 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: } // CHECK:STDOUT: %self: @F.%T1 (%T1) = bind_name self, %self.param // CHECK:STDOUT: } -// CHECK:STDOUT: %vtable_ptr: ref %ptr = vtable_ptr @T1.vtable [concrete = constants.%T1.vtable_ptr] -// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr} [concrete = constants.%struct_type.vptr] +// CHECK:STDOUT: %F.specific_fn.loc6_1.1: = specific_function %F.decl, @F(constants.%T) [symbolic = %F.specific_fn.loc6_1.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc6_1.1: ref %ptr.454 = vtable_ptr @T1.vtable, @T1(constants.%T) [symbolic = %vtable_ptr.loc6_1.2 (constants.%T1.vtable_ptr)] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete = constants.%struct_type.vptr] // CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete = constants.%complete_type] // CHECK:STDOUT: complete_type_witness = %complete_type -// CHECK:STDOUT: vtable_ptr = %vtable_ptr +// CHECK:STDOUT: vtable_ptr = %vtable_ptr.loc6_1.1 // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%T1 @@ -2562,7 +2750,7 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @T1.vtable { -// CHECK:STDOUT: @T1.%F.decl +// CHECK:STDOUT: @T1.%F.specific_fn.loc6_1.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic virtual fn @F(@T1.%T.loc4_15.1: type) { @@ -2570,17 +2758,32 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %T1: type = class_type @T1, @T1(%T) [symbolic = %T1 (constants.%T1)] // CHECK:STDOUT: %pattern_type: type = pattern_type %T1 [symbolic = %pattern_type (constants.%pattern_type.48e)] // CHECK:STDOUT: -// CHECK:STDOUT: virtual fn(%self.param: @F.%T1 (%T1)); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %T1 [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn(%self.param: @F.%T1 (%T1)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @T1(constants.%T) { // CHECK:STDOUT: %T.loc4_15.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %F.type => constants.%F.type +// CHECK:STDOUT: %F => constants.%F +// CHECK:STDOUT: %F.specific_fn.loc6_1.2 => constants.%F.specific_fn +// CHECK:STDOUT: %vtable_ptr.loc6_1.2 => constants.%T1.vtable_ptr // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%T) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: %T1 => constants.%T1 // CHECK:STDOUT: %pattern_type => constants.%pattern_type.48e +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%require_complete // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- with_dependent_arg.carbon @@ -2595,10 +2798,13 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %pattern_type.7dc: type = pattern_type %T [symbolic] // CHECK:STDOUT: %F.type: type = fn_type @F, @T1(%T) [symbolic] // CHECK:STDOUT: %F: %F.type = struct_value () [symbolic] -// CHECK:STDOUT: %ptr: type = ptr_type [concrete] -// CHECK:STDOUT: %T1.vtable_ptr: ref %ptr = vtable_ptr @T1.vtable [concrete] -// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr} [concrete] +// CHECK:STDOUT: %ptr.454: type = ptr_type [concrete] +// CHECK:STDOUT: %F.specific_fn: = specific_function %F, @F(%T) [symbolic] +// CHECK:STDOUT: %T1.vtable_ptr: ref %ptr.454 = vtable_ptr @T1.vtable, @T1(%T) [symbolic] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete] // CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete] +// CHECK:STDOUT: %require_complete.86d: = require_complete_type %T1 [symbolic] +// CHECK:STDOUT: %require_complete.4ae: = require_complete_type %T [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -2627,6 +2833,8 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: !definition: // CHECK:STDOUT: %F.type: type = fn_type @F, @T1(%T.loc4_15.2) [symbolic = %F.type (constants.%F.type)] // CHECK:STDOUT: %F: @T1.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F)] +// CHECK:STDOUT: %F.specific_fn.loc6_1.2: = specific_function %F, @F(%T.loc4_15.2) [symbolic = %F.specific_fn.loc6_1.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc6_1.2: ref %ptr.454 = vtable_ptr @T1.vtable, @T1(%T.loc4_15.2) [symbolic = %vtable_ptr.loc6_1.2 (constants.%T1.vtable_ptr)] // CHECK:STDOUT: // CHECK:STDOUT: class { // CHECK:STDOUT: %F.decl: @T1.%F.type (%F.type) = fn_decl @F [symbolic = @T1.%F (constants.%F)] { @@ -2645,11 +2853,12 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %T.ref: type = name_ref T, @T1.%T.loc4_15.1 [symbolic = %T (constants.%T)] // CHECK:STDOUT: %t: @F.%T (%T) = bind_name t, %t.param // CHECK:STDOUT: } -// CHECK:STDOUT: %vtable_ptr: ref %ptr = vtable_ptr @T1.vtable [concrete = constants.%T1.vtable_ptr] -// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr} [concrete = constants.%struct_type.vptr] +// CHECK:STDOUT: %F.specific_fn.loc6_1.1: = specific_function %F.decl, @F(constants.%T) [symbolic = %F.specific_fn.loc6_1.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc6_1.1: ref %ptr.454 = vtable_ptr @T1.vtable, @T1(constants.%T) [symbolic = %vtable_ptr.loc6_1.2 (constants.%T1.vtable_ptr)] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete = constants.%struct_type.vptr] // CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete = constants.%complete_type] // CHECK:STDOUT: complete_type_witness = %complete_type -// CHECK:STDOUT: vtable_ptr = %vtable_ptr +// CHECK:STDOUT: vtable_ptr = %vtable_ptr.loc6_1.1 // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%T1 @@ -2659,7 +2868,7 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: vtable @T1.vtable { -// CHECK:STDOUT: @T1.%F.decl +// CHECK:STDOUT: @T1.%F.specific_fn.loc6_1.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic virtual fn @F(@T1.%T.loc4_15.1: type) { @@ -2668,11 +2877,24 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %pattern_type.loc5_16: type = pattern_type %T1 [symbolic = %pattern_type.loc5_16 (constants.%pattern_type.48e)] // CHECK:STDOUT: %pattern_type.loc5_28: type = pattern_type %T [symbolic = %pattern_type.loc5_28 (constants.%pattern_type.7dc)] // CHECK:STDOUT: -// CHECK:STDOUT: virtual fn(%self.param: @F.%T1 (%T1), %t.param: @F.%T (%T)); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete.loc5_20: = require_complete_type %T1 [symbolic = %require_complete.loc5_20 (constants.%require_complete.86d)] +// CHECK:STDOUT: %require_complete.loc5_29: = require_complete_type %T [symbolic = %require_complete.loc5_29 (constants.%require_complete.4ae)] +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn(%self.param: @F.%T1 (%T1), %t.param: @F.%T (%T)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @T1(constants.%T) { // CHECK:STDOUT: %T.loc4_15.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %F.type => constants.%F.type +// CHECK:STDOUT: %F => constants.%F +// CHECK:STDOUT: %F.specific_fn.loc6_1.2 => constants.%F.specific_fn +// CHECK:STDOUT: %vtable_ptr.loc6_1.2 => constants.%T1.vtable_ptr // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%T) { @@ -2680,6 +2902,10 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: %T1 => constants.%T1 // CHECK:STDOUT: %pattern_type.loc5_16 => constants.%pattern_type.48e // CHECK:STDOUT: %pattern_type.loc5_28 => constants.%pattern_type.7dc +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete.loc5_20 => constants.%require_complete.86d +// CHECK:STDOUT: %require_complete.loc5_29 => constants.%require_complete.4ae // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- vtable_import_unneeded.carbon @@ -2742,3 +2968,491 @@ fn F(b: Modifiers.Base); // CHECK:STDOUT: // CHECK:STDOUT: fn @F(%b.param: %Base); // CHECK:STDOUT: +// CHECK:STDOUT: --- generic_derived_from_nongeneric.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %NonGenericBase: type = class_type @NonGenericBase [concrete] +// CHECK:STDOUT: %pattern_type.0b8: type = pattern_type %NonGenericBase [concrete] +// CHECK:STDOUT: %F1.type: type = fn_type @F1 [concrete] +// CHECK:STDOUT: %F1: %F1.type = struct_value () [concrete] +// CHECK:STDOUT: %F2.type.809: type = fn_type @F2.1 [concrete] +// CHECK:STDOUT: %F2.053: %F2.type.809 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.454: type = ptr_type [concrete] +// CHECK:STDOUT: %NonGenericBase.vtable_ptr: ref %ptr.454 = vtable_ptr @NonGenericBase.vtable [concrete] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete] +// CHECK:STDOUT: %complete_type.513: = complete_type_witness %struct_type.vptr [concrete] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %pattern_type.98f: type = pattern_type type [concrete] +// CHECK:STDOUT: %GenericDerived.type: type = generic_class_type @GenericDerived [concrete] +// CHECK:STDOUT: %GenericDerived.generic: %GenericDerived.type = struct_value () [concrete] +// CHECK:STDOUT: %GenericDerived: type = class_type @GenericDerived, @GenericDerived(%T) [symbolic] +// CHECK:STDOUT: %GenericDerived.elem: type = unbound_element_type %GenericDerived, %NonGenericBase [symbolic] +// CHECK:STDOUT: %pattern_type.061: type = pattern_type %GenericDerived [symbolic] +// CHECK:STDOUT: %F2.type.e6e: type = fn_type @F2.2, @GenericDerived(%T) [symbolic] +// CHECK:STDOUT: %F2.5da: %F2.type.e6e = struct_value () [symbolic] +// CHECK:STDOUT: %F3.type: type = fn_type @F3, @GenericDerived(%T) [symbolic] +// CHECK:STDOUT: %F3: %F3.type = struct_value () [symbolic] +// CHECK:STDOUT: %F2.specific_fn: = specific_function %F2.5da, @F2.2(%T) [symbolic] +// CHECK:STDOUT: %F3.specific_fn: = specific_function %F3, @F3(%T) [symbolic] +// CHECK:STDOUT: %GenericDerived.vtable_ptr: ref %ptr.454 = vtable_ptr @GenericDerived.vtable, @GenericDerived(%T) [symbolic] +// CHECK:STDOUT: %struct_type.base.432: type = struct_type {.base: %NonGenericBase} [concrete] +// CHECK:STDOUT: %complete_type.099: = complete_type_witness %struct_type.base.432 [concrete] +// CHECK:STDOUT: %require_complete: = require_complete_type %GenericDerived [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .NonGenericBase = %NonGenericBase.decl +// CHECK:STDOUT: .GenericDerived = %GenericDerived.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %NonGenericBase.decl: type = class_decl @NonGenericBase [concrete = constants.%NonGenericBase] {} {} +// CHECK:STDOUT: %GenericDerived.decl: %GenericDerived.type = class_decl @GenericDerived [concrete = constants.%GenericDerived.generic] { +// CHECK:STDOUT: %T.patt: %pattern_type.98f = symbolic_binding_pattern T, 0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.loc9_27.1: type = bind_symbolic_name T, 0 [symbolic = %T.loc9_27.2 (constants.%T)] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @NonGenericBase { +// CHECK:STDOUT: %F1.decl: %F1.type = fn_decl @F1 [concrete = constants.%F1] { +// CHECK:STDOUT: %self.patt: %pattern_type.0b8 = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: %pattern_type.0b8 = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %NonGenericBase = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%NonGenericBase [concrete = constants.%NonGenericBase] +// CHECK:STDOUT: %self: %NonGenericBase = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %F2.decl: %F2.type.809 = fn_decl @F2.1 [concrete = constants.%F2.053] { +// CHECK:STDOUT: %self.patt: %pattern_type.0b8 = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: %pattern_type.0b8 = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %NonGenericBase = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%NonGenericBase [concrete = constants.%NonGenericBase] +// CHECK:STDOUT: %self: %NonGenericBase = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %vtable_ptr: ref %ptr.454 = vtable_ptr @NonGenericBase.vtable [concrete = constants.%NonGenericBase.vtable_ptr] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete = constants.%struct_type.vptr] +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete = constants.%complete_type.513] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: vtable_ptr = %vtable_ptr +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%NonGenericBase +// CHECK:STDOUT: .F1 = %F1.decl +// CHECK:STDOUT: .F2 = %F2.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @GenericDerived(%T.loc9_27.1: type) { +// CHECK:STDOUT: %T.loc9_27.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc9_27.2 (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %GenericDerived: type = class_type @GenericDerived, @GenericDerived(%T.loc9_27.2) [symbolic = %GenericDerived (constants.%GenericDerived)] +// CHECK:STDOUT: %GenericDerived.elem: type = unbound_element_type %GenericDerived, constants.%NonGenericBase [symbolic = %GenericDerived.elem (constants.%GenericDerived.elem)] +// CHECK:STDOUT: %F2.type: type = fn_type @F2.2, @GenericDerived(%T.loc9_27.2) [symbolic = %F2.type (constants.%F2.type.e6e)] +// CHECK:STDOUT: %F2: @GenericDerived.%F2.type (%F2.type.e6e) = struct_value () [symbolic = %F2 (constants.%F2.5da)] +// CHECK:STDOUT: %F3.type: type = fn_type @F3, @GenericDerived(%T.loc9_27.2) [symbolic = %F3.type (constants.%F3.type)] +// CHECK:STDOUT: %F3: @GenericDerived.%F3.type (%F3.type) = struct_value () [symbolic = %F3 (constants.%F3)] +// CHECK:STDOUT: %F2.specific_fn.loc13_1.2: = specific_function %F2, @F2.2(%T.loc9_27.2) [symbolic = %F2.specific_fn.loc13_1.2 (constants.%F2.specific_fn)] +// CHECK:STDOUT: %F3.specific_fn.loc13_1.2: = specific_function %F3, @F3(%T.loc9_27.2) [symbolic = %F3.specific_fn.loc13_1.2 (constants.%F3.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc13_1.2: ref %ptr.454 = vtable_ptr @GenericDerived.vtable, @GenericDerived(%T.loc9_27.2) [symbolic = %vtable_ptr.loc13_1.2 (constants.%GenericDerived.vtable_ptr)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %NonGenericBase.ref: type = name_ref NonGenericBase, file.%NonGenericBase.decl [concrete = constants.%NonGenericBase] +// CHECK:STDOUT: %.loc10: @GenericDerived.%GenericDerived.elem (%GenericDerived.elem) = base_decl %NonGenericBase.ref, element0 [concrete] +// CHECK:STDOUT: %F2.decl: @GenericDerived.%F2.type (%F2.type.e6e) = fn_decl @F2.2 [symbolic = @GenericDerived.%F2 (constants.%F2.5da)] { +// CHECK:STDOUT: %self.patt: @F2.2.%pattern_type (%pattern_type.061) = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: @F2.2.%pattern_type (%pattern_type.061) = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: @F2.2.%GenericDerived (%GenericDerived) = value_param call_param0 +// CHECK:STDOUT: %.loc11_20.1: type = splice_block %Self.ref [symbolic = %GenericDerived (constants.%GenericDerived)] { +// CHECK:STDOUT: %.loc11_20.2: type = specific_constant constants.%GenericDerived, @GenericDerived(constants.%T) [symbolic = %GenericDerived (constants.%GenericDerived)] +// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc11_20.2 [symbolic = %GenericDerived (constants.%GenericDerived)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %self: @F2.2.%GenericDerived (%GenericDerived) = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %F3.decl: @GenericDerived.%F3.type (%F3.type) = fn_decl @F3 [symbolic = @GenericDerived.%F3 (constants.%F3)] { +// CHECK:STDOUT: %self.patt: @F3.%pattern_type (%pattern_type.061) = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: @F3.%pattern_type (%pattern_type.061) = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: @F3.%GenericDerived (%GenericDerived) = value_param call_param0 +// CHECK:STDOUT: %.loc12_23.1: type = splice_block %Self.ref [symbolic = %GenericDerived (constants.%GenericDerived)] { +// CHECK:STDOUT: %.loc12_23.2: type = specific_constant constants.%GenericDerived, @GenericDerived(constants.%T) [symbolic = %GenericDerived (constants.%GenericDerived)] +// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc12_23.2 [symbolic = %GenericDerived (constants.%GenericDerived)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %self: @F3.%GenericDerived (%GenericDerived) = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %F2.specific_fn.loc13_1.1: = specific_function %F2.decl, @F2.2(constants.%T) [symbolic = %F2.specific_fn.loc13_1.2 (constants.%F2.specific_fn)] +// CHECK:STDOUT: %F3.specific_fn.loc13_1.1: = specific_function %F3.decl, @F3(constants.%T) [symbolic = %F3.specific_fn.loc13_1.2 (constants.%F3.specific_fn)] +// CHECK:STDOUT: %vtable_ptr.loc13_1.1: ref %ptr.454 = vtable_ptr @GenericDerived.vtable, @GenericDerived(constants.%T) [symbolic = %vtable_ptr.loc13_1.2 (constants.%GenericDerived.vtable_ptr)] +// CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %NonGenericBase} [concrete = constants.%struct_type.base.432] +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.base [concrete = constants.%complete_type.099] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: vtable_ptr = %vtable_ptr.loc13_1.1 +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%GenericDerived +// CHECK:STDOUT: .NonGenericBase = +// CHECK:STDOUT: .base = %.loc10 +// CHECK:STDOUT: .F2 = %F2.decl +// CHECK:STDOUT: .F3 = %F3.decl +// CHECK:STDOUT: extend %NonGenericBase.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: vtable @NonGenericBase.vtable { +// CHECK:STDOUT: @NonGenericBase.%F1.decl +// CHECK:STDOUT: @NonGenericBase.%F2.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: vtable @GenericDerived.vtable { +// CHECK:STDOUT: constants.%F1 +// CHECK:STDOUT: @GenericDerived.%F2.specific_fn.loc13_1.1 +// CHECK:STDOUT: @GenericDerived.%F3.specific_fn.loc13_1.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn @F1(%self.param: %NonGenericBase) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn @F2.1(%self.param: %NonGenericBase) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic impl fn @F2.2(@GenericDerived.%T.loc9_27.1: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %GenericDerived: type = class_type @GenericDerived, @GenericDerived(%T) [symbolic = %GenericDerived (constants.%GenericDerived)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %GenericDerived [symbolic = %pattern_type (constants.%pattern_type.061)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %GenericDerived [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: impl fn(%self.param: @F2.2.%GenericDerived (%GenericDerived)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic virtual fn @F3(@GenericDerived.%T.loc9_27.1: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %GenericDerived: type = class_type @GenericDerived, @GenericDerived(%T) [symbolic = %GenericDerived (constants.%GenericDerived)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %GenericDerived [symbolic = %pattern_type (constants.%pattern_type.061)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %GenericDerived [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn(%self.param: @F3.%GenericDerived (%GenericDerived)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GenericDerived(constants.%T) { +// CHECK:STDOUT: %T.loc9_27.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %GenericDerived => constants.%GenericDerived +// CHECK:STDOUT: %GenericDerived.elem => constants.%GenericDerived.elem +// CHECK:STDOUT: %F2.type => constants.%F2.type.e6e +// CHECK:STDOUT: %F2 => constants.%F2.5da +// CHECK:STDOUT: %F3.type => constants.%F3.type +// CHECK:STDOUT: %F3 => constants.%F3 +// CHECK:STDOUT: %F2.specific_fn.loc13_1.2 => constants.%F2.specific_fn +// CHECK:STDOUT: %F3.specific_fn.loc13_1.2 => constants.%F3.specific_fn +// CHECK:STDOUT: %vtable_ptr.loc13_1.2 => constants.%GenericDerived.vtable_ptr +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F2.2(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %GenericDerived => constants.%GenericDerived +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.061 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%require_complete +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F3(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %GenericDerived => constants.%GenericDerived +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.061 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%require_complete +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- nongeneric_derived_from_generic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %pattern_type.98f: type = pattern_type type [concrete] +// CHECK:STDOUT: %GenericBase.type: type = generic_class_type @GenericBase [concrete] +// CHECK:STDOUT: %GenericBase.generic: %GenericBase.type = struct_value () [concrete] +// CHECK:STDOUT: %GenericBase.018: type = class_type @GenericBase, @GenericBase(%T) [symbolic] +// CHECK:STDOUT: %pattern_type.34e: type = pattern_type %GenericBase.018 [symbolic] +// CHECK:STDOUT: %F1.type.2af: type = fn_type @F1, @GenericBase(%T) [symbolic] +// CHECK:STDOUT: %F1.80a: %F1.type.2af = struct_value () [symbolic] +// CHECK:STDOUT: %F2.type.2ca: type = fn_type @F2.1, @GenericBase(%T) [symbolic] +// CHECK:STDOUT: %F2.414: %F2.type.2ca = struct_value () [symbolic] +// CHECK:STDOUT: %ptr.454: type = ptr_type [concrete] +// CHECK:STDOUT: %F1.specific_fn.aea: = specific_function %F1.80a, @F1(%T) [symbolic] +// CHECK:STDOUT: %F2.specific_fn.758: = specific_function %F2.414, @F2.1(%T) [symbolic] +// CHECK:STDOUT: %GenericBase.vtable_ptr.e41: ref %ptr.454 = vtable_ptr @GenericBase.vtable, @GenericBase(%T) [symbolic] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete] +// CHECK:STDOUT: %complete_type.513: = complete_type_witness %struct_type.vptr [concrete] +// CHECK:STDOUT: %require_complete: = require_complete_type %GenericBase.018 [symbolic] +// CHECK:STDOUT: %T1: type = class_type @T1 [concrete] +// CHECK:STDOUT: %NonGenericDerived: type = class_type @NonGenericDerived [concrete] +// CHECK:STDOUT: %GenericBase.f84: type = class_type @GenericBase, @GenericBase(%T1) [concrete] +// CHECK:STDOUT: %F1.type.648: type = fn_type @F1, @GenericBase(%T1) [concrete] +// CHECK:STDOUT: %F1.4d3: %F1.type.648 = struct_value () [concrete] +// CHECK:STDOUT: %F2.type.d79: type = fn_type @F2.1, @GenericBase(%T1) [concrete] +// CHECK:STDOUT: %F2.d59: %F2.type.d79 = struct_value () [concrete] +// CHECK:STDOUT: %pattern_type.7a9: type = pattern_type %GenericBase.f84 [concrete] +// CHECK:STDOUT: %F1.specific_fn.094: = specific_function %F1.4d3, @F1(%T1) [concrete] +// CHECK:STDOUT: %F2.specific_fn.b8b: = specific_function %F2.d59, @F2.1(%T1) [concrete] +// CHECK:STDOUT: %GenericBase.vtable_ptr.d41: ref %ptr.454 = vtable_ptr @GenericBase.vtable, @GenericBase(%T1) [concrete] +// CHECK:STDOUT: %NonGenericDerived.elem: type = unbound_element_type %NonGenericDerived, %GenericBase.f84 [concrete] +// CHECK:STDOUT: %pattern_type.5fc: type = pattern_type %NonGenericDerived [concrete] +// CHECK:STDOUT: %F2.type.c10: type = fn_type @F2.2 [concrete] +// CHECK:STDOUT: %F2.deb: %F2.type.c10 = struct_value () [concrete] +// CHECK:STDOUT: %F3.type: type = fn_type @F3 [concrete] +// CHECK:STDOUT: %F3: %F3.type = struct_value () [concrete] +// CHECK:STDOUT: %NonGenericDerived.vtable_ptr: ref %ptr.454 = vtable_ptr @NonGenericDerived.vtable [concrete] +// CHECK:STDOUT: %struct_type.base.29a: type = struct_type {.base: %GenericBase.f84} [concrete] +// CHECK:STDOUT: %complete_type.b6e: = complete_type_witness %struct_type.base.29a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .GenericBase = %GenericBase.decl +// CHECK:STDOUT: .T1 = %T1.decl +// CHECK:STDOUT: .NonGenericDerived = %NonGenericDerived.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %GenericBase.decl: %GenericBase.type = class_decl @GenericBase [concrete = constants.%GenericBase.generic] { +// CHECK:STDOUT: %T.patt: %pattern_type.98f = symbolic_binding_pattern T, 0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.loc4_24.1: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_24.2 (constants.%T)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %T1.decl: type = class_decl @T1 [concrete = constants.%T1] {} {} +// CHECK:STDOUT: %NonGenericDerived.decl: type = class_decl @NonGenericDerived [concrete = constants.%NonGenericDerived] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @GenericBase(%T.loc4_24.1: type) { +// CHECK:STDOUT: %T.loc4_24.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_24.2 (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %F1.type: type = fn_type @F1, @GenericBase(%T.loc4_24.2) [symbolic = %F1.type (constants.%F1.type.2af)] +// CHECK:STDOUT: %F1: @GenericBase.%F1.type (%F1.type.2af) = struct_value () [symbolic = %F1 (constants.%F1.80a)] +// CHECK:STDOUT: %F2.type: type = fn_type @F2.1, @GenericBase(%T.loc4_24.2) [symbolic = %F2.type (constants.%F2.type.2ca)] +// CHECK:STDOUT: %F2: @GenericBase.%F2.type (%F2.type.2ca) = struct_value () [symbolic = %F2 (constants.%F2.414)] +// CHECK:STDOUT: %F1.specific_fn.loc7_1.2: = specific_function %F1, @F1(%T.loc4_24.2) [symbolic = %F1.specific_fn.loc7_1.2 (constants.%F1.specific_fn.aea)] +// CHECK:STDOUT: %F2.specific_fn.loc7_1.2: = specific_function %F2, @F2.1(%T.loc4_24.2) [symbolic = %F2.specific_fn.loc7_1.2 (constants.%F2.specific_fn.758)] +// CHECK:STDOUT: %vtable_ptr.loc7_1.2: ref %ptr.454 = vtable_ptr @GenericBase.vtable, @GenericBase(%T.loc4_24.2) [symbolic = %vtable_ptr.loc7_1.2 (constants.%GenericBase.vtable_ptr.e41)] +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %F1.decl: @GenericBase.%F1.type (%F1.type.2af) = fn_decl @F1 [symbolic = @GenericBase.%F1 (constants.%F1.80a)] { +// CHECK:STDOUT: %self.patt: @F1.%pattern_type (%pattern_type.34e) = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: @F1.%pattern_type (%pattern_type.34e) = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: @F1.%GenericBase (%GenericBase.018) = value_param call_param0 +// CHECK:STDOUT: %.loc5_23.1: type = splice_block %Self.ref [symbolic = %GenericBase (constants.%GenericBase.018)] { +// CHECK:STDOUT: %.loc5_23.2: type = specific_constant constants.%GenericBase.018, @GenericBase(constants.%T) [symbolic = %GenericBase (constants.%GenericBase.018)] +// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc5_23.2 [symbolic = %GenericBase (constants.%GenericBase.018)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %self: @F1.%GenericBase (%GenericBase.018) = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %F2.decl: @GenericBase.%F2.type (%F2.type.2ca) = fn_decl @F2.1 [symbolic = @GenericBase.%F2 (constants.%F2.414)] { +// CHECK:STDOUT: %self.patt: @F2.1.%pattern_type (%pattern_type.34e) = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: @F2.1.%pattern_type (%pattern_type.34e) = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: @F2.1.%GenericBase (%GenericBase.018) = value_param call_param0 +// CHECK:STDOUT: %.loc6_23.1: type = splice_block %Self.ref [symbolic = %GenericBase (constants.%GenericBase.018)] { +// CHECK:STDOUT: %.loc6_23.2: type = specific_constant constants.%GenericBase.018, @GenericBase(constants.%T) [symbolic = %GenericBase (constants.%GenericBase.018)] +// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc6_23.2 [symbolic = %GenericBase (constants.%GenericBase.018)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %self: @F2.1.%GenericBase (%GenericBase.018) = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %F1.specific_fn.loc7_1.1: = specific_function %F1.decl, @F1(constants.%T) [symbolic = %F1.specific_fn.loc7_1.2 (constants.%F1.specific_fn.aea)] +// CHECK:STDOUT: %F2.specific_fn.loc7_1.1: = specific_function %F2.decl, @F2.1(constants.%T) [symbolic = %F2.specific_fn.loc7_1.2 (constants.%F2.specific_fn.758)] +// CHECK:STDOUT: %vtable_ptr.loc7_1.1: ref %ptr.454 = vtable_ptr @GenericBase.vtable, @GenericBase(constants.%T) [symbolic = %vtable_ptr.loc7_1.2 (constants.%GenericBase.vtable_ptr.e41)] +// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.: %ptr.454} [concrete = constants.%struct_type.vptr] +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.vptr [concrete = constants.%complete_type.513] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: vtable_ptr = %vtable_ptr.loc7_1.1 +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%GenericBase.018 +// CHECK:STDOUT: .F1 = %F1.decl +// CHECK:STDOUT: .F2 = %F2.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @T1; +// CHECK:STDOUT: +// CHECK:STDOUT: class @NonGenericDerived { +// CHECK:STDOUT: %GenericBase.ref: %GenericBase.type = name_ref GenericBase, file.%GenericBase.decl [concrete = constants.%GenericBase.generic] +// CHECK:STDOUT: %T1.ref: type = name_ref T1, file.%T1.decl [concrete = constants.%T1] +// CHECK:STDOUT: %GenericBase: type = class_type @GenericBase, @GenericBase(constants.%T1) [concrete = constants.%GenericBase.f84] +// CHECK:STDOUT: %.loc12: %NonGenericDerived.elem = base_decl %GenericBase, element0 [concrete] +// CHECK:STDOUT: %F2.decl: %F2.type.c10 = fn_decl @F2.2 [concrete = constants.%F2.deb] { +// CHECK:STDOUT: %self.patt: %pattern_type.5fc = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: %pattern_type.5fc = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %NonGenericDerived = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%NonGenericDerived [concrete = constants.%NonGenericDerived] +// CHECK:STDOUT: %self: %NonGenericDerived = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %F3.decl: %F3.type = fn_decl @F3 [concrete = constants.%F3] { +// CHECK:STDOUT: %self.patt: %pattern_type.5fc = binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: %pattern_type.5fc = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %NonGenericDerived = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%NonGenericDerived [concrete = constants.%NonGenericDerived] +// CHECK:STDOUT: %self: %NonGenericDerived = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %vtable_ptr: ref %ptr.454 = vtable_ptr @NonGenericDerived.vtable [concrete = constants.%NonGenericDerived.vtable_ptr] +// CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %GenericBase.f84} [concrete = constants.%struct_type.base.29a] +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.base [concrete = constants.%complete_type.b6e] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: vtable_ptr = %vtable_ptr +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%NonGenericDerived +// CHECK:STDOUT: .GenericBase = +// CHECK:STDOUT: .T1 = +// CHECK:STDOUT: .base = %.loc12 +// CHECK:STDOUT: .F2 = %F2.decl +// CHECK:STDOUT: .F3 = %F3.decl +// CHECK:STDOUT: extend %GenericBase +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: vtable @GenericBase.vtable { +// CHECK:STDOUT: @GenericBase.%F1.specific_fn.loc7_1.1 +// CHECK:STDOUT: @GenericBase.%F2.specific_fn.loc7_1.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: vtable @NonGenericDerived.vtable { +// CHECK:STDOUT: constants.%F1.specific_fn.094 +// CHECK:STDOUT: @NonGenericDerived.%F2.decl +// CHECK:STDOUT: @NonGenericDerived.%F3.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic virtual fn @F1(@GenericBase.%T.loc4_24.1: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %GenericBase: type = class_type @GenericBase, @GenericBase(%T) [symbolic = %GenericBase (constants.%GenericBase.018)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %GenericBase [symbolic = %pattern_type (constants.%pattern_type.34e)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %GenericBase [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn(%self.param: @F1.%GenericBase (%GenericBase.018)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic virtual fn @F2.1(@GenericBase.%T.loc4_24.1: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %GenericBase: type = class_type @GenericBase, @GenericBase(%T) [symbolic = %GenericBase (constants.%GenericBase.018)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %GenericBase [symbolic = %pattern_type (constants.%pattern_type.34e)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %GenericBase [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn(%self.param: @F2.1.%GenericBase (%GenericBase.018)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl fn @F2.2(%self.param: %NonGenericDerived) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: virtual fn @F3(%self.param: %NonGenericDerived) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GenericBase(constants.%T) { +// CHECK:STDOUT: %T.loc4_24.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %F1.type => constants.%F1.type.2af +// CHECK:STDOUT: %F1 => constants.%F1.80a +// CHECK:STDOUT: %F2.type => constants.%F2.type.2ca +// CHECK:STDOUT: %F2 => constants.%F2.414 +// CHECK:STDOUT: %F1.specific_fn.loc7_1.2 => constants.%F1.specific_fn.aea +// CHECK:STDOUT: %F2.specific_fn.loc7_1.2 => constants.%F2.specific_fn.758 +// CHECK:STDOUT: %vtable_ptr.loc7_1.2 => constants.%GenericBase.vtable_ptr.e41 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F1(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %GenericBase => constants.%GenericBase.018 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.34e +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%require_complete +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F2.1(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %GenericBase => constants.%GenericBase.018 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.34e +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%require_complete +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GenericBase(constants.%T1) { +// CHECK:STDOUT: %T.loc4_24.2 => constants.%T1 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %F1.type => constants.%F1.type.648 +// CHECK:STDOUT: %F1 => constants.%F1.4d3 +// CHECK:STDOUT: %F2.type => constants.%F2.type.d79 +// CHECK:STDOUT: %F2 => constants.%F2.d59 +// CHECK:STDOUT: %F1.specific_fn.loc7_1.2 => constants.%F1.specific_fn.094 +// CHECK:STDOUT: %F2.specific_fn.loc7_1.2 => constants.%F2.specific_fn.b8b +// CHECK:STDOUT: %vtable_ptr.loc7_1.2 => constants.%GenericBase.vtable_ptr.d41 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F1(constants.%T1) { +// CHECK:STDOUT: %T => constants.%T1 +// CHECK:STDOUT: %GenericBase => constants.%GenericBase.f84 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.7a9 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.513 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F2.1(constants.%T1) { +// CHECK:STDOUT: %T => constants.%T1 +// CHECK:STDOUT: %GenericBase => constants.%GenericBase.f84 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.7a9 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.513 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/lower/constant.cpp b/toolchain/lower/constant.cpp index 97dc35a6e223..55679523d860 100644 --- a/toolchain/lower/constant.cpp +++ b/toolchain/lower/constant.cpp @@ -59,8 +59,9 @@ class ConstantContext { return file_context_->GetFunction(function_id); } - auto GetVtable(SemIR::VtableId vtable_id) -> llvm::GlobalVariable* { - return file_context_->GetVtable(vtable_id); + auto GetVtable(SemIR::VtableId vtable_id, SemIR::SpecificId specific_id) + -> llvm::GlobalVariable* { + return file_context_->GetVtable(vtable_id, specific_id); } // Returns a lowered type for the given type_id. @@ -157,7 +158,7 @@ static auto EmitAsConstant(ConstantContext& context, SemIR::AddrOf inst) static auto EmitAsConstant(ConstantContext& context, SemIR::VtablePtr inst) -> llvm::Constant* { - return context.GetVtable(inst.vtable_id); + return context.GetVtable(inst.vtable_id, inst.specific_id); } static auto EmitAsConstant(ConstantContext& context, diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index c2f9b02db7f4..6af6e75c9d4c 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -54,7 +54,9 @@ FileContext::FileContext(Context& context, const SemIR::File& sem_ir, constants_(LoweredConstantStore::MakeWithExplicitSize( sem_ir.insts().size(), nullptr)), lowered_specifics_(sem_ir.generics(), {}), - coalescer_(vlog_stream_, sem_ir.specifics()) { + coalescer_(vlog_stream_, sem_ir.specifics()), + vtables_(decltype(vtables_)::MakeForOverwrite(sem_ir.vtables())), + specific_vtables_(sem_ir.specifics(), nullptr) { // Initialization that relies on invariants of the class. cpp_code_generator_ = CreateCppCodeGenerator(); CARBON_CHECK(!sem_ir.has_errors(), @@ -84,9 +86,12 @@ auto FileContext::PrepareToLower() -> void { // TODO: Split vtable declaration creation from definition creation to avoid // redundant vtable definitions for imported vtables. - for (const auto& [id, class_info] : sem_ir_->vtables().enumerate()) { - if (auto* vtable = BuildVtable(class_info)) { - vtables_.Insert(id, vtable); + for (const auto& [id, vtable] : sem_ir_->vtables().enumerate()) { + const auto& class_info = sem_ir().classes().Get(vtable.class_id); + // Vtables can't be generated for generics, only for their specifics - and + // must be done lazily based on the use of those specifics. + if (!class_info.generic_id.has_value()) { + vtables_.Set(id, BuildVtable(vtable, SemIR::SpecificId::None)); } } @@ -922,18 +927,13 @@ auto FileContext::GetLocForDI(SemIR::InstId inst_id) -> Context::LocForDI { GetAbsoluteNodeId(sem_ir_, SemIR::LocId(inst_id)).back()); } -auto FileContext::BuildVtable(const SemIR::Vtable& vtable) +auto FileContext::BuildVtable(const SemIR::Vtable& vtable, + SemIR::SpecificId specific_id) -> llvm::GlobalVariable* { const auto& class_info = sem_ir().classes().Get(vtable.class_id); - // Vtables can't be generated for generics, only for their specifics - and - // must be done lazily based on the use of those specifics. - if (class_info.generic_id.has_value()) { - return nullptr; - } - Mangler m(*this); - std::string mangled_name = m.MangleVTable(class_info); + std::string mangled_name = m.MangleVTable(class_info, specific_id); if (sem_ir() .insts() @@ -970,12 +970,12 @@ auto FileContext::BuildVtable(const SemIR::Vtable& vtable) vfuncs.reserve(vtable_inst_block.size()); for (auto fn_decl_id : vtable_inst_block) { - auto fn_decl = GetCalleeFunction(sem_ir(), fn_decl_id); + auto fn_decl = GetCalleeFunction(sem_ir(), fn_decl_id, specific_id); vfuncs.push_back(llvm::ConstantExpr::getTrunc( llvm::ConstantExpr::getSub( llvm::ConstantExpr::getPtrToInt( GetOrCreateFunction(fn_decl.function_id, - SemIR::SpecificId::None), + fn_decl.resolved_specific_id), i64_type), vtable_const_int), i32_type)); diff --git a/toolchain/lower/file_context.h b/toolchain/lower/file_context.h index 11dd7af1a558..aae263ad6744 100644 --- a/toolchain/lower/file_context.h +++ b/toolchain/lower/file_context.h @@ -82,8 +82,17 @@ class FileContext { auto GetConstant(SemIR::ConstantId const_id, SemIR::InstId use_inst_id) -> llvm::Value*; - auto GetVtable(SemIR::VtableId vtable_id) const -> llvm::GlobalVariable* { - return *vtables_[vtable_id]; + auto GetVtable(SemIR::VtableId vtable_id, SemIR::SpecificId specific_id) + -> llvm::GlobalVariable* { + if (!specific_id.has_value()) { + return vtables_.Get(vtable_id); + } + auto*& specific_vtable = specific_vtables_.Get(specific_id); + if (!specific_vtable) { + specific_vtable = + BuildVtable(sem_ir().vtables().Get(vtable_id), specific_id); + } + return specific_vtable; } // Returns the empty LLVM struct type used to represent the type `type`. @@ -184,7 +193,8 @@ class FileContext { // the caller. auto BuildType(SemIR::InstId inst_id) -> llvm::Type*; - auto BuildVtable(const SemIR::Vtable& vtable) -> llvm::GlobalVariable*; + auto BuildVtable(const SemIR::Vtable& vtable, SemIR::SpecificId specific_id) + -> llvm::GlobalVariable*; // Records a specific that was lowered for a generic. These are added one // by one while lowering their definitions. @@ -243,7 +253,9 @@ class FileContext { SpecificCoalescer coalescer_; - Map vtables_; + FixedSizeValueStore vtables_; + FixedSizeValueStore + specific_vtables_; }; } // namespace Carbon::Lower diff --git a/toolchain/lower/function_context.h b/toolchain/lower/function_context.h index a34f69eb6f0a..9becd7b4d207 100644 --- a/toolchain/lower/function_context.h +++ b/toolchain/lower/function_context.h @@ -268,8 +268,9 @@ class FunctionContext { return format_string; } - auto GetVtable(SemIR::VtableId vtable_id) const -> llvm::GlobalVariable* { - return file_context_->GetVtable(vtable_id); + auto GetVtable(SemIR::VtableId vtable_id, SemIR::SpecificId specific_id) const + -> llvm::GlobalVariable* { + return file_context_->GetVtable(vtable_id, specific_id); } private: diff --git a/toolchain/lower/mangler.cpp b/toolchain/lower/mangler.cpp index f1bfbb0d40dc..a466299e49b7 100644 --- a/toolchain/lower/mangler.cpp +++ b/toolchain/lower/mangler.cpp @@ -175,6 +175,13 @@ auto Mangler::Mangle(SemIR::FunctionId function_id, // the mangling. MangleInverseQualifiedNameScope(os, function.parent_scope_id); + MangleSpecificId(os, specific_id); + + return os.TakeStr(); +} + +auto Mangler::MangleSpecificId(llvm::raw_ostream& os, + SemIR::SpecificId specific_id) -> void { // TODO: Add proper support for mangling generic entities. For now we use a // fingerprint of the specific arguments, which should be stable across files, // but isn't necessarily stable across toolchain changes. @@ -186,8 +193,6 @@ auto Mangler::Mangle(SemIR::FunctionId function_id, &sem_ir(), sem_ir().specifics().Get(specific_id).args_id), llvm::HexPrintStyle::Lower, 16); } - - return os.TakeStr(); } auto Mangler::MangleGlobalVariable(SemIR::InstId pattern_id) -> std::string { @@ -215,7 +220,8 @@ auto Mangler::MangleCppClang(const clang::NamedDecl* decl) -> std::string { .str(); } -auto Mangler::MangleVTable(const SemIR::Class& class_info) -> std::string { +auto Mangler::MangleVTable(const SemIR::Class& class_info, + SemIR::SpecificId specific_id) -> std::string { RawStringOstream os; os << "_C"; @@ -226,6 +232,8 @@ auto Mangler::MangleVTable(const SemIR::Class& class_info) -> std::string { os << ".$vtable"; + MangleSpecificId(os, specific_id); + return os.TakeStr(); } diff --git a/toolchain/lower/mangler.h b/toolchain/lower/mangler.h index f4720b6df121..c2932dfecc79 100644 --- a/toolchain/lower/mangler.h +++ b/toolchain/lower/mangler.h @@ -37,12 +37,17 @@ class Mangler { // Produce a deterministically unique mangled name for the specified class's // vtable. - auto MangleVTable(const SemIR::Class& class_info) -> std::string; + auto MangleVTable(const SemIR::Class& class_info, + SemIR::SpecificId specific_id) -> std::string; private: // Mangle this `NameId` as an individual name component. auto MangleNameId(llvm::raw_ostream& os, SemIR::NameId name_id) -> void; + // Mangle this `SpecificId`, or nothing if it is `SpecificId::None`. + auto MangleSpecificId(llvm::raw_ostream& os, SemIR::SpecificId specific_id) + -> void; + // Mangle this qualified name with inner scope first, working outwards. This // may reduce the incidence of common prefixes in the name mangling. (i.e.: // every standard library name won't have a common prefix that has to be diff --git a/toolchain/lower/testdata/class/virtual.carbon b/toolchain/lower/testdata/class/virtual.carbon index 4acd5f76e60a..43eac2e515a4 100644 --- a/toolchain/lower/testdata/class/virtual.carbon +++ b/toolchain/lower/testdata/class/virtual.carbon @@ -112,7 +112,45 @@ fn Use() { library "[[@TEST_NAME]]"; base class Base(T:! type) { - virtual fn F[self: Self](); + virtual fn F[self: Self]() { } +} + +// --- generic_use.carbon + +library "[[@TEST_NAME]]"; + +base class Base(T:! type) { + virtual fn F[self: Self]() { + var v: T; + } +} + +class T1 { } +class T2 { + var v: T1; +} + +fn F() { + var t1: Base(T1) = {}; + var t2: Base(T2) = {}; +} + +// --- generic_base.carbon + +library "[[@TEST_NAME]]"; + +base class Base(T:! type) { + virtual fn F[self: Self]() { } +} + +class T1; + +class Derived { + extend base: Base(T1); +} + +fn Make() { + var v: Derived; } // CHECK:STDOUT: ; ModuleID = 'classes.carbon' @@ -425,3 +463,109 @@ base class Base(T:! type) { // CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} // CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) // CHECK:STDOUT: !3 = !DIFile(filename: "generic_noop.carbon", directory: "") +// CHECK:STDOUT: ; ModuleID = 'generic_use.carbon' +// CHECK:STDOUT: source_filename = "generic_use.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: @"_CBase.Main.$vtable.4d2ffa01ebfb7a1d" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CF.Base.Main.4d2ffa01ebfb7a1d to i64), i64 ptrtoint (ptr @"_CBase.Main.$vtable.4d2ffa01ebfb7a1d" to i64)) to i32)] +// CHECK:STDOUT: @"_CBase.Main.$vtable.4f4310253a4de9ab" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CF.Base.Main.4f4310253a4de9ab to i64), i64 ptrtoint (ptr @"_CBase.Main.$vtable.4f4310253a4de9ab" to i64)) to i32)] +// CHECK:STDOUT: @Base.val.20a.loc16_3 = internal constant { ptr } { ptr @"_CBase.Main.$vtable.4d2ffa01ebfb7a1d" } +// CHECK:STDOUT: @Base.val.f56.loc17_3 = internal constant { ptr } { ptr @"_CBase.Main.$vtable.4f4310253a4de9ab" } +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CF.Main() !dbg !4 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %t1.var = alloca { ptr }, align 8, !dbg !7 +// CHECK:STDOUT: %t2.var = alloca { ptr }, align 8, !dbg !8 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %t1.var), !dbg !7 +// CHECK:STDOUT: %.loc16_23.2.vptr = getelementptr inbounds nuw { ptr }, ptr %t1.var, i32 0, i32 0, !dbg !9 +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %t1.var, ptr align 8 @Base.val.20a.loc16_3, i64 8, i1 false), !dbg !7 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %t2.var), !dbg !8 +// CHECK:STDOUT: %.loc17_23.2.vptr = getelementptr inbounds nuw { ptr }, ptr %t2.var, i32 0, i32 0, !dbg !10 +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %t2.var, ptr align 8 @Base.val.f56.loc17_3, i64 8, i1 false), !dbg !8 +// CHECK:STDOUT: ret void, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define linkonce_odr void @_CF.Base.Main.4d2ffa01ebfb7a1d(ptr %self) !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %v.var = alloca {}, align 8, !dbg !13 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 0, ptr %v.var), !dbg !13 +// CHECK:STDOUT: ret void, !dbg !14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define linkonce_odr void @_CF.Base.Main.4f4310253a4de9ab(ptr %self) !dbg !15 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %v.var = alloca { {} }, align 8, !dbg !16 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 0, ptr %v.var), !dbg !16 +// CHECK:STDOUT: ret void, !dbg !17 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1 +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 3, 2, 1, 0 } +// CHECK:STDOUT: uselistorder ptr @llvm.memcpy.p0.p0.i64, { 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} +// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !3 = !DIFile(filename: "generic_use.carbon", directory: "") +// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main", scope: null, file: !3, line: 15, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !6 = !{} +// CHECK:STDOUT: !7 = !DILocation(line: 16, column: 3, scope: !4) +// CHECK:STDOUT: !8 = !DILocation(line: 17, column: 3, scope: !4) +// CHECK:STDOUT: !9 = !DILocation(line: 16, column: 22, scope: !4) +// CHECK:STDOUT: !10 = !DILocation(line: 17, column: 22, scope: !4) +// CHECK:STDOUT: !11 = !DILocation(line: 15, column: 1, scope: !4) +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "F", linkageName: "_CF.Base.Main.4d2ffa01ebfb7a1d", scope: null, file: !3, line: 5, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !13 = !DILocation(line: 6, column: 5, scope: !12) +// CHECK:STDOUT: !14 = !DILocation(line: 5, column: 3, scope: !12) +// CHECK:STDOUT: !15 = distinct !DISubprogram(name: "F", linkageName: "_CF.Base.Main.4f4310253a4de9ab", scope: null, file: !3, line: 5, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !16 = !DILocation(line: 6, column: 5, scope: !15) +// CHECK:STDOUT: !17 = !DILocation(line: 5, column: 3, scope: !15) +// CHECK:STDOUT: ; ModuleID = 'generic_base.carbon' +// CHECK:STDOUT: source_filename = "generic_base.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: @"_CDerived.Main.$vtable" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CF.Base.Main.4d2ffa01ebfb7a1d to i64), i64 ptrtoint (ptr @"_CDerived.Main.$vtable" to i64)) to i32)] +// CHECK:STDOUT: @"_CBase.Main.$vtable.4d2ffa01ebfb7a1d" = unnamed_addr constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @_CF.Base.Main.4d2ffa01ebfb7a1d to i64), i64 ptrtoint (ptr @"_CBase.Main.$vtable.4d2ffa01ebfb7a1d" to i64)) to i32)] +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CMake.Main() !dbg !4 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %v.var = alloca { { ptr } }, align 8, !dbg !7 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %v.var), !dbg !7 +// CHECK:STDOUT: ret void, !dbg !8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define linkonce_odr void @_CF.Base.Main.4d2ffa01ebfb7a1d(ptr %self) !dbg !9 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !10 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0 +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} +// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !3 = !DIFile(filename: "generic_base.carbon", directory: "") +// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Make", linkageName: "_CMake.Main", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !6 = !{} +// CHECK:STDOUT: !7 = !DILocation(line: 15, column: 3, scope: !4) +// CHECK:STDOUT: !8 = !DILocation(line: 14, column: 1, scope: !4) +// CHECK:STDOUT: !9 = distinct !DISubprogram(name: "F", linkageName: "_CF.Base.Main.4d2ffa01ebfb7a1d", scope: null, file: !3, line: 5, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !10 = !DILocation(line: 5, column: 3, scope: !9)