about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlexander Regueiro <alexreg@me.com>2019-03-16 00:03:51 +0000
committerAlexander Regueiro <alexreg@me.com>2019-06-05 21:09:27 +0100
commit4310ba2c985c161260bbdfef5d92ceea552e9055 (patch)
tree2ec9ae19d0e7ac3d1d8abd1696be90cf81ac396e /src
parentcad1b1847eb6c2b720858f26af16d38d658fbc1a (diff)
downloadrust-4310ba2c985c161260bbdfef5d92ceea552e9055.tar.gz
rust-4310ba2c985c161260bbdfef5d92ceea552e9055.zip
Added test suite.
Diffstat (limited to 'src')
-rw-r--r--src/test/run-pass/issues/issue-25700-2.rs2
-rw-r--r--src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs177
-rw-r--r--src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs182
-rw-r--r--src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs60
-rw-r--r--src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr85
-rw-r--r--src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs51
-rw-r--r--src/test/ui/associated-type-bounds/duplicate.rs161
-rw-r--r--src/test/ui/associated-type-bounds/duplicate.stderr627
-rw-r--r--src/test/ui/associated-type-bounds/dyn-existential-type.rs67
-rw-r--r--src/test/ui/associated-type-bounds/dyn-lcsit.rs69
-rw-r--r--src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs73
-rw-r--r--src/test/ui/associated-type-bounds/entails-sized-object-safety.rs26
-rw-r--r--src/test/ui/associated-type-bounds/enum-bounds.rs122
-rw-r--r--src/test/ui/associated-type-bounds/existential-type.rs67
-rw-r--r--src/test/ui/associated-type-bounds/fn-apit.rs58
-rw-r--r--src/test/ui/associated-type-bounds/fn-aux.rs12
-rw-r--r--src/test/ui/associated-type-bounds/fn-dyn-apit.rs60
-rw-r--r--src/test/ui/associated-type-bounds/fn-inline.rs62
-rw-r--r--src/test/ui/associated-type-bounds/fn-where.rs78
-rw-r--r--src/test/ui/associated-type-bounds/fn-wrap-apit.rs64
-rw-r--r--src/test/ui/associated-type-bounds/implied-region-constraints.rs47
-rw-r--r--src/test/ui/associated-type-bounds/implied-region-constraints.stderr25
-rw-r--r--src/test/ui/associated-type-bounds/inside-adt.rs36
-rw-r--r--src/test/ui/associated-type-bounds/inside-adt.stderr79
-rw-r--r--src/test/ui/associated-type-bounds/lcsit.rs78
-rw-r--r--src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs25
-rw-r--r--src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr9
-rw-r--r--src/test/ui/associated-type-bounds/rpit.rs64
-rw-r--r--src/test/ui/associated-type-bounds/struct-bounds.rs115
-rw-r--r--src/test/ui/associated-type-bounds/trait-params.rs116
-rw-r--r--src/test/ui/associated-type-bounds/type-alias.rs19
-rw-r--r--src/test/ui/associated-type-bounds/type-alias.stderr97
-rw-r--r--src/test/ui/associated-type-bounds/union-bounds.rs123
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs71
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr132
-rw-r--r--src/test/ui/type/type-alias-bounds.stderr10
36 files changed, 3138 insertions, 11 deletions
diff --git a/src/test/run-pass/issues/issue-25700-2.rs b/src/test/run-pass/issues/issue-25700-2.rs
index 65de5edce48..b161e68abaf 100644
--- a/src/test/run-pass/issues/issue-25700-2.rs
+++ b/src/test/run-pass/issues/issue-25700-2.rs
@@ -18,5 +18,5 @@ fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
 }
 
 pub fn main() {
-   assert_eq!(record_type::<u32>(3), 42);
+    assert_eq!(record_type::<u32>(3), 42);
 }
