Remove predicates on associated types from traits

These need to only be bounds to avoid cycle errors in trait checking.
This commit is contained in:
Matthew Jasper 2020-07-04 12:15:04 +01:00
parent 8787090964
commit 582ccec1c5
10 changed files with 141 additions and 42 deletions

View File

@ -391,6 +391,24 @@ rustc_queries! {
desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
}
/// Returns everything that looks like a predicate written explicitly
/// by the user on a trait item.
///
/// Traits are unusual, because predicates on associated types are
/// converted into bounds on that type for backwards compatibility:
///
/// trait X where Self::U: Copy { type U; }
///
/// becomes
///
/// trait X { type U: Copy; }
///
/// `explicit_predicates_of` and `explicit_item_bounds` will then take
/// the appropriate subsets of the predicates here.
query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// Returns the predicates written explicitly by the user.
query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }

View File

@ -77,6 +77,7 @@ pub fn provide(providers: &mut Providers) {
projection_ty_from_predicates,
explicit_predicates_of,
super_predicates_of,
trait_explicit_predicates_and_bounds,
type_param_predicates,
trait_def,
adt_def,
@ -1731,7 +1732,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
/// N.B., this does not include any implied/inferred constraints.
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
use rustc_hir::*;
debug!("explicit_predicates_of(def_id={:?})", def_id);
@ -2116,6 +2117,71 @@ fn const_evaluatable_predicates_of<'tcx>(
collector.preds
}
fn trait_explicit_predicates_and_bounds(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> ty::GenericPredicates<'_> {
assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
gather_explicit_predicates_of(tcx, def_id.to_def_id())
}
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
if let DefKind::Trait = tcx.def_kind(def_id) {
// Remove bounds on associated types from the predicates, they will be
// returned by `explicit_item_bounds`.
let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
let is_assoc_item_ty = |ty: Ty<'_>| {
// For a predicate from a where clause to become a bound on an
// associated type:
// * It must use the identity substs of the item.
// * Since any generic parameters on the item are not in scope,
// this means that the item is not a GAT, and its identity substs
// are the same as the trait's.
// * It must be an associated type for this trait (*not* a
// supertrait).
if let ty::Projection(projection) = ty.kind {
if projection.substs == trait_identity_substs
&& tcx.associated_item(projection.item_def_id).container.id() == def_id
{
true
} else {
false
}
} else {
false
}
};
let predicates: Vec<_> = predicates_and_bounds
.predicates
.iter()
.copied()
.filter(|(pred, _)| match pred.kind() {
ty::PredicateKind::Trait(tr, _) => !is_assoc_item_ty(tr.skip_binder().self_ty()),
ty::PredicateKind::Projection(proj) => {
!is_assoc_item_ty(proj.skip_binder().projection_ty.self_ty())
}
ty::PredicateKind::TypeOutlives(outlives) => {
!is_assoc_item_ty(outlives.skip_binder().0)
}
_ => true,
})
.collect();
if predicates.len() == predicates_and_bounds.predicates.len() {
predicates_and_bounds
} else {
ty::GenericPredicates {
parent: predicates_and_bounds.parent,
predicates: tcx.arena.alloc_slice(&predicates),
}
}
} else {
gather_explicit_predicates_of(tcx, def_id)
}
}
fn projection_ty_from_predicates(
tcx: TyCtxt<'tcx>,
key: (

View File

@ -34,7 +34,7 @@ fn associated_type_bounds<'tcx>(
);
let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
let trait_predicates = tcx.predicates_of(trait_def_id);
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
let bounds_from_parent =
trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.kind() {

View File

@ -1,6 +1,9 @@
// revisions: rpass cfail
trait Tr where Self::Arr: Sized {
trait Tr
where
(Self::Arr,): Sized,
{
type Arr;
const C: usize = 0;

View File

@ -0,0 +1,16 @@
// Check that `where Self::Output: Copy` is turned into a bound on `Op::Output`.
//check-pass
trait Op
where
Self::Output: Copy,
{
type Output;
}
fn duplicate<T: Op>(x: T::Output) -> (T::Output, T::Output) {
(x, x)
}
fn main() {}

View File

@ -5,12 +5,13 @@ trait Foo {
}
impl Foo for () {
// Doesn't error because we abort compilation after the errors below.
// See point-at-type-on-obligation-failure-3.rs
type Assoc = bool;
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
}
trait Baz where Self::Assoc: Bar {
trait Baz
where
Self::Assoc: Bar,
{
type Assoc;
}
@ -18,7 +19,10 @@ impl Baz for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
}
trait Bat where <Self as Bat>::Assoc: Bar {
trait Bat
where
<Self as Bat>::Assoc: Bar,
{
type Assoc;
}

View File

@ -1,21 +1,36 @@
error[E0277]: the trait bound `bool: Bar` is not satisfied
--> $DIR/point-at-type-on-obligation-failure-2.rs:18:18
--> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
|
LL | trait Baz where Self::Assoc: Bar {
| --- required by this bound in `Baz`
LL | type Assoc: Bar;
| --- required by this bound in `Foo::Assoc`
...
LL | type Assoc = bool;
| ^^^^ the trait `Bar` is not implemented for `bool`
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
error[E0277]: the trait bound `bool: Bar` is not satisfied
--> $DIR/point-at-type-on-obligation-failure-2.rs:26:18
--> $DIR/point-at-type-on-obligation-failure-2.rs:19:5
|
LL | trait Bat where <Self as Bat>::Assoc: Bar {
| --- required by this bound in `Bat`
LL | Self::Assoc: Bar,
| --- required by this bound in `Baz::Assoc`
LL | {
LL | type Assoc;
| ----- required by a bound in this
...
LL | type Assoc = bool;
| ^^^^ the trait `Bar` is not implemented for `bool`
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
error: aborting due to 2 previous errors
error[E0277]: the trait bound `bool: Bar` is not satisfied
--> $DIR/point-at-type-on-obligation-failure-2.rs:30:5
|
LL | <Self as Bat>::Assoc: Bar,
| --- required by this bound in `Bat::Assoc`
LL | {
LL | type Assoc;
| ----- required by a bound in this
...
LL | type Assoc = bool;
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,11 +0,0 @@
trait Bar {}
trait Foo {
type Assoc: Bar;
}
impl Foo for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
}
fn main() {}

View File

@ -1,12 +0,0 @@
error[E0277]: the trait bound `bool: Bar` is not satisfied
--> $DIR/point-at-type-on-obligation-failure-3.rs:8:5
|
LL | type Assoc: Bar;
| --- required by this bound in `Foo::Assoc`
...
LL | type Assoc = bool;
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,11 +1,11 @@
error[E0515]: cannot return value referencing local variable `s`
--> $DIR/issue-67765-async-diagnostic.rs:13:11
--> $DIR/issue-67765-async-diagnostic.rs:13:5
|
LL | let b = &s[..];
| - `s` is borrowed here
LL |
LL | Err(b)?;
| ^ returns a value referencing data owned by the current function
| ^^^^^^^ returns a value referencing data owned by the current function
error: aborting due to previous error