Refactor CppWitness as CustomWitness (#6491)

This is in anticipation of using the same construct for all
implementations of `Destroy`, as well as other similar use-cases with
language-defined interfaces.
This commit is contained in:
Jon Ross-Perkins
2025-12-15 19:41:14 +00:00
committed by GitHub
parent 6b28213b36
commit 25f63140e6
8 changed files with 271 additions and 261 deletions
+2 -84
View File
@@ -46,88 +46,6 @@ static auto TypeAsClassDecl(Context& context, SemIR::TypeId type_id)
context.clang_decls().Get(decl_id).key.decl);
}
// Builds a witness that the given type implements the given interface,
// populating it with the specified set of values. Returns a corresponding
// lookup result. Produces a diagnostic and returns `None` if the specified
// values aren't suitable for the interface.
static auto BuildWitness(Context& context, SemIR::LocId loc_id,
SemIR::TypeId self_type_id,
SemIR::SpecificInterface specific_interface,
llvm::ArrayRef<SemIR::InstId> values)
-> SemIR::InstId {
const auto& interface =
context.interfaces().Get(specific_interface.interface_id);
auto assoc_entities =
context.inst_blocks().GetOrEmpty(interface.associated_entities_id);
if (assoc_entities.size() != values.size()) {
context.TODO(loc_id, ("Unsupported definition of interface " +
context.names().GetFormatted(interface.name_id))
.str());
return SemIR::ErrorInst::InstId;
}
llvm::SmallVector<SemIR::InstId> entries;
// Build a witness with the current contents of the witness table. This will
// grow as we progress through the impl. In theory this will build O(n^2)
// table entries, but in practice n <= 2, so that's OK.
//
// This is necessary because later associated entities may refer to earlier
// associated entities in their signatures. In particular, an associated
// result type may be used as the return type of an associated function.
//
// TODO: Consider building one witness after all associated constants, and
// then a second after all associated functions, rather than building one at
// each step. For now this doesn't really matter since we don't have more than
// one of each anyway.
auto make_witness = [&] {
return context.constant_values().GetInstId(EvalOrAddInst<SemIR::CppWitness>(
context, loc_id,
{.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
.elements_id = context.inst_blocks().Add(entries)}));
};
// Fill in the witness table.
for (const auto& [assoc_entity_id, value_id] :
llvm::zip_equal(assoc_entities, values)) {
LoadImportRef(context, assoc_entity_id);
auto decl_id =
context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
context.sem_ir(), specific_interface.specific_id, assoc_entity_id));
CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
auto decl = context.insts().Get(decl_id);
CARBON_KIND_SWITCH(decl) {
case CARBON_KIND(SemIR::StructValue struct_value): {
if (struct_value.type_id == SemIR::ErrorInst::TypeId) {
return SemIR::ErrorInst::InstId;
}
// TODO: If a thunk is needed, this will build a different value each
// time it's called, so we won't properly deduplicate repeated
// witnesses.
// TODO: Skip calling make_witness if this function signature doesn't
// involve `Self`.
entries.push_back(CheckAssociatedFunctionImplementation(
context,
context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
value_id, self_type_id, make_witness(),
/*defer_thunk_definition=*/false));
break;
}
case SemIR::AssociatedConstantDecl::Kind: {
context.TODO(loc_id,
"Associated constant in interface with synthesized impl");
return SemIR::ErrorInst::InstId;
}
default:
CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
"Unexpected kind of associated entity {0}", decl);
return SemIR::ErrorInst::InstId;
}
}
return make_witness();
}
static auto BuildSingleFunctionWitness(
Context& context, SemIR::LocId loc_id, clang::FunctionDecl* cpp_fn,
clang::DeclAccessPair found_decl, int num_params,
@@ -144,8 +62,8 @@ static auto BuildSingleFunctionWitness(
CARBON_CHECK(fn_id == SemIR::ErrorInst::InstId);
return SemIR::ErrorInst::InstId;
}
return BuildWitness(context, loc_id, self_type_id, specific_interface,
{fn_id});
return BuildCustomWitness(context, loc_id, self_type_id, specific_interface,
{fn_id});
}
static auto LookupCopyImpl(Context& context, SemIR::LocId loc_id,