Ensure where requirements in named constraints are visible to lookups (#7299)

Require rewrite and same-type constraints that do not depend on `.Self`
to be satisfied when a facet type is identified, since those constraints
may not be found later.
This commit is contained in:
Dana Jansens
2026-07-22 16:18:57 +00:00
committed by GitHub
parent a48d14e451
commit 21dc5cde04
2 changed files with 229 additions and 0 deletions
+71
View File
@@ -29,6 +29,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- [Facet types](#facet-types)
- [Identified facet types](#identified-facet-types)
- [Named constraints](#named-constraints)
- [Rewrites and same-type constraints in a named constraint](#rewrites-and-same-type-constraints-in-a-named-constraint)
- [Constraints that don't depend on `.Self`](#constraints-that-dont-depend-on-self)
- [Subtyping between facet types](#subtyping-between-facet-types)
- [Combining interfaces by anding facet types](#combining-interfaces-by-anding-facet-types)
- [Interface requiring other interfaces](#interface-requiring-other-interfaces)
@@ -1110,6 +1112,75 @@ class ImplementsS {
}
```
### Rewrites and same-type constraints in a named constraint
A `require` statement may include rewrite or same-type constraints. In the case
of `extend require`, the rewrites are
[preserved as such](appendix-rewrite-constraints.md#combining-constraints-with-extend).
But otherwise, any rewrite constraint in the
[identified facet type](#identified-facet-types) of the `require` is
[treated as a same-type constraint](appendix-rewrite-constraints.md#combining-constraints-with-require-and-impls)
instead.
### Constraints that don't depend on `.Self`
> **TODO:** Link to section explaining when identifying a facet type happens when
> [#5168: Forward `impl` declaration of an incomplete interface](/proposals/p005168-forward-impl-declaration-of-an-incomplete-interface.md)
> is applied to these docs.
When identifying a facet type, we collect all constraints found in the facet
type and named constraints. Each constraint must depend on `.Self` in some way
in order to be found in future impl lookups involving the facet being
constrained. Thus, if there is no dependency on `.Self` in a constraint, it must
be satisfied immediately for the identify to complete successfully.
```carbon
constraint N(T: type) {
require impls Z where .Z1 = {};
}
```
When the above named constraint is identified as part of a facet type as
`C impls N(.Self)`, the resulting requirement `Z where .Z1 = {}` is only
constraining `C`, and not `.Self` from the top-level top-level facet type. So we
require that `C impls (Z where .Z1 = {})` is already true in order to successfully
identify.
```carbon
interface Z(V: type) {
let Z1: type;
let Z2: type;
}
constraint M(T2: type, U2: type) {
extend require impls Z(U2) where .Z1 = {} and .Z2 == ();
}
interface Y {
fn YY();
}
class C;
fn F(U: Y where C impls Z(.Self) where .Z1 = {} and .Z2 == (),
T: Y where C impls M(.Self, U)) {
// Member access into `T` causes its type to be identified, which succeeds.
// The identified facet type requires
// `C impls Z(U) where .Z1 = {} and .Z2 == ()` which is true from the facet
// type of `U`.
T.YY();
}
fn G(U: Y where C impls Z(.Self),
T: Y where C impls M(.Self, U));
// ❌ Error: The type of `T` can not be identified.
// Member access into `T` causes its type to be identified, which fails.
// The identified facet type requires
// `C impls Z(U) where .Z1 = {} and .Z2 == ()` which we don't know to be
// true here.
T.YY();
```
### Subtyping between facet types
There is a subtyping relationship between facet types that allows calls of one