Skip to content

Commit 582ccec

Browse files
committed
Remove predicates on associated types from traits
These need to only be bounds to avoid cycle errors in trait checking.
1 parent 8787090 commit 582ccec

File tree

10 files changed

+141
-42
lines changed

10 files changed

+141
-42
lines changed

compiler/rustc_middle/src/query/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,24 @@ rustc_queries! {
391391
desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
392392
}
393393

394+
/// Returns everything that looks like a predicate written explicitly
395+
/// by the user on a trait item.
396+
///
397+
/// Traits are unusual, because predicates on associated types are
398+
/// converted into bounds on that type for backwards compatibility:
399+
///
400+
/// trait X where Self::U: Copy { type U; }
401+
///
402+
/// becomes
403+
///
404+
/// trait X { type U: Copy; }
405+
///
406+
/// `explicit_predicates_of` and `explicit_item_bounds` will then take
407+
/// the appropriate subsets of the predicates here.
408+
query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
409+
desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
410+
}
411+
394412
/// Returns the predicates written explicitly by the user.
395413
query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
396414
desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }

compiler/rustc_typeck/src/collect.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub fn provide(providers: &mut Providers) {
7777
projection_ty_from_predicates,
7878
explicit_predicates_of,
7979
super_predicates_of,
80+
trait_explicit_predicates_and_bounds,
8081
type_param_predicates,
8182
trait_def,
8283
adt_def,
@@ -1731,7 +1732,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
17311732

17321733
/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
17331734
/// N.B., this does not include any implied/inferred constraints.
1734-
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
1735+
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
17351736
use rustc_hir::*;
17361737

17371738
debug!("explicit_predicates_of(def_id={:?})", def_id);
@@ -2116,6 +2117,71 @@ fn const_evaluatable_predicates_of<'tcx>(
21162117
collector.preds
21172118
}
21182119

