Files
carbon-lang/toolchain/check/testdata/impl/lookup/access.carbon
T
Dana Jansens 835a61c385 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.
2026-05-15 14:53:51 +00:00

84 lines
3.3 KiB
Plaintext

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/lookup/access.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/lookup/access.carbon
// --- impl_witness_access_in_impl_type_structure.carbon
library "[[@TEST_NAME]]";
interface X(T:! type) {}
interface Y {
let Y1:! type;
}
interface Z {
let Z1:! type;
}
// There's 2 ImplWitnessAccess instructions in the type, but they together
// resolve to a symbolic type value, so the type structure is: `? as X(?)`
impl forall [T:! Z where .Z1 impls Y] T as X(T.Z1.(Y.Y1)) {}
class C {
impl as Y where .Y1 = {} {}
}
fn F(V:! Z where .Z1 = C) {
// The type stucture is `? as X({})` which will match the impl's less specific
// `? as X(?)`, then the impl will deduce the parameter of `X` to be `{}` from
// the type of `V`. This would fail if ImplWitnessAccess instructions were
// treated as Concrete in the type structure, since the impl would have a
// different concrete value (an ImplWitnessAccess) than the query (a
// StructValue).
V as X({});
}
fn G(V:! Z where .Z1 impls Y) {
// The type structure is `? as X(?)`, also built from ImplWitnessAccess insts,
// which will match the impl's `? as X(?)`.
V as X(V.(Z.Z1).(Y.Y1));
}
fn H(U:! type, V:! Z where .Z1 impls (Y where .Y1 = U)) {
// The type structure is `? as X(?)`, without using an ImplWitnessAccess,
// which will match the impl's `? as X(?)`. This would fail if
// ImplWitnessAccess instructions were treated as Concrete in the type
// structure, since the impl's type structure would be more specific than the
// 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);
}