From 2d9e3fee67f64f0fff4ea05d00953fb8b7e62db0 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 16 Jul 2026 15:11:23 -0400 Subject: [PATCH] Use identified facet type to get impl-as target (#7519) This supports impl lookup choosing an impl that targets a generic interface through a named constraint, without crashing. Instead of assuming the impl's target is a facet type containing an interface, we use the identified facet type to find the specific interface it targets. --- toolchain/check/impl_lookup.cpp | 41 ++++++++++++------- .../impl/impl_as_named_constraint.carbon | 31 +++++++++----- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index 3927c7e5c1f0..7148b3c608a1 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -243,15 +243,16 @@ static auto TreatImplAsFinal(Context& context, const SemIR::Impl& impl) static auto TryGetSpecificWitnessIdForImpl( Context& context, SemIR::LocId loc_id, SemIR::ConstantId query_self_const_id, - const SemIR::SpecificInterface& interface, SemIR::ImplId impl_id, - const SemIR::Impl& impl) -> SemIR::ConstantId { + const SemIR::SpecificInterface& query_specific_interface, + SemIR::ImplId impl_id, const SemIR::Impl& impl) -> SemIR::ConstantId { // The impl may have generic arguments, in which case we need to deduce them // to find what they are given the specific type and interface query. We use // that specific to map values in the impl to the deduced values. auto specific_id = SemIR::SpecificId::None; if (impl.generic_id.has_value()) { - specific_id = DeduceImplArguments( - context, loc_id, impl_id, query_self_const_id, interface.specific_id); + specific_id = + DeduceImplArguments(context, loc_id, impl_id, query_self_const_id, + query_specific_interface.specific_id); if (!specific_id.has_value()) { return SemIR::ConstantId::None; } @@ -282,21 +283,31 @@ static auto TryGetSpecificWitnessIdForImpl( return SemIR::ConstantId::None; } - auto deduced_constraint_facet_type_id = - context.constant_values() - .GetInstAs(deduced_constraint_id) - .facet_type_id; - const auto& deduced_constraint_facet_type_info = - context.facet_types().Get(deduced_constraint_facet_type_id); - CARBON_CHECK(deduced_constraint_facet_type_info.extend_constraints.size() == - 1); + // Get the identified facet type of the deduced impl's constraint, so we can + // get the specific interface being implemented after deduction. + auto deduced_constrant_type_inst_id = + context.types().GetTypeInstIdForTypeConstantId(deduced_constraint_id); + auto deduced_constraint_identified_facet_type_id = + TryToIdentifyFacetType(context, loc_id, deduced_self_const_id, + deduced_constrant_type_inst_id, false); + if (!deduced_constraint_identified_facet_type_id.has_value()) { + return SemIR::ConstantId::None; + } + + const auto& deduced_constraint_identified_facet_type = + context.identified_facet_types().Get( + deduced_constraint_identified_facet_type_id); + // We only find valid impls in impl lookup, which implement a single specific + // interface. + CARBON_CHECK( + deduced_constraint_identified_facet_type.is_valid_impl_as_target()); // The specifics in the queried interface must match the deduced specifics in // the impl's constraint facet type. auto impl_interface_specific_id = - deduced_constraint_facet_type_info.extend_constraints[0].specific_id; - auto query_interface_specific_id = interface.specific_id; - if (impl_interface_specific_id != query_interface_specific_id) { + deduced_constraint_identified_facet_type.impl_as_target_interface() + .specific_id; + if (impl_interface_specific_id != query_specific_interface.specific_id) { return SemIR::ConstantId::None; } diff --git a/toolchain/check/testdata/impl/impl_as_named_constraint.carbon b/toolchain/check/testdata/impl/impl_as_named_constraint.carbon index 53612520727c..b6feb7771ae1 100644 --- a/toolchain/check/testdata/impl/impl_as_named_constraint.carbon +++ b/toolchain/check/testdata/impl/impl_as_named_constraint.carbon @@ -185,8 +185,7 @@ impl C as N where .I1 = C {} fn F(generic _: I where .I1 = .Self) {} fn G() { -// TODO: This crashes. -// F(C); + F(C); } // --- impl_as_concrete_generic_constraint_where_rewrite.carbon @@ -206,11 +205,10 @@ impl C as N where .I1 = C {} fn F(generic _: I(.Self) where .I1 = .Self) {} fn G() { -// TODO: This crashes. -// F(C); + F(C); } -// --- todo_impl_as_symbolic_generic_constraint_where_rewrite.carbon +// --- impl_as_symbolic_generic_constraint_where_rewrite.carbon library "[[@TEST_NAME]]"; interface I(T: type) { @@ -226,8 +224,7 @@ impl C as N where .I1 = C {} fn F(generic _: I(.Self) where .I1 = .Self) {} fn G() { -// TODO: This crashes. -// F(C); + F(C); } // --- fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon @@ -253,8 +250,14 @@ impl C as N {} fn F(generic _: I where .I1 = .Self) {} fn G() { -// TODO: This crashes. -// F(C); + // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `I where .(I.I1) = .Self` [ConversionFailureTypeToFacet] + // CHECK:STDERR: F(C); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_concrete_interface.carbon:[[@LINE-5]]:14: note: initializing generic parameter `_` declared here [InitializingGenericParam] + // CHECK:STDERR: fn F(generic _: I where .I1 = .Self) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + F(C); } // --- fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon @@ -280,8 +283,14 @@ impl C as N {} fn F(generic _: I(.Self) where .I1 = .Self) {} fn G() { -// TODO: This crashes. -// F(C); + // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `I(.Self) where .(I(.Self).I1) = .Self` [ConversionFailureTypeToFacet] + // CHECK:STDERR: F(C); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_todo_impl_as_constraint_containing_rewrite_for_generic_interface.carbon:[[@LINE-5]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn F(generic _: I(.Self) where .I1 = .Self) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + F(C); } // --- fail_no_require_self.carbon