2120+
fn trait_explicit_predicates_and_bounds(
2121+
tcx: TyCtxt<'_>,
2122+
def_id: LocalDefId,
2123+
) -> ty::GenericPredicates<'_> {
2124+
assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
2125+
gather_explicit_predicates_of(tcx, def_id.to_def_id())
2126+
}
2127+
2128+
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
2129+
if let DefKind::Trait = tcx.def_kind(def_id) {
2130+
// Remove bounds on associated types from the predicates, they will be
2131+
// returned by `explicit_item_bounds`.
2132+
let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
2133+
let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
2134+
2135+
let is_assoc_item_ty = |ty: Ty<'_>| {
2136+
// For a predicate from a where clause to become a bound on an
2137+
// associated type:
2138+
// * It must use the identity substs of the item.
2139+
// * Since any generic parameters on the item are not in scope,
2140+
// this means that the item is not a GAT, and its identity substs
2141+
// are the same as the trait's.
2142+
// * It must be an associated type for this trait (*not* a
2143+
// supertrait).
2144+
if let ty::Projection(projection) = ty.kind {
2145+
if projection.substs == trait_identity_substs
2146+
&& tcx.associated_item(projection.item_def_id).container.id() == def_id
2147+
{
2148+
true
2149+
} else {
2150+
false
2151+
}
2152+
} else {
2153+
false
2154+
}
2155+
};
2156+
2157+
let predicates: Vec<_> = predicates_and_bounds
2158+
.predicates
2159+
.iter()
2160+
.copied()
2161+
.filter(|(pred, _)| match pred.kind() {
2162+
ty::PredicateKind::Trait(tr, _) => !is_assoc_item_ty(tr.skip_binder().self_ty()),
2163+
ty::PredicateKind::Projection(proj) => {
2164+
!is_assoc_item_ty(proj.skip_binder().projection_ty.self_ty())
2165+
}
2166+
ty::PredicateKind::TypeOutlives(outlives) => {
2167+
!is_assoc_item_ty(outlives.skip_binder().0)
2168+
}
2169+
_ => true,
2170+
})
2171+
.collect();
2172+
if predicates.len() == predicates_and_bounds.predicates.len() {
2173+
predicates_and_bounds
2174+
} else {
2175+
ty::GenericPredicates {
2176+
parent: predicates_and_bounds.parent,
2177+
predicates: tcx.arena.alloc_slice(&predicates),
2178+
}
2179+
}
2180+
} else {
2181+
gather_explicit_predicates_of(tcx, def_id)
2182+
}
2183+
}
2184+
21192185
fn projection_ty_from_predicates(
21202186
tcx: TyCtxt<'tcx>,
21212187
key: (

compiler/rustc_typeck/src/collect/item_bounds.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fn associated_type_bounds<'tcx>(
3434
);
3535

3636
let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
37-
let trait_predicates = tcx.predicates_of(trait_def_id);
37+
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
3838

3939
let bounds_from_parent =
4040
trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.kind() {

src/test/incremental/issue-54242.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// revisions: rpass cfail
22

3-
trait Tr where Self::Arr: Sized {
3+
trait Tr
4+
where
5+
(Self::Arr,): Sized,
6+
{
47
type Arr;
58

69
const C: usize = 0;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Check that `where Self::Output: Copy` is turned into a bound on `Op::Output`.
2+
3+
//check-pass
4+
5+
trait Op
6+
where
7+
Self::Output: Copy,
8+
{
9+
type Output;
10+
}
11+
12+
fn duplicate<T: Op>(x: T::Output) -> (T::Output, T::Output) {
13+
(x, x)
14+
}
15+
16+
fn main() {}

src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,24 @@ trait Foo {
55
}
66

77
impl Foo for () {
8-
// Doesn't error because we abort compilation after the errors below.
9-
// See point-at-type-on-obligation-failure-3.rs
10-
type Assoc = bool;
8+
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
119
}
1210

13-
trait Baz where Self::Assoc: Bar {
11+
trait Baz
12+
where
13+
Self::Assoc: Bar,
14+
{
1415
type Assoc;
1516
}
1617

1718
impl Baz for () {
1819
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
1920
}
2021

21-
trait Bat where <Self as Bat>::Assoc: Bar {
22+
trait Bat
23+
where
24+
<Self as Bat>::Assoc: Bar,
25+
{
2226
type Assoc;
2327
}
2428

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,36 @@
11
error[E0277]: the trait bound `bool: Bar` is not satisfied
2-
--> $DIR/point-at-type-on-obligation-failure-2.rs:18:18
2+
--> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
33
|
4-
LL | trait Baz where Self::Assoc: Bar {
5-
| --- required by this bound in `Baz`
4+
LL | type Assoc: Bar;
5+
| --- required by this bound in `Foo::Assoc`
66
...
77
LL | type Assoc = bool;
8-
| ^^^^ the trait `Bar` is not implemented for `bool`
8+
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
99

1010
error[E0277]: the trait bound `bool: Bar` is not satisfied
11-
--> $DIR/point-at-type-on-obligation-failure-2.rs:26:18
11+
--> $DIR/point-at-type-on-obligation-failure-2.rs:19:5
1212
|
13-
LL | trait Bat where <Self as Bat>::Assoc: Bar {
14-
| --- required by this bound in `Bat`
13+
LL | Self::Assoc: Bar,
14+
| --- required by this bound in `Baz::Assoc`
15+
LL | {
16+
LL | type Assoc;
17+
| ----- required by a bound in this
1518
...
1619
LL | type Assoc = bool;
17-
| ^^^^ the trait `Bar` is not implemented for `bool`
20+
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
1821

19-
error: aborting due to 2 previous errors
22+
error[E0277]: the trait bound `bool: Bar` is not satisfied
23+
--> $DIR/point-at-type-on-obligation-failure-2.rs:30:5
24+
|
25+
LL | <Self as Bat>::Assoc: Bar,
26+
| --- required by this bound in `Bat::Assoc`
27+
LL | {
28+
LL | type Assoc;
29+
| ----- required by a bound in this
30+
...
31+
LL | type Assoc = bool;
32+
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
33+
34+
error: aborting due to 3 previous errors
2035

2136
For more information about this error, try `rustc --explain E0277`.

src/test/ui/associated-types/point-at-type-on-obligation-failure-3.rs

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/test/ui/associated-types/point-at-type-on-obligation-failure-3.stderr

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/test/ui/async-await/issue-67765-async-diagnostic.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0515]: cannot return value referencing local variable `s`
2-
--> $DIR/issue-67765-async-diagnostic.rs:13:11
2+
--> $DIR/issue-67765-async-diagnostic.rs:13:5
33
|
44
LL | let b = &s[..];
55
| - `s` is borrowed here
66
LL |
77
LL | Err(b)?;
8-
| ^ returns a value referencing data owned by the current function
8+
| ^^^^^^^ returns a value referencing data owned by the current function
99

1010
error: aborting due to previous error
1111

0 commit comments

Comments
 (0)