Gracefully handle a concrete ImplWitnessAccess in the type structure (#7214)

While this can only happen when some other error is taking place, we
should handle it gracefully and report a concrete (but unmatchable)
value in the type structure instead of CHECK-failing.
This commit is contained in:
Dana Jansens
2026-05-15 14:53:51 +00:00
committed by GitHub
parent dd47e41da6
commit 835a61c385
2 changed files with 30 additions and 4 deletions
+28
View File
@@ -53,3 +53,31 @@ fn H(U:! type, V:! Z where .Z1 impls (Y where .Y1 = U)) {
// query's.
V as X(U);
}
// --- fail_concrete_impl_witness_access_in_type_structure.carbon
library "[[@TEST_NAME]]";
interface Z(T:! type) {
let Z1:! type;
}
interface Y {}
class C;
// Converting to this facet type requires a lookup for `C.(Z(C).Z1) as Y`. That
// has a type structure that contains a fully concrete ImplWitnessAccess. But if
// the lookup fails because there is no impl for `C as Z(C)`, then the access
// remains in the type structure as is. This test ensures the type structure can
// handle this edge case.
fn F(unused T:! Z(.Self) where C impls (Z(C) where .Z1 impls Y)) {}
fn G(T:! Z(.Self)) {
// CHECK:STDERR: fail_concrete_impl_witness_access_in_type_structure.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `Z(.Self)` into type implementing `Z(.Self) where C impls Z(C) and C.(Z(C).Z1) impls Y` [ConversionFailureFacetToFacet]
// CHECK:STDERR: F(T);
// CHECK:STDERR: ^~~~
// CHECK:STDERR: fail_concrete_impl_witness_access_in_type_structure.carbon:[[@LINE-6]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn F(unused T:! Z(.Self) where C impls (Z(C) where .Z1 impls Y)) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
F(T);
}
+2 -4
View File
@@ -254,10 +254,8 @@ auto TypeIterator::ProcessType(InstId inst_id) -> std::optional<Step> {
// We return FacetValues as a separate iterative step, then also recurse
// into the the self value being accessed.
//
// Witness access of a concrete value would have evaluated to the accessed
// value, so we only see ImplWitnessAccess in a type when it's a symbolic
// value, which implies it contains a LookupImplWitness.
CARBON_CHECK(sem_ir_->constant_values().Get(inst_id).is_symbolic());
// If ImplWitnessAccess did not evaluate to some other value, it must
// contain a non-final witness.
auto witness =
sem_ir_->insts().GetAs<LookupImplWitness>(access.witness_id);
// Recurse into symbolic ImplWitnessAccess, replacing it with the self