Vtable support for generics (#5793)

Some specific features:

* Use `SpecificFunction` for vtable entries for generic classes.
* Create specific constants for vtable entries in classes derived from
  generic classes to reference the appropriate specific of the function
  in the context of such a derived class.
* Create specific constants for vtable_ptrs for uses of specific generic
  classes.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
David Blaikie
2025-07-11 22:29:10 +00:00
committed by GitHub
co-authored by Richard Smith
parent 8cd1307711
commit 27be0973e7
12 changed files with 1044 additions and 123 deletions
+83 -52
View File
@@ -14,14 +14,6 @@
namespace Carbon::Check {
auto TryGetAsClass(Context& context, SemIR::TypeId type_id) -> SemIR::Class* {
auto class_type = context.types().TryGetAs<SemIR::ClassType>(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<SemIR::ClassType> base_class_type,
llvm::ArrayRef<SemIR::InstId> 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<SemIR::VtablePtr>(
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<SemIR::FunctionDecl>(fn_decl_id);
const auto& function = context.functions().Get(fn_decl.function_id);
return GetOrAddInst<SemIR::SpecificFunction>(
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<SemIR::InstId> 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<SemIR::FunctionDecl>(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<SemIR::FunctionDecl>(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<SemIR::FunctionDecl>(*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<SemIR::ClassType> 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<SemIR::ClassType>(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<SemIR::VtablePtr>(
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<SemIR::VtablePtr>(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<SemIR::StructType>(
-4
View File
@@ -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;
+6
View File
@@ -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()) {
+8 -5
View File
@@ -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<SemIR::ClassType>(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};
}
+748 -34
View File
@@ -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 `<pattern for T1>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for T>` [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 <vtable> [concrete]
// CHECK:STDOUT: %F.specific_fn: <specific function> = 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 {.<vptr>: %ptr} [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %struct_type.vptr [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = 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> = 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> = 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> = 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 {.<vptr>: %ptr} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %complete_type: <witness> = 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 <vtable> [concrete]
// CHECK:STDOUT: %Base.vtable_ptr: ref %ptr.454 = vtable_ptr @Base.vtable [concrete]
// CHECK:STDOUT: %F.specific_fn.892: <specific function> = 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 {.<vptr>: %ptr.454} [concrete]
// CHECK:STDOUT: %complete_type.513: <witness> = complete_type_witness %struct_type.vptr [concrete]
// CHECK:STDOUT: %require_complete.97d: <witness> = require_complete_type %Base.370 [symbolic]
// CHECK:STDOUT: %require_complete.4ae: <witness> = 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> = 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: <witness> = 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: <witness> = 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> = 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> = 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 {.<vptr>: %ptr.454} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %complete_type: <witness> = 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: <witness> = 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: <witness> = require_complete_type %Base [symbolic = %require_complete.loc8_20 (constants.%require_complete.97d)]
// CHECK:STDOUT: %require_complete.loc8_29: <witness> = 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 <vtable> [concrete]
// CHECK:STDOUT: %T1.vtable_ptr: ref %ptr = vtable_ptr @T1.vtable [concrete]
// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.<vptr>: %ptr} [concrete]
// CHECK:STDOUT: %ptr.454: type = ptr_type <vtable> [concrete]
// CHECK:STDOUT: %F.specific_fn: <specific function> = 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 {.<vptr>: %ptr.454} [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %struct_type.vptr [concrete]
// CHECK:STDOUT: %require_complete: <witness> = 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> = 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 {.<vptr>: %ptr} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %F.specific_fn.loc6_1.1: <specific function> = 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 {.<vptr>: %ptr.454} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %complete_type: <witness> = 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: <witness> = 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 <vtable> [concrete]
// CHECK:STDOUT: %T1.vtable_ptr: ref %ptr = vtable_ptr @T1.vtable [concrete]
// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.<vptr>: %ptr} [concrete]
// CHECK:STDOUT: %ptr.454: type = ptr_type <vtable> [concrete]
// CHECK:STDOUT: %F.specific_fn: <specific function> = 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 {.<vptr>: %ptr.454} [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %struct_type.vptr [concrete]
// CHECK:STDOUT: %require_complete.86d: <witness> = require_complete_type %T1 [symbolic]
// CHECK:STDOUT: %require_complete.4ae: <witness> = 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> = 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 {.<vptr>: %ptr} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %F.specific_fn.loc6_1.1: <specific function> = 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 {.<vptr>: %ptr.454} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %complete_type: <witness> = 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: <witness> = require_complete_type %T1 [symbolic = %require_complete.loc5_20 (constants.%require_complete.86d)]
// CHECK:STDOUT: %require_complete.loc5_29: <witness> = 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 <vtable> [concrete]
// CHECK:STDOUT: %NonGenericBase.vtable_ptr: ref %ptr.454 = vtable_ptr @NonGenericBase.vtable [concrete]
// CHECK:STDOUT: %struct_type.vptr: type = struct_type {.<vptr>: %ptr.454} [concrete]
// CHECK:STDOUT: %complete_type.513: <witness> = 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> = specific_function %F2.5da, @F2.2(%T) [symbolic]
// CHECK:STDOUT: %F3.specific_fn: <specific function> = 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: <witness> = complete_type_witness %struct_type.base.432 [concrete]
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type %GenericDerived [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = 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> = 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 {.<vptr>: %ptr.454} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %complete_type: <witness> = 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> = 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> = 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> = 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> = 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: <witness> = 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 = <poisoned>
// 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: <witness> = 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: <witness> = 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 <vtable> [concrete]
// CHECK:STDOUT: %F1.specific_fn.aea: <specific function> = specific_function %F1.80a, @F1(%T) [symbolic]
// CHECK:STDOUT: %F2.specific_fn.758: <specific function> = 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 {.<vptr>: %ptr.454} [concrete]
// CHECK:STDOUT: %complete_type.513: <witness> = complete_type_witness %struct_type.vptr [concrete]
// CHECK:STDOUT: %require_complete: <witness> = 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> = specific_function %F1.4d3, @F1(%T1) [concrete]
// CHECK:STDOUT: %F2.specific_fn.b8b: <specific function> = 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: <witness> = complete_type_witness %struct_type.base.29a [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = 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> = 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> = 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> = 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> = 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> = 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 {.<vptr>: %ptr.454} [concrete = constants.%struct_type.vptr]
// CHECK:STDOUT: %complete_type: <witness> = 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: <witness> = 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 = <poisoned>
// CHECK:STDOUT: .T1 = <poisoned>
// 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: <witness> = 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: <witness> = 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:
+4 -3
View File
@@ -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,
+14 -14
View File
@@ -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));
+16 -4
View File
@@ -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<SemIR::VtableId, llvm::GlobalVariable*> vtables_;
FixedSizeValueStore<SemIR::VtableId, llvm::GlobalVariable*> vtables_;
FixedSizeValueStore<SemIR::SpecificId, llvm::GlobalVariable*>
specific_vtables_;
};
} // namespace Carbon::Lower
+3 -2
View File
@@ -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:
+11 -3
View File
@@ -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();
}
+6 -1
View File
@@ -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
+145 -1
View File
@@ -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)