Add Destroy.SubobjectDestroy as a temporary replacement for Destroy.Op (#7773)

This change partially implements [PR #7362], which revises how objects
are destroyed. It is a partial implementation for two reasons:

1. This change moves `Destroy.Op`'s current behaviour into
`Destroy.SubobjectDestroy`, but it doesn't add support for objects with
non-trivial destruction.
2. `Destroy.SubobjectDestroy` is a workaround for `require impls
SubobjectDestroy`. We aren't able to use the latter until the dependents
add their requirements' implementations to their own witness tables.

[PR #7362]: https://github.com/carbon-language/carbon-lang/pulls/7362
This commit is contained in:
Christopher Di Bella
2026-09-24 00:06:28 +00:00
committed by GitHub
parent 03939a9223
commit f7cd39428e
309 changed files with 51760 additions and 15269 deletions
+119 -1
View File
@@ -40,6 +40,92 @@ auto HandleParseNode(Context& context, Parse::InterfaceIntroducerId node_id)
return true;
}
static auto ValidateCoreInterfaceAssociatedFunction(
Context& context, SemIR::InstId decl_id, int index, CoreIdentifier name_id,
SemIR::Function::InterfaceModifier interface_modifier =
SemIR::Function::InterfaceModifier::None) -> bool {
auto loc_id = context.insts().GetCanonicalLocId(decl_id);
auto decl = context.insts().TryGetAs<SemIR::FunctionDecl>(decl_id);
if (!decl) {
context.TODO(loc_id, "associated entity must be a method");
return false;
}
auto fn = context.functions().Get(decl->function_id);
if (fn.name_id != context.core_identifiers().AddNameId(name_id)) {
context.TODO(loc_id,
llvm::formatv("associated function #{} must be named `{}`",
index, name_id));
return false;
}
auto call_params = context.inst_blocks().Get(fn.call_param_patterns_id);
// TODO: extend to support arbitrary parameters.
if (call_params.size() != 1) {
context.TODO(loc_id, "associated function must have exactly 1 parameter");
return false;
}
auto self = context.insts().TryGetAs<SemIR::RefParamPattern>(call_params[0]);
if (!self.has_value() || self->pretty_name_id != SemIR::NameId::SelfValue) {
context.TODO(loc_id,
"associated function must take `ref self` as its parameter");
return false;
}
// TODO: extend to support arbitrary return types.
if (fn.return_type_inst_id.has_value()) {
context.TODO(loc_id, "associated function must not have a return type");
return false;
}
if (fn.interface_modifier != interface_modifier) {
context.TODO(
loc_id,
interface_modifier == SemIR::Function::InterfaceModifier::None
? std::string(
"associated function must not have an interface modifier")
: llvm::formatv("associated function must be `{}`",
interface_modifier));
return false;
}
return true;
}
static auto ValidateCoreDestroy(Context& context, SemIR::LocId loc_id,
SemIR::InstBlockId associated_entities_id)
-> bool {
auto assoc_entities = context.inst_blocks().Get(associated_entities_id);
if (assoc_entities.size() != 3) {
context.TODO(
loc_id,
"interface `Core.Destroy` needs exactly 3 associated functions");
return false;
}
if (!ValidateCoreInterfaceAssociatedFunction(context, assoc_entities[0], 1,
CoreIdentifier::Op)) {
return false;
}
if (!ValidateCoreInterfaceAssociatedFunction(
context, assoc_entities[1], 2, CoreIdentifier::SubobjectDestroy,
SemIR::Function::InterfaceModifier::Final)) {
return false;
}
if (!ValidateCoreInterfaceAssociatedFunction(
context, assoc_entities[2], 3, CoreIdentifier::SelfDestruct,
SemIR::Function::InterfaceModifier::Final)) {
return false;
}
return true;
}
static auto BuildInterfaceDecl(Context& context,
Parse::AnyInterfaceDeclId node_id,
bool is_definition)
@@ -218,7 +304,7 @@ auto HandleParseNode(Context& context,
return true;
}
auto HandleParseNode(Context& context, Parse::InterfaceDefinitionId /*node_id*/)
auto HandleParseNode(Context& context, Parse::InterfaceDefinitionId node_id)
-> bool {
auto interface_id =
context.node_stack().Pop<Parse::NodeKind::InterfaceDefinitionStart>();
@@ -251,6 +337,38 @@ auto HandleParseNode(Context& context, Parse::InterfaceDefinitionId /*node_id*/)
// Finish the definition of interface-without-self.
FinishGenericDefinition(context, interface_info.generic_id);
if (context.sem_ir().package_id() == PackageNameId::Core) {
switch (interface_info.core_interface) {
case SemIR::CoreInterface::Destroy:
return ValidateCoreDestroy(context, node_id,
interface_info.associated_entities_id);
case SemIR::CoreInterface::AddAssignWith:
case SemIR::CoreInterface::AddWith:
case SemIR::CoreInterface::Copy:
case SemIR::CoreInterface::CppRangeForIterate:
case SemIR::CoreInterface::CppUnsafeDeref:
case SemIR::CoreInterface::Dec:
case SemIR::CoreInterface::Default:
case SemIR::CoreInterface::FloatFitsIn:
case SemIR::CoreInterface::DivAssignWith:
case SemIR::CoreInterface::DivWith:
case SemIR::CoreInterface::EqWith:
case SemIR::CoreInterface::Inc:
case SemIR::CoreInterface::IntFitsIn:
case SemIR::CoreInterface::ModAssignWith:
case SemIR::CoreInterface::ModWith:
case SemIR::CoreInterface::MulAssignWith:
case SemIR::CoreInterface::MulWith:
case SemIR::CoreInterface::Negate:
case SemIR::CoreInterface::OrderedWith:
case SemIR::CoreInterface::SubAssignWith:
case SemIR::CoreInterface::SubWith:
case SemIR::CoreInterface::Unknown:
// TODO: validate other core interfaces
return true;
}
}
// The decl_name_stack and scopes are popped by `ProcessNodeIds`.
return true;
}