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.
This commit is contained in:
Dana Jansens
2026-07-16 19:11:23 +00:00
committed by GitHub
parent 0848cf941d
commit 2d9e3fee67
2 changed files with 46 additions and 26 deletions
+26 -15
View File
@@ -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<SemIR::FacetType>(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;
}
+20 -11
View File
@@ -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