Concrete impl takes precedence over a facet value (#5305)

If a concrete impl is found via lookup, its associated constants should
be used over the constants found through a facet value.
This commit is contained in:
Dana Jansens
2025-04-14 18:48:55 +00:00
committed by GitHub
parent afa946aefa
commit da83b65aa2
2 changed files with 19 additions and 23 deletions
+16 -8
View File
@@ -441,15 +441,23 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id,
for (const auto& interface : interfaces) {
// TODO: Since both `interfaces` and `query_self_const_id` are sorted lists,
// do an O(N+M) merge instead of O(N*M) nested loops.
auto result_witness_id =
FindWitnessInFacet(context, loc_id, query_self_const_id, interface);
// TODO: If the impl lookup finds a final impl, it should take precedence
// over the witness from the facet value. See the test:
// fail_todo_final_impl_precidence_over_facet_value.carbon.
if (!result_witness_id.has_value()) {
result_witness_id = GetOrAddLookupImplWitness(
context, loc_id, query_self_const_id, interface);
auto result_witness_id = GetOrAddLookupImplWitness(
context, loc_id, query_self_const_id, interface);
if (!result_witness_id.has_value() ||
!context.insts().Is<SemIR::ImplWitness>(result_witness_id)) {
// If the witness is not concrete (the result is not final), then we
// prefer the witness from the query's facet value (if it is one), which
// may include rewrite rules of associated constants that can be relied
// on.
auto facet_value_witness_id =
FindWitnessInFacet(context, loc_id, query_self_const_id, interface);
if (facet_value_witness_id.has_value()) {
result_witness_id = facet_value_witness_id;
}
}
if (result_witness_id.has_value()) {
result_witness_ids.push_back(result_witness_id);
} else {
@@ -62,7 +62,7 @@ fn F[T:! Z where .X = ()](z: T) {
let a: z.Y = ();
}
// --- fail_todo_final_impl_makes_compatible_facet_values.carbon
// --- final_impl_makes_compatible_facet_values.carbon
library "[[@TEST_NAME]]";
interface I {}
@@ -80,24 +80,12 @@ class D(T:! J) {
fn F(T:! I & J) {
// `I` found in the facet type; The facet value of `T` in `C(T)` holds a `FacetAccessWitness`.
// TODO: It should use the `final impl` and thus hold the same `ImplWitness`
var x: C(T);
// `D.c` used the final impl decl to make a facet value with an `ImplWitness`
// for its `T` in `C(T)`.
var y: D(T);
// This converts a pointer to a facet value (should be `ImplWitness` but
// isn't) to a pointer to a facet value (with `ImplWitness`).
//
// TODO: It should type check when they are both the same generic type
// `C(T:! I)` defined by the `final impl` of `I`.
//
// CHECK:STDERR: fail_todo_final_impl_makes_compatible_facet_values.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `C(T as I)*` to `C(T as I)*` [ConversionFailure]
// CHECK:STDERR: y.c = &x;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_todo_final_impl_makes_compatible_facet_values.carbon:[[@LINE+4]]:3: note: type `C(T as I)*` does not implement interface `Core.ImplicitAs(C(T as I)*)` [MissingImplInMemberAccessNote]
// CHECK:STDERR: y.c = &x;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
// This converts a pointer to a type with with facet value (an `ImplWitness`)
// to a pointer to a type with a facet value (the same `ImplWitness`).
y.c = &x;
}