diff --git a/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs b/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs
new file mode 100644
index 00000000000..0ea23ad1dbf
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs
@@ -0,0 +1,177 @@
+// Traits:
+
+pub trait Alpha {
+    fn alpha(self) -> usize;
+}
+
+pub trait Beta {
+    type Gamma;
+    fn gamma(self) -> Self::Gamma;
+}
+
+pub trait Delta {
+    fn delta(self) -> usize;
+}
+
+pub trait Epsilon<'a> {
+    type Zeta;
+    fn zeta(&'a self) -> Self::Zeta;
+
+    fn epsilon(&'a self) -> usize;
+}
+
+pub trait Eta {
+    fn eta(self) -> usize;
+}
+
+// Assertions:
+
+pub fn assert_alpha<T: Alpha>(x: T) -> usize { x.alpha() }
+pub fn assert_static<T: 'static>(_: T) -> usize { 24 }
+pub fn assert_delta<T: Delta>(x: T) -> usize { x.delta() }
+pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() }
+pub fn assert_epsilon_forall<T: for<'a> Epsilon<'a>>() {}
+pub fn assert_forall_epsilon_zeta_satisfies_eta<T>(x: T) -> usize
+where
+    T: for<'a> Epsilon<'a>,
+    for<'a> <T as Epsilon<'a>>::Zeta: Eta,
+{
+    x.epsilon() + x.zeta().eta()
+}
+
+// Implementations and types:
+
+#[derive(Copy, Clone)]
+pub struct BetaType;
+
+#[derive(Copy, Clone)]
+pub struct GammaType;
+
+#[derive(Copy, Clone)]
+pub struct ZetaType;
+
+impl Beta for BetaType {
+    type Gamma = GammaType;
+    fn gamma(self) -> Self::Gamma { GammaType }
+}
+
+impl<'a> Beta for &'a BetaType {
+    type Gamma = GammaType;
+    fn gamma(self) -> Self::Gamma { GammaType }
+}
+
+impl Beta for GammaType {
+    type Gamma = Self;
+    fn gamma(self) -> Self::Gamma { self }
+}
+
+impl Alpha for GammaType {
+    fn alpha(self) -> usize { 42 }
+}
+
+impl Delta for GammaType {
+    fn delta(self) -> usize { 1337 }
+}
+
+impl<'a> Epsilon<'a> for GammaType {
+    type Zeta = ZetaType;
+    fn zeta(&'a self) -> Self::Zeta { ZetaType }
+
+    fn epsilon(&'a self) -> usize { 7331 }
+}
+
+impl Eta for ZetaType {
+    fn eta(self) -> usize { 7 }
+}
+
+// Desugared forms to check against:
+
+pub fn desugared_bound<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Alpha
+{
+    let gamma: B::Gamma = beta.gamma();
+    assert_alpha::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: 'static,
+{
+    assert_static::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_multi<B>(beta: B) -> usize
+where
+    B: Copy + Beta,
+    B::Gamma: Alpha + 'static + Delta,
+{
+    assert_alpha::<B::Gamma>(beta.gamma()) +
+    assert_static::<B::Gamma>(beta.gamma()) +
+    assert_delta::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize
+where
+    B: Beta,
+    B::Gamma: 'a + Epsilon<'a>,
+{
+    assert_epsilon_specific::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region_forall<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+{
+    assert_epsilon_forall::<B::Gamma>();
+    let g1: B::Gamma = beta.gamma();
+    let g2: B::Gamma = g1;
+    assert_epsilon_specific::<B::Gamma>(&g1) +
+    assert_epsilon_specific::<B::Gamma>(&g2)
+}
+
+pub fn desugared_bound_region_forall2<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+    for<'a> <B::Gamma as Epsilon<'a>>::Zeta: Eta,
+{
+    let gamma = beta.gamma();
+    assert_forall_epsilon_zeta_satisfies_eta::<B::Gamma>(gamma)
+}
+
+pub fn desugared_contraint_region_forall<B>(beta: B) -> usize
+where
+    for<'a> &'a B: Beta,
+    for<'a> <&'a B as Beta>::Gamma: Alpha,
+{
+    let g1 = beta.gamma();
+    let g2 = beta.gamma();
+    assert_alpha(g1) + assert_alpha(g2)
+}
+
+pub fn desugared_bound_nested<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + Alpha + Beta,
+    <B::Gamma as Beta>::Gamma: Delta,
+{
+    let go = beta.gamma();
+    let gi = go.gamma();
+    go.alpha() + gi.delta()
+}
+
+pub fn desugared() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, desugared_bound(beta));
+    assert_eq!(24, desugared_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta));
+    assert_eq!(7331, desugared_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, desugared_bound_region_forall(beta));
+    assert_eq!(42 + 1337, desugared_bound_nested(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs b/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs
new file mode 100644
index 00000000000..85d6c5aaf3c
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs
@@ -0,0 +1,182 @@
+// Traits:
+
+pub trait Alpha {
+    fn alpha(self) -> usize;
+}
+
+pub trait Beta {
+    type Gamma;
+    fn gamma(&self) -> Self::Gamma;
+}
+
+pub trait Delta {
+    fn delta(self) -> usize;
+}
+
+pub trait Epsilon<'a> {
+    type Zeta;
+    fn zeta(&'a self) -> Self::Zeta;
+
+    fn epsilon(&'a self) -> usize;
+}
+
+pub trait Eta {
+    fn eta(self) -> usize;
+}
+
+// Assertions:
+
+pub fn assert_alpha<T: Alpha>(x: T) -> usize { x.alpha() }
+pub fn assert_static<T: 'static>(_: T) -> usize { 24 }
+pub fn assert_delta<T: Delta>(x: T) -> usize { x.delta() }
+pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() }
+pub fn assert_epsilon_forall<T: for<'a> Epsilon<'a>>() {}
+pub fn assert_forall_epsilon_zeta_satisfies_eta<T>(x: T) -> usize
+where
+    T: for<'a> Epsilon<'a>,
+    for<'a> <T as Epsilon<'a>>::Zeta: Eta,
+{
+    x.epsilon() + x.zeta().eta()
+}
+
+// Implementations and types:
+
+#[derive(Copy, Clone)]
+pub struct BetaType;
+
+#[derive(Copy, Clone)]
+pub struct GammaType;
+
+#[derive(Copy, Clone)]
+pub struct ZetaType;
+
+impl<T> Beta for &(dyn Beta<Gamma = T> + Send) {
+    type Gamma = T;
+    fn gamma(&self) -> Self::Gamma { (*self).gamma() }
+}
+
+impl Beta for BetaType {
+    type Gamma = GammaType;
+    fn gamma(&self) -> Self::Gamma { GammaType }
+}
+
+impl<'a> Beta for &'a BetaType {
+    type Gamma = GammaType;
+    fn gamma(&self) -> Self::Gamma { GammaType }
+}
+
+impl Beta for GammaType {
+    type Gamma = Self;
+    fn gamma(&self) -> Self::Gamma { Self }
+}
+
+impl Alpha for GammaType {
+    fn alpha(self) -> usize { 42 }
+}
+
+impl Delta for GammaType {
+    fn delta(self) -> usize { 1337 }
+}
+
+impl<'a> Epsilon<'a> for GammaType {
+    type Zeta = ZetaType;
+    fn zeta(&'a self) -> Self::Zeta { ZetaType }
+
+    fn epsilon(&'a self) -> usize { 7331 }
+}
+
+impl Eta for ZetaType {
+    fn eta(self) -> usize { 7 }
+}
+
+// Desugared forms to check against:
+
+pub fn desugared_bound<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Alpha
+{
+    let gamma: B::Gamma = beta.gamma();
+    assert_alpha::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: 'static,
+{
+    assert_static::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_multi<B: ?Sized>(beta: B) -> usize
+where
+    B: Copy + Beta,
+    B::Gamma: Alpha + 'static + Delta,
+{
+    assert_alpha::<B::Gamma>(beta.gamma()) +
+    assert_static::<B::Gamma>(beta.gamma()) +
+    assert_delta::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_region_specific<'a, B: ?Sized>(gamma: &'a B::Gamma) -> usize
+where
+    B: Beta,
+    B::Gamma: 'a + Epsilon<'a>,
+{
+    assert_epsilon_specific::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region_forall<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+{
+    assert_epsilon_forall::<B::Gamma>();
+    let g1: B::Gamma = beta.gamma();
+    let g2: B::Gamma = g1;
+    assert_epsilon_specific::<B::Gamma>(&g1) +
+    assert_epsilon_specific::<B::Gamma>(&g2)
+}
+
+pub fn desugared_bound_region_forall2<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+    for<'a> <B::Gamma as Epsilon<'a>>::Zeta: Eta,
+{
+    let gamma = beta.gamma();
+    assert_forall_epsilon_zeta_satisfies_eta::<B::Gamma>(gamma)
+}
+
+pub fn desugared_contraint_region_forall<B: ?Sized>(beta: &B) -> usize
+where
+    for<'a> &'a B: Beta,
+    for<'a> <&'a B as Beta>::Gamma: Alpha,
+{
+    let g1 = beta.gamma();
+    let g2 = beta.gamma();
+    assert_alpha(g1) + assert_alpha(g2)
+}
+
+pub fn desugared_bound_nested<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + Alpha + Beta,
+    <B::Gamma as Beta>::Gamma: Delta,
+{
+    let go = beta.gamma();
+    let gi = go.gamma();
+    go.alpha() + gi.delta()
+}
+
+pub fn desugared() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, desugared_bound(&beta));
+    assert_eq!(24, desugared_bound_region(&beta));
+    assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta));
+    assert_eq!(7331, desugared_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, desugared_bound_region_forall(&beta));
+    assert_eq!(42 + 1337, desugared_bound_nested(&beta));
+}
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
new file mode 100644
index 00000000000..78704a9b512
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
@@ -0,0 +1,60 @@
+// compile-fail
+// ignore-tidy-linelength
+
+// NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
+// This should hopefully be fixed with Chalk.
+
+#![feature(associated_type_bounds)]
+
+use std::fmt::Debug;
+use std::iter::Once;
+
+trait Lam<Binder> { type App; }
+
+#[derive(Clone)]
+struct L1;
+impl<'a> Lam<&'a u8> for L1 { type App = u8; }
+
+#[derive(Clone)]
+struct L2;
+impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
+
+trait Case1 {
+    type C: Clone + Iterator<Item:
+        Send + Iterator<Item:
+            for<'a> Lam<&'a u8, App:
+                Debug
+            >
+        > + Sync>;
+}
+
+pub struct S1;
+impl Case1 for S1 {
+//~^ ERROR `<L1 as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277]
+    type C = Once<Once<L1>>;
+}
+
+fn assume_case1<T: Case1>() {
+//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277]
+//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator [E0277]
+//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely [E0277]
+//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely [E0277]
+    fn assert_a<_0, A>() where A: Iterator<Item = _0>, _0: Debug {}
+    assert_a::<_, T::A>();
+
+    fn assert_b<_0, B>() where B: Iterator<Item = _0>, _0: 'static {}
+    assert_b::<_, T::B>();
+
+    fn assert_c<_0, _1, _2, C>()
+    where
+        C: Clone + Iterator<Item = _2>,
+        _2: Send + Iterator<Item = _1>,
+        _1: for<'a> Lam<&'a u8, App = _0>,
+        _0: Debug,
+    {}
+    assert_c::<_, _, _, T::C>();
+}
+
+fn main() {
+    assume_case1(S1);
+}
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
new file mode 100644
index 00000000000..aebf29cc332
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
@@ -0,0 +1,85 @@
+error[E0277]: `<L1 as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:32:6
+   |
+LL | impl Case1 for S1 {
+   |      ^^^^^ `<L1 as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+   |
+   = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<L1 as Lam<&'a u8>>::App`
+
+error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator` bound
+
+error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send` bound
+note: required by `Case1`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
+   |
+LL | trait Case1 {
+   | ^^^^^^^^^^^
+
+error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
+   |
+   = help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync` bound
+note: required by `Case1`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
+   |
+LL | trait Case1 {
+   | ^^^^^^^^^^^
+
+error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+   |
+   = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App`
+note: required by `Case1`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
+   |
+LL | trait Case1 {
+   | ^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
new file mode 100644
index 00000000000..8c9110d03ec
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
@@ -0,0 +1,51 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+use std::fmt::Debug;
+use std::iter::Empty;
+use std::ops::Range;
+
+trait Lam<Binder> { type App; }
+
+#[derive(Clone)]
+struct L1;
+impl<'a> Lam<&'a u8> for L1 { type App = u8; }
+
+#[derive(Clone)]
+struct L2;
+impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
+
+trait Case1 {
+    type A: Iterator<Item: Debug>;
+
+    type B: Iterator<Item: 'static>;
+}
+
+pub struct S1;
+impl Case1 for S1 {
+    type A = Empty<String>;
+    type B = Range<u16>;
+}
+
+// Ensure we don't have existential desugaring:
+
+pub trait Foo { type Out: Baz<Assoc: Default>; }
+pub trait Baz { type Assoc; }
+
+#[derive(Default)]
+struct S2;
+#[derive(Default)]
+struct S3;
+struct S4;
+struct S5;
+struct S6;
+struct S7;
+
+impl Foo for S6 { type Out = S4; }
+impl Foo for S7 { type Out = S5; }
+
+impl Baz for S4 { type Assoc = S2; }
+impl Baz for S5 { type Assoc = S3; }
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs
new file mode 100644
index 00000000000..bee56d6f689
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/duplicate.rs
@@ -0,0 +1,161 @@
+// compile-fail
+// ignore-tidy-linelength
+// error-pattern:could not find defining uses
+
+#![feature(associated_type_bounds)]
+#![feature(existential_type)]
+#![feature(impl_trait_in_bindings)]
+#![feature(untagged_unions)]
+
+use std::iter;
+
+struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI4: Iterator<Item: Copy, Item: Send>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRS1: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRS2: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRS3: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr
new file mode 100644
index 00000000000..fbf02ddc703
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/duplicate.stderr
@@ -0,0 +1,627 @@
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:12:36
+   |
+LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:14:36
+   |
+LL | struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:16:39
+   |
+LL | struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+   |                        -------------  ^^^^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:18:45
+   |
+LL | struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:20:45
+   |
+LL | struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:22:48
+   |
+LL | struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+   |                                 -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:25:34
+   |
+LL | enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:27:34
+   |
+LL | enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:29:37
+   |
+LL | enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
+   |                      -------------  ^^^^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:31:43
+   |
+LL | enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:33:43
+   |
+LL | enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:35:46
+   |
+LL | enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
+   |                               -------------  ^^^^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:38:35
+   |
+LL | union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:40:35
+   |
+LL | union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:42:38
+   |
+LL | union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+   |                       -------------  ^^^^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:44:44
+   |
+LL | union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:46:44
+   |
+LL | union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:48:47
+   |
+LL | union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+   |                                -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:51:32
+   |
+LL | fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
+   |                    ----------  ^^^^^^^^^^ re-bound here
+   |                    |
+   |                    `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:53:32
+   |
+LL | fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
+   |                    ----------  ^^^^^^^^^^ re-bound here
+   |                    |
+   |                    `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:55:35
+   |
+LL | fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
+   |                    -------------  ^^^^^^^^^^^^^ re-bound here
+   |                    |
+   |                    `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:57:43
+   |
+LL | fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:59:43
+   |
+LL | fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:61:46
+   |
+LL | fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
+   |                               -------------  ^^^^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:70:40
+   |
+LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:72:40
+   |
+LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:74:43
+   |
+LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
+   |                            -------------  ^^^^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:64:42
+   |
+LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:66:42
+   |
+LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:68:45
+   |
+LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
+   |                              -------------  ^^^^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:77:39
+   |
+LL | const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+   |                           ----------  ^^^^^^^^^^ re-bound here
+   |                           |
+   |                           `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:79:39
+   |
+LL | const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+   |                           ----------  ^^^^^^^^^^ re-bound here
+   |                           |
+   |                           `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:81:42
+   |
+LL | const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+   |                           -------------  ^^^^^^^^^^^^^ re-bound here
+   |                           |
+   |                           `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:83:40
+   |
+LL | static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:85:40
+   |
+LL | static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:87:43
+   |
+LL | static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+   |                            -------------  ^^^^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:90:46
+   |
+LL | fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:92:46
+   |
+LL | fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:94:49
+   |
+LL | fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
+   |                                  -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:97:35
+   |
+LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:99:35
+   |
+LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:101:38
+   |
+LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
+   |                       -------------  ^^^^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:103:44
+   |
+LL | type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:105:44
+   |
+LL | type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:107:47
+   |
+LL | type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
+   |                                -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:110:1
+   |
+LL | existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:110:48
+   |
+LL | existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
+   |                                    ----------  ^^^^^^^^^^ re-bound here
+   |                                    |
+   |                                    `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:112:1
+   |
+LL | existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:112:48
+   |
+LL | existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
+   |                                    ----------  ^^^^^^^^^^ re-bound here
+   |                                    |
+   |                                    `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:114:1
+   |
+LL | existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:114:51
+   |
+LL | existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
+   |                                    -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                    |
+   |                                    `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:116:1
+   |
+LL | existential type ETAI4: Iterator<Item: Copy, Item: Send>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:116:46
+   |
+LL | existential type ETAI4: Iterator<Item: Copy, Item: Send>;
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:118:1
+   |
+LL | existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:118:46
+   |
+LL | existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:120:1
+   |
+LL | existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:120:49
+   |
+LL | existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
+   |                                  -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:123:36
+   |
+LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:125:36
+   |
+LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:127:39
+   |
+LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
+   |                        -------------  ^^^^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:129:34
+   |
+LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:131:34
+   |
+LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:133:37
+   |
+LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
+   |                      -------------  ^^^^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:135:45
+   |
+LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:137:45
+   |
+LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:139:48
+   |
+LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
+   |                                 -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:141:46
+   |
+LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:143:46
+   |
+LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:145:49
+   |
+LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
+   |                                  -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:147:43
+   |
+LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:149:43
+   |
+LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:151:46
+   |
+LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
+   |                               -------------  ^^^^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:154:40
+   |
+LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:156:44
+   |
+LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:158:43
+   |
+LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
+   |                            -------------  ^^^^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: aborting due to 93 previous errors
+
+For more information about this error, try `rustc --explain E0719`.
diff --git a/src/test/ui/associated-type-bounds/dyn-existential-type.rs b/src/test/ui/associated-type-bounds/dyn-existential-type.rs
new file mode 100644
index 00000000000..dc0afaa934a
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/dyn-existential-type.rs
@@ -0,0 +1,67 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(existential_type)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+type Et1 = Box<dyn Tr1<As1: Copy>>;
+fn def_et1() -> Et1 { Box::new(S1) }
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+type Et2 = Box<dyn Tr1<As1: 'static>>;
+fn def_et2() -> Et2 { Box::new(S1) }
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+type Et3 = Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>>;
+fn def_et3() -> Et3 {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    Box::new(A)
+}
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+type Et4 = Box<dyn Tr1<As1: for<'a> Tr2<'a>>>;
+fn def_et4() -> Et4 {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    Box::new(A)
+}
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/dyn-lcsit.rs b/src/test/ui/associated-type-bounds/dyn-lcsit.rs
new file mode 100644
index 00000000000..439304fd309
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/dyn-lcsit.rs
@@ -0,0 +1,69 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(impl_trait_in_bindings)]
+
+#![allow(non_upper_case_globals)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+#[derive(Copy, Clone)]
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+const cdef_et1: &dyn Tr1<As1: Copy> = &S1;
+const sdef_et1: &dyn Tr1<As1: Copy> = &S1;
+pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); }
+
+const cdef_et2: &(dyn Tr1<As1: 'static> + Sync) = &S1;
+static sdef_et2: &(dyn Tr1<As1: 'static> + Sync) = &S1;
+pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); }
+
+const cdef_et3: &dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    &A
+};
+pub fn use_et3() {
+    let _0 = cdef_et3.mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+const cdef_et4: &(dyn Tr1<As1: for<'a> Tr2<'a>> + Sync) = {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    &A
+};
+static sdef_et4: &(dyn Tr1<As1: for<'a> Tr2<'a>> + Sync) = cdef_et4;
+pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs b/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs
new file mode 100644
index 00000000000..f22a6c44cb8
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs
@@ -0,0 +1,73 @@
+// run-pass
+
+// FIXME: uncomment let binding types below when `impl_trait_in_bindings` feature is fixed.
+
+#![feature(associated_type_bounds)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+fn def_et1() -> Box<dyn Tr1<As1: Copy>> {
+    let x /* : Box<dyn Tr1<As1: Copy>> */ = Box::new(S1);
+    x
+}
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+fn def_et2() -> Box<dyn Tr1<As1: Send + 'static>> {
+    let x /* : Box<dyn Tr1<As1: Send + 'static>> */ = Box::new(S1);
+    x
+}
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+fn def_et3() -> Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>> {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    let x /* : Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>> */
+        = Box::new(A);
+    x
+}
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+fn def_et4() -> Box<dyn Tr1<As1: for<'a> Tr2<'a>>> {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    let x /* : Box<dyn Tr1<As1: for<'a> Tr2<'a>>> */ = Box::new(A);
+    x
+}
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs b/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs
new file mode 100644
index 00000000000..1b3e978594d
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs
@@ -0,0 +1,26 @@
+// compile-pass
+
+#![feature(associated_type_bounds)]
+
+trait Tr1: Sized { type As1; }
+trait Tr2<'a>: Sized { type As2; }
+
+trait ObjTr1 { fn foo() -> Self where Self: Tr1<As1: Copy>; }
+fn _assert_obj_safe_1(_: Box<dyn ObjTr1>) {}
+
+trait ObjTr2 { fn foo() -> Self where Self: Tr1<As1: 'static>; }
+fn _assert_obj_safe_2(_: Box<dyn ObjTr2>) {}
+
+trait ObjTr3 { fn foo() -> Self where Self: Tr1<As1: Into<u8> + 'static + Copy>; }
+fn _assert_obj_safe_3(_: Box<dyn ObjTr3>) {}
+
+trait ObjTr4 { fn foo() -> Self where Self: Tr1<As1: for<'a> Tr2<'a>>; }
+fn _assert_obj_safe_4(_: Box<dyn ObjTr4>) {}
+
+trait ObjTr5 { fn foo() -> Self where for<'a> Self: Tr1<As1: Tr2<'a>>; }
+fn _assert_obj_safe_5(_: Box<dyn ObjTr5>) {}
+
+trait ObjTr6 { fn foo() -> Self where Self: for<'a> Tr1<As1: Tr2<'a, As2: for<'b> Tr2<'b>>>; }
+fn _assert_obj_safe_6(_: Box<dyn ObjTr6>) {}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/enum-bounds.rs b/src/test/ui/associated-type-bounds/enum-bounds.rs
new file mode 100644
index 00000000000..a6b0bb7070b
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/enum-bounds.rs
@@ -0,0 +1,122 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+trait Tr3 { type As3; }
+trait Tr4<'a> { type As4; }
+trait Tr5 { type As5; }
+
+impl Tr1 for &str { type As1 = bool; }
+impl Tr2 for bool { type As2 = u8; }
+impl Tr3 for u8 { type As3 = fn() -> u8; }
+impl Tr1 for () { type As1 = (usize,); }
+impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
+impl Tr5 for bool { type As5 = u16; }
+
+enum En1<T: Tr1<As1: Tr2>> {
+    Outest(T),
+    Outer(T::As1),
+    Inner(<T::As1 as Tr2>::As2),
+}
+
+fn wrap_en1_1<T>(x: T) -> En1<T> where T: Tr1, T::As1: Tr2 {
+    En1::Outest(x)
+}
+
+fn wrap_en1_2<T>(x: T::As1) -> En1<T> where T: Tr1, T::As1: Tr2 {
+    En1::Outer(x)
+}
+
+fn wrap_en1_3<T>(x: <T::As1 as Tr2>::As2) -> En1<T> where T: Tr1, T::As1: Tr2 {
+    En1::Inner(x)
+}
+
+enum En2<T: Tr1<As1: Tr2<As2: Tr3>>> {
+    V0(T),
+    V1(T::As1),
+    V2(<T::As1 as Tr2>::As2),
+    V3(<<T::As1 as Tr2>::As2 as Tr3>::As3),
+}
+
+enum En3<T: Tr1<As1: 'static>> {
+    V0(T),
+    V1(&'static T::As1),
+}
+
+enum En4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
+    V0(&'x1 <T::As1 as Tr4<'x1>>::As4),
+    V1(&'x2 <T::As1 as Tr4<'x2>>::As4),
+}
+
+enum _En5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
+    _V0(&'x1 <T::As1 as Tr4<'x1>>::As4),
+    _V1(&'x2 <T::As1 as Tr4<'x2>>::As4),
+}
+
+enum En6<T>
+where
+    T: Tr1<As1: Tr2 + 'static + Tr5>,
+{
+    V0(T),
+    V1(<T::As1 as Tr2>::As2),
+    V2(&'static T::As1),
+    V3(<T::As1 as Tr5>::As5),
+}
+
+enum _En7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1<As1: Tr2>,
+{
+    V0(&'a T),
+    V1(&'b <T::As1 as Tr2>::As2),
+}
+
+fn _make_en7<'a, 'b, T>(x: _En7<'a, 'b, T>)
+where
+    T: Tr1<As1: Tr2>,
+{
+    match x {
+        _En7::V0(x) => {
+            let _: &'a T = &x;
+        },
+        _En7::V1(_) => {},
+    }
+}
+
+enum EnSelf<T> where Self: Tr1<As1: Tr2> {
+    V0(T),
+    V1(<Self as Tr1>::As1),
+    V2(<<Self as Tr1>::As1 as Tr2>::As2),
+}
+
+impl Tr1 for EnSelf<&'static str> { type As1 = bool; }
+
+fn main() {
+    if let En1::Outest("foo") = wrap_en1_1::<_>("foo") {} else { panic!() };
+    if let En1::Outer(true) = wrap_en1_2::<&str>(true) {} else { panic!() };
+    if let En1::Inner(24u8) = wrap_en1_3::<&str>(24u8) {} else { panic!() };
+
+    let _ = En2::<_>::V0("151571");
+    let _ = En2::<&str>::V1(false);
+    let _ = En2::<&str>::V2(42u8);
+    let _ = En2::<&str>::V3(|| 12u8);
+
+    let _ = En3::<_>::V0("deadbeef");
+    let _ = En3::<&str>::V1(&true);
+
+    let f1 = (1,);
+    let f2 = (2,);
+    let _ = En4::<()>::V0(&f1.0);
+    let _ = En4::<()>::V1(&f2.0);
+
+    let _ = En6::<_>::V0("bar");
+    let _ = En6::<&str>::V1(24u8);
+    let _ = En6::<&str>::V2(&false);
+    let _ = En6::<&str>::V3(12u16);
+
+    let _ = EnSelf::<_>::V0("foo");
+    let _ = EnSelf::<&'static str>::V1(true);
+    let _ = EnSelf::<&'static str>::V2(24u8);
+}
diff --git a/src/test/ui/associated-type-bounds/existential-type.rs b/src/test/ui/associated-type-bounds/existential-type.rs
new file mode 100644
index 00000000000..87046aec5c4
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/existential-type.rs
@@ -0,0 +1,67 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(existential_type)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } }
+
+existential type Et1: Tr1<As1: Copy>;
+fn def_et1() -> Et1 { S1 }
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+existential type Et2: Tr1<As1: 'static>;
+fn def_et2() -> Et2 { S1 }
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+existential type Et3: Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>;
+fn def_et3() -> Et3 {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(self) -> Self::As1 { 0..10 }
+    };
+    A
+}
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+existential type Et4: Tr1<As1: for<'a> Tr2<'a>>;
+fn def_et4() -> Et4 {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    A
+}
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/fn-apit.rs b/src/test/ui/associated-type-bounds/fn-apit.rs
new file mode 100644
index 00000000000..7e208b4e70d
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-apit.rs
@@ -0,0 +1,58 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+fn apit_bound(beta: impl Beta<Gamma: Alpha>) -> usize {
+    desugared_bound(beta)
+}
+
+fn apit_bound_region(beta: impl Beta<Gamma: 'static>) -> usize {
+    desugared_bound_region(beta)
+}
+
+fn apit_bound_multi(
+    beta: impl Copy + Beta<Gamma: Alpha + 'static + Delta>
+) -> usize {
+    desugared_bound_multi(beta)
+}
+
+fn apit_bound_region_forall(
+    beta: impl Beta<Gamma: Copy + for<'a> Epsilon<'a>>
+) -> usize {
+    desugared_bound_region_forall(beta)
+}
+
+fn apit_bound_region_forall2(
+    beta: impl Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>
+) -> usize {
+    desugared_bound_region_forall2(beta)
+}
+
+fn apit_bound_nested(
+    beta: impl Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn apit_bound_nested2(
+    beta: impl Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let _gamma = beta.gamma();
+
+    assert_eq!(42, apit_bound(beta));
+    assert_eq!(24, apit_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, apit_bound_multi(beta));
+    assert_eq!(7331 * 2, apit_bound_region_forall(beta));
+    assert_eq!(42 + 1337, apit_bound_nested(beta));
+    assert_eq!(42 + 1337, apit_bound_nested2(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-aux.rs b/src/test/ui/associated-type-bounds/fn-aux.rs
new file mode 100644
index 00000000000..434bdbe996c
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-aux.rs
@@ -0,0 +1,12 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+fn main() {
+    desugared();
+}
diff --git a/src/test/ui/associated-type-bounds/fn-dyn-apit.rs b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs
new file mode 100644
index 00000000000..9ff4a50e1e6
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs
@@ -0,0 +1,60 @@
+// run-pass
+// aux-build:fn-dyn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_dyn_aux;
+
+use fn_dyn_aux::*;
+
+// ATB, APIT (dyn trait):
+
+fn dyn_apit_bound(beta: &dyn Beta<Gamma: Alpha>) -> usize {
+    desugared_bound(beta)
+}
+
+fn dyn_apit_bound_region(beta: &dyn Beta<Gamma: 'static>) -> usize {
+    desugared_bound_region(beta)
+}
+
+fn dyn_apit_bound_multi(
+    beta: &(dyn Beta<Gamma: Alpha + 'static + Delta> + Send)
+) -> usize {
+    desugared_bound_multi(beta)
+}
+
+fn dyn_apit_bound_region_forall(
+    beta: &dyn Beta<Gamma: Copy + for<'a> Epsilon<'a>>
+) -> usize {
+    desugared_bound_region_forall(beta)
+}
+
+fn dyn_apit_bound_region_forall2(
+    beta: &dyn Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>
+) -> usize {
+    desugared_bound_region_forall2(beta)
+}
+
+fn dyn_apit_bound_nested(
+    beta: &dyn Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn dyn_apit_bound_nested2(
+    beta: &dyn Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let _gamma = beta.gamma();
+
+    assert_eq!(42, dyn_apit_bound(&beta));
+    assert_eq!(24, dyn_apit_bound_region(&beta));
+    assert_eq!(42 + 24 + 1337, dyn_apit_bound_multi(&beta));
+    assert_eq!(7331 * 2, dyn_apit_bound_region_forall(&beta));
+    assert_eq!(42 + 1337, dyn_apit_bound_nested(&beta));
+    assert_eq!(42 + 1337, dyn_apit_bound_nested2(&beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-inline.rs b/src/test/ui/associated-type-bounds/fn-inline.rs
new file mode 100644
index 00000000000..7b188763b7a
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-inline.rs
@@ -0,0 +1,62 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+// ATB, Type parameters, Inline bounds:
+
+fn inline_bound<B: Beta<Gamma: Alpha>>(beta: B) -> usize {
+    desugared_bound(beta)
+}
+
+fn inline_bound_region<B: Beta<Gamma: 'static>>(beta: B) -> usize {
+    desugared_bound_region(beta)
+}
+
+fn inline_bound_multi<B: Copy + Beta<Gamma: Alpha + 'static + Delta>>(
+    beta: B
+) -> usize {
+    desugared_bound_multi(beta)
+}
+
+fn inline_bound_region_specific<'a, B: Beta<Gamma: 'a + Epsilon<'a>>>(
+    gamma: &'a B::Gamma
+) -> usize {
+    desugared_bound_region_specific::<B>(gamma)
+}
+
+fn inline_bound_region_forall<B: Beta<Gamma: Copy + for<'a> Epsilon<'a>>>(
+    beta: B
+) -> usize {
+    desugared_bound_region_forall(beta)
+}
+
+fn inline_bound_region_forall2<B: Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>>(
+    beta: B
+) -> usize {
+    desugared_bound_region_forall2(beta)
+}
+
+fn inline_bound_nested<B: Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>>(
+    beta: B
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, inline_bound(beta));
+    assert_eq!(24, inline_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, inline_bound_multi(beta));
+    assert_eq!(7331, inline_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, inline_bound_region_forall(beta));
+    // FIXME: requires lazy normalization.
+    // assert_eq!(7331 * 2, inline_bound_region_forall2(beta));
+    assert_eq!(42 + 1337, inline_bound_nested(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-where.rs b/src/test/ui/associated-type-bounds/fn-where.rs
new file mode 100644
index 00000000000..60d7149a56f
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-where.rs
@@ -0,0 +1,78 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+// ATB, Type parameters, Where-clauses:
+
+fn where_bound<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Alpha>
+{
+    desugared_bound(beta)
+}
+
+fn where_bound_region<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: 'static>
+{
+    desugared_bound_region(beta)
+}
+
+fn where_bound_multi<B>(beta: B) -> usize
+where
+    B: Copy + Beta<Gamma: Alpha + 'static + Delta>,
+{
+    desugared_bound_multi(beta)
+}
+
+fn where_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize
+where
+    B: Beta<Gamma: 'a + Epsilon<'a>>,
+{
+    desugared_bound_region_specific::<B>(gamma)
+}
+
+fn where_bound_region_forall<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Copy + for<'a> Epsilon<'a>>,
+{
+    desugared_bound_region_forall(beta)
+}
+
+fn where_bound_region_forall2<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>,
+{
+    desugared_bound_region_forall2(beta)
+}
+
+fn where_contraint_region_forall<B>(beta: B) -> usize
+where
+    for<'a> &'a B: Beta<Gamma: Alpha>,
+{
+    desugared_contraint_region_forall(beta)
+}
+
+fn where_bound_nested<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>,
+{
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, where_bound(beta));
+    assert_eq!(24, where_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, where_bound_multi(beta));
+    assert_eq!(7331, where_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, where_bound_region_forall::<BetaType>(beta));
+    assert_eq!(42 + 1337, where_bound_nested::<BetaType>(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-wrap-apit.rs b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs
new file mode 100644
index 00000000000..23790d416e1
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs
@@ -0,0 +1,64 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+// ATB, APIT + Wrap:
+
+struct Wrap<T>(T);
+
+fn wrap_apit_bound(beta: Wrap<impl Beta<Gamma: Alpha>>) -> usize {
+    desugared_bound(beta.0)
+}
+
+fn wrap_apit_bound_region(beta: Wrap<impl Beta<Gamma: 'static>>) -> usize {
+    desugared_bound_region(beta.0)
+}
+
+fn wrap_apit_bound_multi(
+    beta: Wrap<impl Copy + Beta<Gamma: Alpha + 'static + Delta>>
+) -> usize {
+    desugared_bound_multi(beta.0)
+}
+
+fn wrap_apit_bound_region_forall(
+    beta: Wrap<impl Beta<Gamma: Copy + for<'a> Epsilon<'a>>>
+) -> usize {
+    desugared_bound_region_forall(beta.0)
+}
+
+fn wrap_apit_bound_region_forall2(
+    beta: Wrap<impl Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>>
+) -> usize {
+    desugared_bound_region_forall2(beta.0)
+}
+
+fn wrap_apit_bound_nested(
+    beta: Wrap<impl Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>>
+) -> usize {
+    desugared_bound_nested(beta.0)
+}
+
+fn wrap_apit_bound_nested2(
+    beta: Wrap<impl Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>>
+) -> usize {
+    desugared_bound_nested(beta.0)
+}
+
+fn main() {
+    let beta = BetaType;
+    let _gamma = beta.gamma();
+
+    assert_eq!(42, wrap_apit_bound(Wrap(beta)));
+    assert_eq!(24, wrap_apit_bound_region(Wrap(beta)));
+    assert_eq!(42 + 24 + 1337, wrap_apit_bound_multi(Wrap(beta)));
+    assert_eq!(7331 * 2, wrap_apit_bound_region_forall(Wrap(beta)));
+    // FIXME: requires lazy normalization.
+    // assert_eq!(7331 * 2, wrap_apit_bound_region_forall2(Wrap(beta)));
+    assert_eq!(42 + 1337, wrap_apit_bound_nested(Wrap(beta)));
+    assert_eq!(42 + 1337, wrap_apit_bound_nested2(Wrap(beta)));
+}
diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.rs b/src/test/ui/associated-type-bounds/implied-region-constraints.rs
new file mode 100644
index 00000000000..4dbaab50a61
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/implied-region-constraints.rs
@@ -0,0 +1,47 @@
+// compile-fail
+
+#![feature(associated_type_bounds)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+
+struct St<'a, 'b, T: Tr1<As1: Tr2>> { // `T: 'b` is *not* implied!
+    f0: &'a T, // `T: 'a` is implied.
+    f1: &'b <T::As1 as Tr2>::As2, // `<T::As1 as Tr2>::As2: 'a` is implied.
+}
+
+fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    // This should fail because `T: 'b` is not implied from `WF(St<'a, 'b, T>)`.
+    let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
+    //~^ ERROR lifetime mismatch [E0623]
+}
+
+enum En7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    V0(&'a T),
+    V1(&'b <T::As1 as Tr2>::As2),
+}
+
+fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    match x {
+        En7::V0(x) => {
+            // Also fails for the same reason as above:
+            let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
+            //~^ ERROR lifetime mismatch [E0623]
+        },
+        En7::V1(_) => {},
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.stderr b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr
new file mode 100644
index 00000000000..b07b20272a8
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr
@@ -0,0 +1,25 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/implied-region-constraints.rs:19:64
+   |
+LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
+   |                          -------------
+   |                          |
+   |                          this type is declared with multiple lifetimes...
+...
+LL |     let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
+   |                                                                ^^^^^ ...but data with one lifetime flows into the other here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/implied-region-constraints.rs:40:72
+   |
+LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
+   |                           --------------
+   |                           |
+   |                           this type is declared with multiple lifetimes...
+...
+LL |             let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
+   |                                                                        ^^ ...but data with one lifetime flows into the other here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs
new file mode 100644
index 00000000000..1257dc6e94b
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/inside-adt.rs
@@ -0,0 +1,36 @@
+// compile-fail
+// ignore-tidy-linelength
+// error-pattern:could not find defining uses
+
+#![feature(associated_type_bounds)]
+#![feature(untagged_unions)]
+
+struct S1 { f: dyn Iterator<Item: Copy> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+struct S2 { f: Box<dyn Iterator<Item: Copy>> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+struct S3 { f: dyn Iterator<Item: 'static> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+
+enum E1 { V(dyn Iterator<Item: Copy>) }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+enum E3 { V(dyn Iterator<Item: 'static>) }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+
+union U1 { f: dyn Iterator<Item: Copy> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+union U2 { f: Box<dyn Iterator<Item: Copy>> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+union U3 { f: dyn Iterator<Item: 'static> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr
new file mode 100644
index 00000000000..7bdd71b8296
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/inside-adt.stderr
@@ -0,0 +1,79 @@
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:8:29
+   |
+LL | struct S1 { f: dyn Iterator<Item: Copy> }
+   |                             ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:11:33
+   |
+LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> }
+   |                                 ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:14:29
+   |
+LL | struct S3 { f: dyn Iterator<Item: 'static> }
+   |                             ^^^^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:18:26
+   |
+LL | enum E1 { V(dyn Iterator<Item: Copy>) }
+   |                          ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:21:30
+   |
+LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
+   |                              ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:24:26
+   |
+LL | enum E3 { V(dyn Iterator<Item: 'static>) }
+   |                          ^^^^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:28:28
+   |
+LL | union U1 { f: dyn Iterator<Item: Copy> }
+   |                            ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:31:32
+   |
+LL | union U2 { f: Box<dyn Iterator<Item: Copy>> }
+   |                                ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:34:28
+   |
+LL | union U3 { f: dyn Iterator<Item: 'static> }
+   |                            ^^^^^^^^^^^^^
+
+error[E0601]: `main` function not found in crate `inside_adt`
+   |
+   = note: consider adding a `main` function to `$DIR/inside-adt.rs`
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: aborting due to 19 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/associated-type-bounds/lcsit.rs b/src/test/ui/associated-type-bounds/lcsit.rs
new file mode 100644
index 00000000000..85b6e804b4e
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/lcsit.rs
@@ -0,0 +1,78 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(impl_trait_in_bindings)]
+
+#![allow(non_upper_case_globals)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+#[derive(Copy, Clone)]
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+const cdef_et1: impl Copy + Tr1<As1: Copy> = {
+    let x: impl Copy + Tr1<As1: Copy> = S1;
+    x
+};
+static sdef_et1: impl Copy + Tr1<As1: Copy> = cdef_et1;
+pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); }
+
+const cdef_et2: impl Tr1<As1: 'static> = {
+    let x: impl Tr1<As1: 'static> = S1;
+    x
+};
+static sdef_et2: impl Tr1<As1: 'static> = cdef_et2;
+pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); }
+
+const cdef_et3: impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    let x: impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = A;
+    x
+};
+pub fn use_et3() {
+    let _0 = cdef_et3.mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+const cdef_et4: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    let x: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = A;
+    x
+};
+
+static sdef_et4: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = cdef_et4;
+pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
new file mode 100644
index 00000000000..25c2c2916f3
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
@@ -0,0 +1,25 @@
+// compile-fail
+
+#![feature(associated_type_bounds)]
+
+use std::fmt::Debug;
+
+trait Lam<Binder> { type App; }
+
+fn nested_bounds<_0, _1, _2, D>()
+where
+    D: Clone + Iterator<Item: Send + for<'a> Iterator<Item: for<'b> Lam<&'a &'b u8, App = _0>>>,
+    //~^ ERROR nested quantification of lifetimes [E0316]
+    _0: Debug,
+{}
+
+fn nested_bounds_desugared<_0, _1, _2, D>()
+where
+    D: Clone + Iterator<Item = _2>,
+    _2: Send + for<'a> Iterator,
+    for<'a> <_2 as Iterator>::Item: for<'b> Lam<&'a &'b u8, App = _0>,
+    //~^ ERROR nested quantification of lifetimes [E0316]
+    _0: Debug,
+{}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
new file mode 100644
index 00000000000..44fa9e89d35
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
@@ -0,0 +1,9 @@
+error[E0316]: nested quantification of lifetimes
+  --> $DIR/nested-lifetime-bounds.rs:20:37
+   |
+LL |     for<'a> <_2 as Iterator>::Item: for<'b> Lam<&'a &'b u8, App = _0>,
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0316`.
diff --git a/src/test/ui/associated-type-bounds/rpit.rs b/src/test/ui/associated-type-bounds/rpit.rs
new file mode 100644
index 00000000000..7b640d5a457
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/rpit.rs
@@ -0,0 +1,64 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } }
+
+fn def_et1() -> impl Tr1<As1: Copy> { S1 }
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+fn def_et2() -> impl Tr1<As1: 'static> { S1 }
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+fn def_et3() -> impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(self) -> Self::As1 { 0..10 }
+    };
+    A
+}
+
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+fn def_et4() -> impl Tr1<As1: for<'a> Tr2<'a>> {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    A
+}
+
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/struct-bounds.rs b/src/test/ui/associated-type-bounds/struct-bounds.rs
new file mode 100644
index 00000000000..2d189cd6672
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/struct-bounds.rs
@@ -0,0 +1,115 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+trait Tr3 {}
+trait Tr4<'a> { type As4; }
+trait Tr5 { type As5; }
+
+impl Tr1 for &str { type As1 = bool; }
+impl Tr2 for bool { type As2 = u8; }
+impl Tr3 for u8 {}
+impl Tr1 for () { type As1 = (usize,); }
+impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
+impl Tr5 for bool { type As5 = u16; }
+
+struct St1<T: Tr1<As1: Tr2>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+fn unwrap_1_st1<T: Tr1<As1: Tr2>>(x: St1<T>) -> (T, T::As1, <T::As1 as Tr2>::As2) {
+    (x.outest, x.outer, x.inner)
+}
+
+fn unwrap_2_st1<T>(x: St1<T>) -> (T, T::As1, <T::As1 as Tr2>::As2)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    unwrap_1_st1(x)
+}
+
+struct St2<T: Tr1<As1: Tr2<As2: Tr3>>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+struct St3<T: Tr1<As1: 'static>> {
+    outest: T,
+    outer: &'static T::As1,
+}
+
+struct St4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+struct St5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+struct St6<T>
+where
+    T: Tr1<As1: Tr2 + 'static + Tr5>,
+{
+    f0: T,
+    f1: <T::As1 as Tr2>::As2,
+    f2: &'static T::As1,
+    f3: <T::As1 as Tr5>::As5,
+}
+
+struct St7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1<As1: Tr2>,
+{
+    f0: &'a T,
+    f1: &'b <T::As1 as Tr2>::As2,
+}
+
+fn _use_st7<'a, 'b, T>(x: St7<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    let _: &'a T = &x.f0;
+}
+
+struct StSelf<T> where Self: Tr1<As1: Tr2> {
+    f2: <<Self as Tr1>::As1 as Tr2>::As2,
+}
+
+impl Tr1 for StSelf<&'static str> { type As1 = bool; }
+
+fn main() {
+    let st1 = St1 { outest: "foo", outer: true, inner: 42u8 };
+    assert_eq!(("foo", true, 42), unwrap_1_st1(st1));
+
+    let _ = St2 { outest: "foo", outer: true, inner: 42u8 };
+
+    let _ = St3 { outest: "foo", outer: &true };
+
+    let f1 = (1,);
+    let f2 = (2,);
+    let st4 = St4::<()> { f1: &f1.0, f2: &f2.0, };
+    assert_eq!((&1, &2), (st4.f1, st4.f2));
+
+    // FIXME: requires lazy normalization.
+    /*
+    let f1 = (1,);
+    let f2 = (2,);
+    let st5 = St5::<()> { f1: &f1.0, f2: &f2.0, };
+    assert_eq!((&1, &2), (st5.f1, st5.f2));
+    */
+
+    let st6 = St6 { f0: "bar", f1: 24u8, f2: &true, f3: 12u16, };
+    assert_eq!(("bar", 24, &true, 12), (st6.f0, st6.f1, st6.f2, st6.f3));
+
+    let stself = StSelf::<&'static str> { f2: 42u8 };
+    assert_eq!(stself.f2, 42u8);
+}
diff --git a/src/test/ui/associated-type-bounds/trait-params.rs b/src/test/ui/associated-type-bounds/trait-params.rs
new file mode 100644
index 00000000000..a9081d50cfc
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/trait-params.rs
@@ -0,0 +1,116 @@
+// compile-pass
+
+#![feature(associated_type_bounds)]
+
+use std::iter::Once;
+use std::ops::Range;
+
+pub trait Three { type A; type B; type C; }
+pub fn assert_three<T: ?Sized + Three>() {}
+pub fn assert_iterator<T: Iterator>() {}
+pub fn assert_copy<T: Copy>() {}
+pub fn assert_static<T: 'static>() {}
+pub fn assert_send<T: Send>() {}
+pub fn assert_forall_into<T: for<'a> Into<&'a u8>>() {}
+
+struct A; struct B;
+impl<'a> Into<&'a u8> for A { fn into(self) -> &'a u8 { &0 } }
+impl Three for B { type A = Range<u8>; type B = Range<u8>; type C = Range<u8>; }
+
+trait Case1<A, B, C, D, E>
+where
+    A: Iterator<Item: Copy>,
+    B: Iterator<Item: 'static>,
+    C: Iterator<Item: 'static + Copy + Send>,
+    D: Iterator<Item: for<'a> Into<&'a u8>>,
+    E: Three<A: Iterator<Item: Copy>, B: Iterator<Item: Copy>, C: Iterator<Item: Copy>>,
+    Self: Three<A: 'static, B: Copy, C: Send>,
+{
+    fn _a() {
+        assert_iterator::<A>();
+        assert_copy::<A::Item>();
+    }
+    fn _b() {
+        assert_iterator::<B>();
+        assert_static::<B::Item>();
+    }
+    fn _c() {
+        assert_iterator::<C>();
+        assert_copy::<C::Item>();
+        assert_static::<C::Item>();
+        assert_send::<C::Item>();
+    }
+    fn _d() {
+        assert_iterator::<D>();
+        assert_forall_into::<D::Item>();
+    }
+    fn _e() {
+        assert_three::<E>();
+        assert_iterator::<E::A>();
+        assert_iterator::<E::B>();
+        assert_iterator::<E::C>();
+        assert_copy::<<E::A as Iterator>::Item>();
+        assert_copy::<<E::B as Iterator>::Item>();
+        assert_copy::<<E::C as Iterator>::Item>();
+    }
+    fn _self() {
+        assert_three::<Self>();
+        assert_copy::<Self::B>();
+        assert_static::<Self::A>();
+        assert_send::<Self::C>();
+    }
+}
+
+struct DataCase1;
+impl Three for DataCase1 { type A = u8; type B = u8; type C = u8; }
+impl Case1<Range<u8>, Range<u8>, Range<u8>, Once<A>, B> for DataCase1 {}
+
+trait Case2<
+    A: Iterator<Item: Copy>,
+    B: Iterator<Item: 'static>,
+    C: Iterator<Item: 'static + Copy + Send>,
+    D: Iterator<Item: for<'a> Into<&'a u8>>,
+    E: Three<A: Iterator<Item: Copy>, B: Iterator<Item: Copy>, C: Iterator<Item: Copy>>,
+>:
+    Three<A: 'static, B: Copy, C: Send>
+{
+    fn _a() {
+        assert_iterator::<A>();
+        assert_copy::<A::Item>();
+    }
+    fn _b() {
+        assert_iterator::<B>();
+        assert_static::<B::Item>();
+    }
+    fn _c() {
+        assert_iterator::<C>();
+        assert_copy::<C::Item>();
+        assert_static::<C::Item>();
+        assert_send::<C::Item>();
+    }
+    fn _d() {
+        assert_iterator::<D>();
+        assert_forall_into::<D::Item>();
+    }
+    fn _e() {
+        assert_three::<E>();
+        assert_iterator::<E::A>();
+        assert_iterator::<E::B>();
+        assert_iterator::<E::C>();
+        assert_copy::<<E::A as Iterator>::Item>();
+        assert_copy::<<E::B as Iterator>::Item>();
+        assert_copy::<<E::C as Iterator>::Item>();
+    }
+    fn _self() {
+        assert_three::<Self>();
+        assert_copy::<Self::B>();
+        assert_static::<Self::A>();
+        assert_send::<Self::C>();
+    }
+}
+
+struct DataCase2;
+impl Three for DataCase2 { type A = u8; type B = u8; type C = u8; }
+impl Case2<Range<u8>, Range<u8>, Range<u8>, Once<A>, B> for DataCase2 {}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/type-alias.rs b/src/test/ui/associated-type-bounds/type-alias.rs
new file mode 100644
index 00000000000..1602fdd275a
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/type-alias.rs
@@ -0,0 +1,19 @@
+// compile-pass
+
+#![feature(associated_type_bounds)]
+
+type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+type _TaWhere2<T> where T: Iterator<Item: 'static> = T;
+type _TaWhere3<T> where T: Iterator<Item: 'static> = T;
+type _TaWhere4<T> where T: Iterator<Item: 'static + Copy + Send> = T;
+type _TaWhere5<T> where T: Iterator<Item: for<'a> Into<&'a u8>> = T;
+type _TaWhere6<T> where T: Iterator<Item: Iterator<Item: Copy>> = T;
+
+type _TaInline1<T: Iterator<Item: Copy>> = T;
+type _TaInline2<T: Iterator<Item: 'static>> = T;
+type _TaInline3<T: Iterator<Item: 'static>> = T;
+type _TaInline4<T: Iterator<Item: 'static + Copy + Send>> = T;
+type _TaInline5<T: Iterator<Item: for<'a> Into<&'a u8>>> = T;
+type _TaInline6<T: Iterator<Item: Iterator<Item: Copy>>> = T;
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/type-alias.stderr b/src/test/ui/associated-type-bounds/type-alias.stderr
new file mode 100644
index 00000000000..b93fc393ae3
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/type-alias.stderr
@@ -0,0 +1,97 @@
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:5:25
+   |
+LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(type_alias_bounds)] on by default
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:6:25
+   |
+LL | type _TaWhere2<T> where T: Iterator<Item: 'static> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:7:25
+   |
+LL | type _TaWhere3<T> where T: Iterator<Item: 'static> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:8:25
+   |
+LL | type _TaWhere4<T> where T: Iterator<Item: 'static + Copy + Send> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:9:25
+   |
+LL | type _TaWhere5<T> where T: Iterator<Item: for<'a> Into<&'a u8>> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:10:25
+   |
+LL | type _TaWhere6<T> where T: Iterator<Item: Iterator<Item: Copy>> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:12:20
+   |
+LL | type _TaInline1<T: Iterator<Item: Copy>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:13:20
+   |
+LL | type _TaInline2<T: Iterator<Item: 'static>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:14:20
+   |
+LL | type _TaInline3<T: Iterator<Item: 'static>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:15:20
+   |
+LL | type _TaInline4<T: Iterator<Item: 'static + Copy + Send>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:16:20
+   |
+LL | type _TaInline5<T: Iterator<Item: for<'a> Into<&'a u8>>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:17:20
+   |
+LL | type _TaInline6<T: Iterator<Item: Iterator<Item: Copy>>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs
new file mode 100644
index 00000000000..ce482fff401
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/union-bounds.rs
@@ -0,0 +1,123 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(untagged_unions)]
+
+#![allow(unions_with_drop_fields, unused_assignments)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+trait Tr3 { type As3; }
+trait Tr4<'a> { type As4; }
+trait Tr5 { type As5; }
+
+impl Tr1 for &str { type As1 = bool; }
+impl Tr2 for bool { type As2 = u8; }
+impl Tr3 for u8 { type As3 = fn() -> u8; }
+impl Tr1 for () { type As1 = (usize,); }
+impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
+impl Tr5 for bool { type As5 = u16; }
+
+union Un1<T: Tr1<As1: Tr2>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+union Un2<T: Tr1<As1: Tr2<As2: Tr3>>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+union Un3<T: Tr1<As1: 'static>> {
+    outest: T,
+    outer: &'static T::As1,
+}
+
+union Un4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+union _Un5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+union Un6<T>
+where
+    T: Tr1<As1: Tr2 + 'static + Tr5>,
+{
+    f0: T,
+    f1: <T::As1 as Tr2>::As2,
+    f2: &'static T::As1,
+    f3: <T::As1 as Tr5>::As5,
+}
+
+union _Un7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1<As1: Tr2>,
+{
+    f0: &'a T,
+    f1: &'b <T::As1 as Tr2>::As2,
+}
+
+unsafe fn _use_un7<'a, 'b, T>(x: _Un7<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    let _: &'a T = &x.f0;
+}
+
+union UnSelf<T> where Self: Tr1<As1: Tr2> {
+    f0: T,
+    f1: <Self as Tr1>::As1,
+    f2: <<Self as Tr1>::As1 as Tr2>::As2,
+}
+
+impl Tr1 for UnSelf<&'static str> { type As1 = bool; }
+
+fn main() {
+    let mut un1 = Un1 { outest: "foo" };
+    un1 = Un1 { outer: true };
+    assert_eq!(unsafe { un1.outer }, true);
+    un1 = Un1 { inner: 42u8 };
+    assert_eq!(unsafe { un1.inner }, 42u8);
+
+    let mut un2 = Un2 { outest: "bar" };
+    assert_eq!(unsafe { un2.outest }, "bar");
+    un2 = Un2 { outer: true };
+    assert_eq!(unsafe { un2.outer }, true);
+    un2 = Un2 { inner: 42u8 };
+    assert_eq!(unsafe { un2.inner }, 42u8);
+
+    let mut un3 = Un3 { outest: "baz" };
+    assert_eq!(unsafe { un3.outest }, "baz");
+    un3 = Un3 { outer: &true };
+    assert_eq!(unsafe { *un3.outer }, true);
+
+    let f1 = (1,);
+    let f2 = (2,);
+    let mut un4 = Un4::<()> { f1: &f1.0 };
+    assert_eq!(1, unsafe { *un4.f1 });
+    un4 = Un4 { f2: &f2.0 };
+    assert_eq!(2, unsafe { *un4.f2 });
+
+    let mut un6 = Un6 { f0: "bar" };
+    assert_eq!(unsafe { un6.f0 }, "bar");
+    un6 = Un6 { f1: 24u8 };
+    assert_eq!(unsafe { un6.f1 }, 24u8);
+    un6 = Un6 { f2: &true };
+    assert_eq!(unsafe { un6.f2 }, &true);
+    un6 = Un6 { f3: 12u16 };
+    assert_eq!(unsafe { un6.f3 }, 12u16);
+
+    let mut unself = UnSelf::<_> { f0: "selfish" };
+    assert_eq!(unsafe { unself.f0 }, "selfish");
+    unself = UnSelf { f1: true };
+    assert_eq!(unsafe { unself.f1 }, true);
+    unself = UnSelf { f2: 24u8 };
+    assert_eq!(unsafe { unself.f2 }, 24u8);
+}
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
new file mode 100644
index 00000000000..6b4f5005d48
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
@@ -0,0 +1,71 @@
+#![feature(untagged_unions)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; }
+
+trait _Tr3 {
+    type A: Iterator<Item: Copy>;
+    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+    type B: Iterator<Item: 'static>;
+    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+}
+
+struct _St1<T: Tr1<As1: Tr2>> {
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+enum _En1<T: Tr1<As1: Tr2>> {
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    Outest(T),
+    Outer(T::As1),
+    Inner(<T::As1 as Tr2>::As2),
+}
+
+union _Un1<T: Tr1<As1: Tr2>> {
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+fn _apit(_: impl Tr1<As1: Copy>) {}
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+fn _rpit() -> impl Tr1<As1: Copy> { S1 }
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+const _cdef: impl Tr1<As1: Copy> = S1;
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
+// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
+// const _cdef_dyn: &dyn Tr1<As1: Copy> = &S1;
+
+static _sdef: impl Tr1<As1: Copy> = S1;
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
+// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
+// static _sdef_dyn: &dyn Tr1<As1: Copy> = &S1;
+
+fn main() {
+    let _: impl Tr1<As1: Copy> = S1;
+    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    //~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
+    // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
+    // let _: &dyn Tr1<As1: Copy> = &S1;
+}
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
new file mode 100644
index 00000000000..9b83c1cfb33
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
@@ -0,0 +1,132 @@
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:12:22
+   |
+LL |     type A: Iterator<Item: Copy>;
+   |                      ^^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:15:22
+   |
+LL |     type B: Iterator<Item: 'static>;
+   |                      ^^^^^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:19:20
+   |
+LL | struct _St1<T: Tr1<As1: Tr2>> {
+   |                    ^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:26:18
+   |
+LL | enum _En1<T: Tr1<As1: Tr2>> {
+   |                  ^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:33:19
+   |
+LL | union _Un1<T: Tr1<As1: Tr2>> {
+   |                   ^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:40:37
+   |
+LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+   |                                     ^^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:43:22
+   |
+LL | fn _apit(_: impl Tr1<As1: Copy>) {}
+   |                      ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:45:26
+   |
+LL | fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
+   |                          ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:48:24
+   |
+LL | fn _rpit() -> impl Tr1<As1: Copy> { S1 }
+   |                        ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:50:31
+   |
+LL | fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
+   |                               ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:53:23
+   |
+LL | const _cdef: impl Tr1<As1: Copy> = S1;
+   |                       ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:59:24
+   |
+LL | static _sdef: impl Tr1<As1: Copy> = S1;
+   |                        ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:66:21
+   |
+LL |     let _: impl Tr1<As1: Copy> = S1;
+   |                     ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-associated_type_bounds.rs:53:14
+   |
+LL | const _cdef: impl Tr1<As1: Copy> = S1;
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-associated_type_bounds.rs:59:15
+   |
+LL | static _sdef: impl Tr1<As1: Copy> = S1;
+   |               ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-associated_type_bounds.rs:66:12
+   |
+LL |     let _: impl Tr1<As1: Copy> = S1;
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
+
+error: aborting due to 16 previous errors
+
+Some errors occurred: E0562, E0658.
+For more information about an error, try `rustc --explain E0562`.
diff --git a/src/test/ui/type/type-alias-bounds.stderr b/src/test/ui/type/type-alias-bounds.stderr
index c0ff56d5ec0..177e5f893ed 100644
--- a/src/test/ui/type/type-alias-bounds.stderr
+++ b/src/test/ui/type/type-alias-bounds.stderr
@@ -1,13 +1,3 @@
-warning: duplicate auto trait `::marker[0]::Send[0]` found in type parameter bounds
-  --> $DIR/type-alias-bounds.rs:8:14
-   |
-LL | type SVec<T: Send + Send> = Vec<T>;
-   |              ^^^^   ^^^^ subsequent use of auto trait
-   |              |
-   |              first use of auto trait
-   |
-   = note: #[warn(duplicate_auto_traits_in_bounds)] on by default
-
 warning: bounds on generic parameters are not enforced in type aliases
   --> $DIR/type-alias-bounds.rs:8:14
    |