about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-11-06 04:15:22 +0000
committerbors <bors@rust-lang.org>2021-11-06 04:15:22 +0000
commit9d39f6ab7dec5b8c6e8d9ce52a1f15b9e656c900 (patch)
tree359db033386756ffef79ce62ef1a5f1b0fa7157e /src/test
parent18cae2680fff914c95a633c468f09b614f385844 (diff)
parentb6edcbd7b5db718ff5e8ba229812b35f803ddd7a (diff)
downloadrust-9d39f6ab7dec5b8c6e8d9ce52a1f15b9e656c900.tar.gz
rust-9d39f6ab7dec5b8c6e8d9ce52a1f15b9e656c900.zip
Auto merge of #89970 - jackh726:gats_diagnostics, r=nikomatsakis
Implementation of GATs outlives lint

See #87479 for background. Closes #87479

The basic premise of this lint/error is to require the user to write where clauses on a GAT when those bounds can be implied or proven from any function on the trait returning that GAT.

## Intuitive Explanation (Attempt) ##
Let's take this trait definition as an example:
```rust
trait Iterable {
    type Item<'x>;
    fn iter<'a>(&'a self) -> Self::Item<'a>;
}
```
Let's focus on the `iter` function. The first thing to realize is that we know that `Self: 'a` because of `&'a self`. If an impl wants `Self::Item` to contain any data with references, then those references must be derived from `&'a self`. Thus, they must live only as long as `'a`. Furthermore, because of the `Self: 'a` implied bound, they must live only as long as `Self`. Since it's `'a` is used in place of `'x`, it is reasonable to assume that any value of `Self::Item<'x>`, and thus `'x`, will only be able to live as long as `Self`. Therefore, we require this bound on `Item` in the trait.

As another example:
```rust
trait Deserializer<T> {
    type Out<'x>;
    fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
}
```
The intuition is similar here, except rather than a `Self: 'a` implied bound, we have a `T: 'a` implied bound. Thus, the data on `Self::Out<'a>` is derived from `&'a T`, and thus it is reasonable to expect that the lifetime `'x` will always be less than `T`.

## Implementation Algorithm ##
* Given a GAT `<P0 as Trait<P1..Pi>>::G<Pi...Pn>` declared as `trait T<A1..Ai> for A0 { type G<Ai...An>; }` used in return type of one associated function `F`
* Given env `E` (including implied bounds) for `F`
* For each lifetime parameter `'a` in `P0...Pn`:
    * For each other type parameter `Pi != 'a` in `P0...Pn`: // FIXME: this include of lifetime parameters too
        * If `E => (P: 'a)`:
            * Require where clause `Ai: 'a`

## Follow-up questions ##
* What should we do when we don't pass params exactly?
For this example:
```rust
trait Des {
    type Out<'x, D>;
    fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
}
```
Should we be requiring a `D: 'x` clause? We pass `Wrap<T>` as `D` and `'z` as `'x`, and should be able to prove that `Wrap<T>: 'z`.

