diff options
10 files changed, 141 insertions, 42 deletions
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 808a0793a94..240f2c0792c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -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) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index ac4abd6a511..7e125481671 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -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: ( diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 96e331ba516..c9af86f70fd 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -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() { diff --git a/src/test/incremental/issue-54242.rs b/src/test/incremental/issue-54242.rs index a95cf776c2e..9e449de0cf5 100644 --- a/src/test/incremental/issue-54242.rs +++ b/src/test/incremental/issue-54242.rs @@ -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; diff --git a/src/test/ui/associated-type-bounds/assoc-type-bound-through-where-clause.rs b/src/test/ui/associated-type-bounds/assoc-type-bound-through-where-clause.rs new file mode 100644 index 00000000000..49f11140741 --- /dev/null +++ b/src/test/ui/associated-type-bounds/assoc-type-bound-through-where-clause.rs @@ -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() {} diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs index 4bd3ccab834..4b3d6e9d606 100644 --- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs +++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs @@ -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; } diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr index f4971105499..b23030d7cb5 100644 --- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr +++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr @@ -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`. diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-3.rs b/src/test/ui/associated-types/point-at-type-on-obligation-failure-3.rs deleted file mode 100644 index 9360d96f05e..00000000000 --- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-3.rs +++ /dev/null @@ -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() {} diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-3.stderr b/src/test/ui/associated-types/point-at-type-on-obligation-failure-3.stderr deleted file mode 100644 index 6ab3d94e102..00000000000 --- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-3.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.stderr b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr index 78253042bee..832b736ad86 100644 --- a/src/test/ui/async-await/issue-67765-async-diagnostic.stderr +++ b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr @@ -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 |
