Support impl lookup for multiple interfaces in a facet type (#5047)

If the query facet type has more than one interface, we must find an
impl that provides that interface for the query type for each interface.
This just looks like a for loop over the interfaces and ensuring we
found one impl witness for every one.

However the impl matching must change since it can't look at the
constant value of the entire query facet type for comparison with the
impl, as that query facet type may be for multiple interfaces and we are
looking to match an impl of a single interface.

To do this we break the query facet type up into each interface and make
sure the interface ids match. Then ensure that the impl was able to
deduce any generic parameters using the specific of the single query
interface.

There are some TODOs left here:

1. If the facet type for the query or the impl constraint has
"other_requirements" then we can't verify that they match since they are
lost. We fall back to comparing the constant id of the query to the
impl's constraint (after deducing generics in the impl). This correctly
eliminates mismatches but eagerly eliminates impls that could match the
query interface as well when there's more than one interface in the
query.

2. We don't return a witness for every interface in the query facet
type. Since we can't demonstrate any use of the witness there yet, for
cases that can have more than one interface in the query facet type,
this doesn't break anything that was previously working. The return
value is currently treated as a bool for cases with multiple interfaces
in the facet type (as a test for "can this be converted") but the
converted-to facet value's witnesses are unused.

---------

Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
This commit is contained in:
Dana Jansens
2025-03-05 22:14:44 +00:00
committed by GitHub
co-authored by josh11b
parent 79a86074b1
commit a0b7f39591
10 changed files with 2392 additions and 257 deletions
+3 -5
View File
@@ -639,11 +639,10 @@ auto DeduceGenericCallArguments(
return deduction.MakeSpecific();
}
// Deduces the impl arguments to use in a use of a parameterized impl. Returns
// `None` if deduction fails.
auto DeduceImplArguments(Context& context, SemIR::LocId loc_id,
const SemIR::Impl& impl, SemIR::ConstantId self_id,
SemIR::ConstantId constraint_id) -> SemIR::SpecificId {
SemIR::SpecificId constraint_specific_id)
-> SemIR::SpecificId {
DeductionContext deduction(context, loc_id, impl.generic_id,
/*enclosing_specific_id=*/SemIR::SpecificId::None,
/*self_type_id=*/SemIR::InstId::None,
@@ -652,8 +651,7 @@ auto DeduceImplArguments(Context& context, SemIR::LocId loc_id,
// Prepare to perform deduction of the type and interface.
deduction.Add(impl.self_id, context.constant_values().GetInstId(self_id),
/*needs_substitution=*/false);
deduction.Add(impl.constraint_id,
context.constant_values().GetInstId(constraint_id),
deduction.Add(impl.interface.specific_id, constraint_specific_id,
/*needs_substitution=*/false);
if (!deduction.Deduce() || !deduction.CheckDeductionIsComplete()) {