r? `@nikomatsakis`
Diffstat (limited to 'src/test')
-rw-r--r--src/test/ui/generic-associated-types/collections-project-default.rs2
-rw-r--r--src/test/ui/generic-associated-types/collections.rs2
-rw-r--r--src/test/ui/generic-associated-types/generic-associated-type-bounds.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-70303.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-76535.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-76535.stderr6
-rw-r--r--src/test/ui/generic-associated-types/issue-79422.rs4
-rw-r--r--src/test/ui/generic-associated-types/issue-79422.stderr6
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.rs5
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.stderr36
-rw-r--r--src/test/ui/generic-associated-types/issue-88287.rs4
-rw-r--r--src/test/ui/generic-associated-types/issue-88360.rs3
-rw-r--r--src/test/ui/generic-associated-types/issue-88360.stderr2
-rw-r--r--src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs2
-rw-r--r--src/test/ui/generic-associated-types/self-outlives-lint.rs173
-rw-r--r--src/test/ui/generic-associated-types/self-outlives-lint.stderr98
-rw-r--r--src/test/ui/generic-associated-types/streaming_iterator.rs8
-rw-r--r--src/test/ui/generic-associated-types/variance_constraints.rs2
18 files changed, 306 insertions, 53 deletions
diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs
index 0944bf110c1..5b94cdee7c9 100644
--- a/src/test/ui/generic-associated-types/collections-project-default.rs
+++ b/src/test/ui/generic-associated-types/collections-project-default.rs
@@ -8,7 +8,7 @@
 // check that we don't normalize with trait defaults.
 
 trait Collection<T> {
-    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
+    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter, Self: 'iter;
     type Family: CollectionFamily;
     // Test associated type defaults with parameters
     type Sibling<U>: Collection<U> =
diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs
index f14c6dac1b1..b0f2fb3f567 100644
--- a/src/test/ui/generic-associated-types/collections.rs
+++ b/src/test/ui/generic-associated-types/collections.rs
@@ -8,7 +8,7 @@
 // run-pass
 
 trait Collection<T> {
-    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
+    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter, Self: 'iter;
     type Family: CollectionFamily;
     // Test associated type defaults with parameters
     type Sibling<U>: Collection<U> =
diff --git a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs
index 5d3a3a89352..d7c4dbda264 100644
--- a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs
+++ b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs
@@ -3,7 +3,7 @@
 #![feature(generic_associated_types)]
 
 pub trait X {
-    type Y<'a>;
+    type Y<'a> where Self: 'a;
     fn m(&self) -> Self::Y<'_>;
 }
 
diff --git a/src/test/ui/generic-associated-types/issue-70303.rs b/src/test/ui/generic-associated-types/issue-70303.rs
index d238f53bde7..568996e1a17 100644
--- a/src/test/ui/generic-associated-types/issue-70303.rs
+++ b/src/test/ui/generic-associated-types/issue-70303.rs
@@ -3,7 +3,7 @@
 #![feature(generic_associated_types)]
 
 trait Document {
-    type Cursor<'a>: DocCursor<'a>;
+    type Cursor<'a>: DocCursor<'a> where Self: 'a;
 
     fn cursor(&self) -> Self::Cursor<'_>;
 }
diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs
index 1dad856d5a3..20c6924afa6 100644
--- a/src/test/ui/generic-associated-types/issue-76535.rs
+++ b/src/test/ui/generic-associated-types/issue-76535.rs
@@ -3,7 +3,7 @@
 pub trait SubTrait {}
 
 pub trait SuperTrait {
-    type SubType<'a>: SubTrait;
+    type SubType<'a>: SubTrait where Self: 'a;
 
     fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
 }
diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr
index 0a7eb5dde60..64eeec1b2fc 100644
--- a/src/test/ui/generic-associated-types/issue-76535.stderr
+++ b/src/test/ui/generic-associated-types/issue-76535.stderr
@@ -7,7 +7,7 @@ LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruc
 note: associated type defined here, with 1 lifetime parameter: `'a`
   --> $DIR/issue-76535.rs:6:10
    |
-LL |     type SubType<'a>: SubTrait;
+LL |     type SubType<'a>: SubTrait where Self: 'a;
    |          ^^^^^^^ --
 help: add missing lifetime argument
    |
@@ -25,7 +25,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
    |
 LL | pub trait SuperTrait {
    |           ---------- this trait cannot be made into an object...
-LL |     type SubType<'a>: SubTrait;
+LL |     type SubType<'a>: SubTrait where Self: 'a;
    |          ^^^^^^^ ...because it contains the generic associated type `SubType`
    = help: consider moving `SubType` to another trait
 
@@ -40,7 +40,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
    |
 LL | pub trait SuperTrait {
    |           ---------- this trait cannot be made into an object...
-LL |     type SubType<'a>: SubTrait;
+LL |     type SubType<'a>: SubTrait where Self: 'a;
    |          ^^^^^^^ ...because it contains the generic associated type `SubType`
    = help: consider moving `SubType` to another trait
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs
index 7f0ac348358..47ef38ff45d 100644
--- a/src/test/ui/generic-associated-types/issue-79422.rs
+++ b/src/test/ui/generic-associated-types/issue-79422.rs
@@ -17,12 +17,12 @@ impl<'a, T> RefCont<'a, T> for Box<T> {
 }
 
 trait MapLike<K, V> {
-    type VRefCont<'a>: RefCont<'a, V>;
+    type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
     fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
 }
 
 impl<K: Ord, V: 'static> MapLike<K, V> for std::collections::BTreeMap<K, V> {
-    type VRefCont<'a> = &'a V;
+    type VRefCont<'a> where Self: 'a = &'a V;
     fn get<'a>(&'a self, key: &K) -> Option<&'a V> {
         std::collections::BTreeMap::get(self, key)
     }
diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr
index b6f856a97e7..8b6f9b866e5 100644
--- a/src/test/ui/generic-associated-types/issue-79422.stderr
+++ b/src/test/ui/generic-associated-types/issue-79422.stderr
@@ -7,7 +7,7 @@ LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
 note: associated type defined here, with 1 lifetime parameter: `'a`
   --> $DIR/issue-79422.rs:20:10
    |
-LL |     type VRefCont<'a>: RefCont<'a, V>;
+LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ --
 help: add missing lifetime argument
    |
@@ -25,7 +25,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
    |
 LL | trait MapLike<K, V> {
    |       ------- this trait cannot be made into an object...
-LL |     type VRefCont<'a>: RefCont<'a, V>;
+LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
 
@@ -40,7 +40,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
    |
 LL | trait MapLike<K, V> {
    |       ------- this trait cannot be made into an object...
-LL |     type VRefCont<'a>: RefCont<'a, V>;
+LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs
index f1f05ea6627..0f62f83e256 100644
--- a/src/test/ui/generic-associated-types/issue-86787.rs
+++ b/src/test/ui/generic-associated-types/issue-86787.rs
@@ -9,6 +9,7 @@ enum Either<L, R> {
 pub trait HasChildrenOf {
     type T;
     type TRef<'a>;
+    //~^ Missing required bounds
 
     fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>;
     fn take_children(self) -> Vec<Self::T>;
@@ -20,9 +21,9 @@ where
     Right: HasChildrenOf,
 {
     type T = Either<Left::T, Right::T>;
+    // We used to error below because the where clause doesn't match the trait.
+    // Now, we error early on the trait itself.
     type TRef<'a>
-    //~^ `impl` associated type signature
-    //~^^ `impl` associated type signature
     where
     <Left as HasChildrenOf>::T: 'a,
     <Right as HasChildrenOf>::T: 'a
diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr
index 648eff77d73..87dcd875de7 100644
--- a/src/test/ui/generic-associated-types/issue-86787.stderr
+++ b/src/test/ui/generic-associated-types/issue-86787.stderr
@@ -1,32 +1,10 @@
-error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature
-  --> $DIR/issue-86787.rs:23:5
+error: Missing required bounds on TRef
+  --> $DIR/issue-86787.rs:11:5
    |
-LL |       type TRef<'a>;
-   |       -------------- expected
-...
-LL | /     type TRef<'a>
-LL | |
-LL | |
-LL | |     where
-LL | |     <Left as HasChildrenOf>::T: 'a,
-LL | |     <Right as HasChildrenOf>::T: 'a
-LL | |     = Either<&'a Left::T, &'a Right::T>;
-   | |________________________________________^ found
+LL |     type TRef<'a>;
+   |     ^^^^^^^^^^^^^-
+   |                  |
+   |                  help: add the required where clauses: `where Self: 'a`
 
-error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature
-  --> $DIR/issue-86787.rs:23:5
-   |
-LL |       type TRef<'a>;
-   |       -------------- expected
-...
-LL | /     type TRef<'a>
-LL | |
-LL | |
-LL | |     where
-LL | |     <Left as HasChildrenOf>::T: 'a,
-LL | |     <Right as HasChildrenOf>::T: 'a
-LL | |     = Either<&'a Left::T, &'a Right::T>;
-   | |________________________________________^ found
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/issue-88287.rs b/src/test/ui/generic-associated-types/issue-88287.rs
index 2e65af594a6..df5586ed422 100644
--- a/src/test/ui/generic-associated-types/issue-88287.rs
+++ b/src/test/ui/generic-associated-types/issue-88287.rs
@@ -13,7 +13,8 @@ trait SearchableResource<Criteria> {
 trait SearchableResourceExt<Criteria>: SearchableResource<Criteria> {
     type Future<'f, A: 'f + ?Sized, B: 'f>: Future<Output = Result<Vec<A::SearchResult>, ()>> + 'f
     where
-        A: SearchableResource<B>;
+        A: SearchableResource<B>,
+        Self: 'f;
 
     fn search<'c>(&'c self, client: &'c ()) -> Self::Future<'c, Self, Criteria>;
 }
@@ -29,6 +30,7 @@ where
     type Future<'f, A, B: 'f>
     where
         A: SearchableResource<B> + ?Sized + 'f,
+        Self: 'f,
     = SearchFutureTy<'f, A, B>;
 
     fn search<'c>(&'c self, _client: &'c ()) -> Self::Future<'c, Self, Criteria> {
diff --git a/src/test/ui/generic-associated-types/issue-88360.rs b/src/test/ui/generic-associated-types/issue-88360.rs
index 06af3f5ec96..8ee98201aba 100644
--- a/src/test/ui/generic-associated-types/issue-88360.rs
+++ b/src/test/ui/generic-associated-types/issue-88360.rs
@@ -1,13 +1,14 @@
 #![feature(generic_associated_types)]
 
 trait GatTrait {
-    type Gat<'a>;
+    type Gat<'a> where Self: 'a;
 
     fn test(&self) -> Self::Gat<'_>;
 }
 
 trait SuperTrait<T>
 where
+    Self: 'static,
     for<'a> Self: GatTrait<Gat<'a> = &'a T>,
 {
     fn copy(&self) -> Self::Gat<'_> where T: Copy {
diff --git a/src/test/ui/generic-associated-types/issue-88360.stderr b/src/test/ui/generic-associated-types/issue-88360.stderr
index cfbf3aaa4e6..5f769d799fa 100644
--- a/src/test/ui/generic-associated-types/issue-88360.stderr
+++ b/src/test/ui/generic-associated-types/issue-88360.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-88360.rs:14:9
+  --> $DIR/issue-88360.rs:15:9
    |
 LL | trait SuperTrait<T>
    |                  - this type parameter
diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
index b976ee3261f..bcbcfc18996 100644
--- a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
+++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
@@ -1,7 +1,7 @@
 #![feature(generic_associated_types)]
 
 pub trait X {
-    type Y<'a>;
+    type Y<'a> where Self: 'a;
     fn m(&self) -> Self::Y<'_>;
 }
 
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs
new file mode 100644
index 00000000000..af90d158855
--- /dev/null
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs
@@ -0,0 +1,173 @@
+#![feature(generic_associated_types)]
+
+// check-fail
+
+use std::fmt::Debug;
+
+// We have a `&'a self`, so we need a `Self: 'a`
+trait Iterable {
+    type Item<'x>;
+    //~^ Missing required bounds
+    fn iter<'a>(&'a self) -> Self::Item<'a>;
+}
+
+/*
+impl<T> Iterable for T {
+    type Item<'a> = &'a T;
+    fn iter<'a>(&'a self) -> Self::Item<'a> {
+        self
+    }
+}
+*/
+
+// We have a `&'a T`, so we need a `T: 'x`
+trait Deserializer<T> {
+    type Out<'x>;
+    //~^ Missing required bounds
+    fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
+}
+
+/*
+impl<T> Deserializer<T> for () {
+    type Out<'a> = &'a T;
+    fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input }
+}
+*/
+
+// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x`
+trait Deserializer2<T> {
+    type Out<'x>;
+    //~^ Missing required bounds
+    fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>;
+}
+
+// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y`
+trait Deserializer3<T, U> {
+    type Out<'x, 'y>;
+    //~^ Missing required bounds
+    fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
+}
+
+// `T` is a param on the function, so it can't be named by the associated type
+trait Deserializer4 {
+    type Out<'x>;
+    fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>;
+}
+
+struct Wrap<T>(T);
+
+// We pass `Wrap<T>` and we see `&'z Wrap<T>`, so we require `D: 'x`
+trait Des {
+    type Out<'x, D>;
+    //~^ Missing required bounds
+    fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
+}
+/*
+impl Des for () {
+    type Out<'x, D> = &'x D; // Not okay
+    fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, Wrap<T>> {
+        data
+    }
+}
+*/
+
+// We have `T` and `'z` as GAT substs. Because of `&'z Wrap<T>`, there is an
+// implied bound that `T: 'z`, so we require `D: 'x`
+trait Des2 {
+    type Out<'x, D>;
+    //~^ Missing required bounds
+    fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>;
+}
+/*
+impl Des2 for () {
+    type Out<'x, D> = &'x D;
+    fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, T> {
+        &data.0
+    }
+}
+*/
+
+// We see `&'z T`, so we require `D: 'x`
+trait Des3 {
+    type Out<'x, D>;
+    //~^ Missing required bounds
+    fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
+}
+/*
+impl Des3 for () {
+    type Out<'x, D> = &'x D;
+    fn des<'a, T>(&self, data: &'a T) -> Self::Out<'a, T> {
+          data
+    }
+}
+*/
+
+// Similar case to before, except with GAT.
+trait NoGat<'a> {
+    type Bar;
+    fn method(&'a self) -> Self::Bar;
+}
+
+// Lifetime is not on function; except `Self: 'a`
+// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
+trait TraitLifetime<'a> {
+    type Bar<'b>;
+    //~^ Missing required bounds
+    fn method(&'a self) -> Self::Bar<'a>;
+}
+
+// Like above, but we have a where clause that can prove what we want
+// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
+trait TraitLifetimeWhere<'a> where Self: 'a {
+    type Bar<'b>;
+    //~^ Missing required bounds
+    fn method(&'a self) -> Self::Bar<'a>;
+}
+
+// Explicit bound instead of implicit; we want to still error
+trait ExplicitBound {
+    type Bar<'b>;
+    //~^ Missing required bounds
+    fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b;
+}
+
+// The use of the GAT here is not in the return, we don't want to error
+trait NotInReturn {
+    type Bar<'b>;
+    fn method<'b>(&'b self) where Self::Bar<'b>: Debug;
+}
+
+// We obviously error for `Iterator`, but we should also error for `Item`
+trait IterableTwo {
+    type Item<'a>;
+    type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
+    //~^ Missing required bounds
+    fn iter<'a>(&'a self) -> Self::Iterator<'a>;
+}
+
+// We also should report region outlives clauses
+trait RegionOutlives {
+    type Bar<'a, 'b>;
+    //~^ Missing required bounds
+    fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>;
+}
+
+/*
+impl Foo for () {
+    type Bar<'a, 'b> = &'a &'b ();
+    fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y> {
+        input
+    }
+}
+*/
+
+// If there are multiple methods that return the GAT, require a set of clauses
+// that can be satisfied by *all* methods
+trait MultipleMethods {
+    type Bar<'me>;
+
+    fn gimme<'a>(&'a self) -> Self::Bar<'a>;
+    fn gimme_default(&self) -> Self::Bar<'static>;
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
new file mode 100644
index 00000000000..bf85780f69f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
@@ -0,0 +1,98 @@
+error: Missing required bounds on Item
+  --> $DIR/self-outlives-lint.rs:9:5
+   |
+LL |     type Item<'x>;
+   |     ^^^^^^^^^^^^^-
+   |                  |
+   |                  help: add the required where clauses: `where Self: 'x`
+
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:25:5
+   |
+LL |     type Out<'x>;
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clauses: `where T: 'x`
+
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:39:5
+   |
+LL |     type Out<'x>;
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clauses: `where T: 'x`
+
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:46:5
+   |
+LL |     type Out<'x, 'y>;
+   |     ^^^^^^^^^^^^^^^^-
+   |                     |
+   |                     help: add the required where clauses: `where T: 'x, U: 'y`
+
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:61:5
+   |
+LL |     type Out<'x, D>;
+   |     ^^^^^^^^^^^^^^^-
+   |                    |
+   |                    help: add the required where clauses: `where D: 'x`
+
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:77:5
+   |
+LL |     type Out<'x, D>;
+   |     ^^^^^^^^^^^^^^^-
+   |                    |
+   |                    help: add the required where clauses: `where D: 'x`
+
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:92:5
+   |
+LL |     type Out<'x, D>;
+   |     ^^^^^^^^^^^^^^^-
+   |                    |
+   |                    help: add the required where clauses: `where D: 'x`
+
+error: Missing required bounds on Bar
+  --> $DIR/self-outlives-lint.rs:114:5
+   |
+LL |     type Bar<'b>;
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clauses: `where Self: 'a, Self: 'b`
+
+error: Missing required bounds on Bar
+  --> $DIR/self-outlives-lint.rs:122:5
+   |
+LL |     type Bar<'b>;
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clauses: `where Self: 'a, Self: 'b`
+
+error: Missing required bounds on Bar
+  --> $DIR/self-outlives-lint.rs:129:5
+   |
+LL |     type Bar<'b>;
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clauses: `where Self: 'b`
+
+error: Missing required bounds on Iterator
+  --> $DIR/self-outlives-lint.rs:143:5
+   |
+LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                                       |
+   |                                                       help: add the required where clauses: `where Self: 'a`
+
+error: Missing required bounds on Bar
+  --> $DIR/self-outlives-lint.rs:150:5
+   |
+LL |     type Bar<'a, 'b>;
+   |     ^^^^^^^^^^^^^^^^-
+   |                     |
+   |                     help: add the required where clauses: `where 'a: 'b`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/ui/generic-associated-types/streaming_iterator.rs b/src/test/ui/generic-associated-types/streaming_iterator.rs
index 2feff9f4c6f..f83d4d7b68e 100644
--- a/src/test/ui/generic-associated-types/streaming_iterator.rs
+++ b/src/test/ui/generic-associated-types/streaming_iterator.rs
@@ -5,12 +5,12 @@
 use std::fmt::Display;
 
 trait StreamingIterator {
-    type Item<'a>;
+    type Item<'a> where Self: 'a;
     // Applying the lifetime parameter `'a` to `Self::Item` inside the trait.
     fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
 }
 
-struct Foo<T: StreamingIterator> {
+struct Foo<T: StreamingIterator + 'static> {
     // Applying a concrete lifetime to the constructor outside the trait.
     bar: <T as StreamingIterator>::Item<'static>,
 }
@@ -30,7 +30,7 @@ struct StreamEnumerate<I> {
 }
 
 impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
-    type Item<'a> = (usize, I::Item<'a>);
+    type Item<'a> where Self: 'a = (usize, I::Item<'a>);
     fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
         match self.iter.next() {
             None => None,
@@ -44,7 +44,7 @@ impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
 }
 
 impl<I: Iterator> StreamingIterator for I {
-    type Item<'a> = <I as Iterator>::Item;
+    type Item<'a> where Self: 'a = <I as Iterator>::Item;
     fn next(&mut self) -> Option<<I as StreamingIterator>::Item<'_>> {
         Iterator::next(self)
     }
diff --git a/src/test/ui/generic-associated-types/variance_constraints.rs b/src/test/ui/generic-associated-types/variance_constraints.rs
index 7bc250ee87b..7d0f7638ac8 100644
--- a/src/test/ui/generic-associated-types/variance_constraints.rs
+++ b/src/test/ui/generic-associated-types/variance_constraints.rs
@@ -3,7 +3,7 @@
 #![feature(generic_associated_types)]
 
 trait A {
-    type B<'a>;
+    type B<'a> where Self: 'a;
 
     fn make_b<'a>(&'a self) -> Self::B<'a>;
 }