about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/query/mod.rs18
-rw-r--r--compiler/rustc_typeck/src/collect.rs68
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs2
-rw-r--r--src/test/incremental/issue-54242.rs5
-rw-r--r--src/test/ui/associated-type-bounds/assoc-type-bound-through-where-clause.rs16
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs14
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr33
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure-3.rs11
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure-3.stderr12
-rw-r--r--src/test/ui/async-await/issue-67765-async-diagnostic.stderr4
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