Forward impl declarations of incomplete facet types (#5219)

Implements some of the changes from proposal #5168.

* The data structure for complete facet types has been repurposed for
identified facet types. Identified facet types are now a concept in the
toolchain, but without named constraint support they are not
substantially different from incomplete facet types.
* Identified facet types keep the list of required specific interfaces
in sorted order, for efficiency improvements in impl lookup. Found
another way to identify the interface to impl (or number of impls if not
1).
* Forward `impl` declarations of identified but incomplete facet types
are allowed unless the facet type has rewrites. An incomplete facet type
with rewrites is already either an error or has more than one interface
and so can't be implemented, so this case can't be exercised very well
yet.
* Forward `impl` declarations of interface without rewrites use a
placeholder inst block for the witness.
* Changed some machinery to use RequireIdentifiedFacetType to access the
interfaces of the facet type so we only need to add support for
expanding named constraints into interfaces in one place.

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Co-authored-by: Dana Jansens <danakj@orodu.net>
This commit is contained in:
josh11b
2025-04-02 01:46:27 +00:00
committed by GitHub
co-authored by Josh L Dana Jansens
parent 265968b396
commit bc439ad092
32 changed files with 2921 additions and 351 deletions
+22 -6
View File
@@ -84,10 +84,9 @@ static auto CheckAssociatedFunctionImplementation(
return impl_decl_id;
}
// Builds an initial empty witness.
// TODO: Fill the witness with the rewrites from the declaration.
auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl)
-> SemIR::InstId {
// Builds an initial witness from the rewrites in the facet type, if any.
auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl,
bool is_definition) -> SemIR::InstId {
CARBON_CHECK(!impl.has_definition_started());
auto self_type_id = context.types().GetTypeIdForTypeInstId(impl.self_id);
@@ -96,10 +95,10 @@ auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl)
return SemIR::ErrorInst::SingletonInstId;
}
return ResolveFacetTypeImplWitness(
return InitialFacetTypeImplWitness(
context, context.insts().GetLocId(impl.latest_decl_id()),
impl.constraint_id, impl.self_id, impl.interface,
context.generics().GetSelfSpecific(impl.generic_id));
context.generics().GetSelfSpecific(impl.generic_id), is_definition);
}
auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
@@ -110,6 +109,23 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
}
auto witness = context.insts().GetAs<SemIR::ImplWitness>(impl.witness_id);
auto witness_block = context.inst_blocks().GetMutable(witness.elements_id);
// `witness.elements_id` will be `SemIR::InstBlockId::Empty` when the
// definition is the first declaration and the interface has no members. The
// other case where `witness_block` will be empty is when we are using a
// placeholder witness. This happens when there is a forward declaration of
// the impl and the facet type has no rewrite constraints and so it wasn't
// required to be complete.
if (witness.elements_id != SemIR::InstBlockId::Empty &&
witness_block.empty()) {
if (!RequireCompleteFacetTypeForImplDefinition(
context, impl.latest_decl_id(), impl.constraint_id)) {
return;
}
AllocateFacetTypeImplWitness(context, impl.interface.interface_id,
witness.elements_id);
witness_block = context.inst_blocks().GetMutable(witness.elements_id);
}
const auto& interface = context.interfaces().Get(impl.interface.interface_id);
auto assoc_entities =
context.inst_blocks().Get(interface.associated_entities_id);