mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
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:
@@ -594,4 +594,83 @@ auto GetOrAddImpl(Context& context, SemIR::LocId loc_id,
|
||||
return impl_id;
|
||||
}
|
||||
|
||||
auto BuildCustomWitness(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::CustomWitness>(
|
||||
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();
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
Reference in New Issue
Block a user