diff options
| author | bors <bors@rust-lang.org> | 2021-11-06 04:15:22 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-11-06 04:15:22 +0000 |
| commit | 9d39f6ab7dec5b8c6e8d9ce52a1f15b9e656c900 (patch) | |
| tree | 359db033386756ffef79ce62ef1a5f1b0fa7157e /src/test | |
| parent | 18cae2680fff914c95a633c468f09b614f385844 (diff) | |
| parent | b6edcbd7b5db718ff5e8ba229812b35f803ddd7a (diff) | |
| download | rust-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')
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>; } |
