Skip to content

Implementation of GATs outlives lint #89970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 6, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -1255,16 +1255,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.tainted_by_errors_flag.set(true)
}

/// Process the region constraints and report any errors that
/// Process the region constraints and return any any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
pub fn resolve_regions_and_report_errors(
pub fn resolve_regions(
&self,
region_context: DefId,
outlives_env: &OutlivesEnvironment<'tcx>,
mode: RegionckMode,
) {
) -> Vec<RegionResolutionError<'tcx>> {
let (var_infos, data) = {
let mut inner = self.inner.borrow_mut();
let inner = &mut *inner;
@@ -1290,6 +1290,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
assert!(old_value.is_none());

errors
}

/// Process the region constraints and report any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
pub fn resolve_regions_and_report_errors(
&self,
region_context: DefId,
outlives_env: &OutlivesEnvironment<'tcx>,
mode: RegionckMode,
) {
let errors = self.resolve_regions(region_context, outlives_env, mode);

if !self.is_tainted_by_errors() {
// As a heuristic, just skip reporting region errors
// altogether if other errors have been reported while
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/regionck.rs
Original file line number Diff line number Diff line change
@@ -104,7 +104,7 @@ macro_rules! ignore_err {
};
}

trait OutlivesEnvironmentExt<'tcx> {
pub(crate) trait OutlivesEnvironmentExt<'tcx> {
fn add_implied_bounds(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
372 changes: 368 additions & 4 deletions compiler/rustc_typeck/src/check/wfcheck.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/lib.rs
Original file line number Diff line number Diff line change
@@ -69,6 +69,7 @@ This API is completely unstable and subject to change.
#![feature(never_type)]
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
#![feature(hash_drain_filter)]
#![recursion_limit = "256"]

#[macro_use]
Original file line number Diff line number Diff line change
@@ -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> =
2 changes: 1 addition & 1 deletion src/test/ui/generic-associated-types/collections.rs
Original file line number Diff line number Diff line change
@@ -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> =
Original file line number Diff line number Diff line change
@@ -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<'_>;
}

2 changes: 1 addition & 1 deletion src/test/ui/generic-associated-types/issue-70303.rs
Original file line number Diff line number Diff line change
@@ -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<'_>;
}
2 changes: 1 addition & 1 deletion src/test/ui/generic-associated-types/issue-76535.rs
Original file line number Diff line number Diff line change
@@ -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>;
}
6 changes: 3 additions & 3 deletions src/test/ui/generic-associated-types/issue-76535.stderr
Original file line number Diff line number Diff line change
@@ -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>`
4 changes: 2 additions & 2 deletions src/test/ui/generic-associated-types/issue-79422.rs
Original file line number Diff line number Diff line change
@@ -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)
}
6 changes: 3 additions & 3 deletions src/test/ui/generic-associated-types/issue-79422.stderr
Original file line number Diff line number Diff line change
@@ -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>>`
5 changes: 3 additions & 2 deletions src/test/ui/generic-associated-types/issue-86787.rs
Original file line number Diff line number Diff line change
@@ -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
36 changes: 7 additions & 29 deletions src/test/ui/generic-associated-types/issue-86787.stderr
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: lowercase letter

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can do more to give an intuitive understanding here. I'd like the message to be something like this...

error: associated type `TRef` must declare that it may borrow from `Self`
  --> $DIR/issue-86787.rs:11:5
   |
LL |     type TRef<'a>;
   |     ^^^^^^^^^^^^^-
   |                  |
   |                  help: add the required where clauses: `where Self: 'a`
LL |     fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>;
   |        ^^^^^^^^^^^^
   |        |
   |        in this function, `TRef` could return content from the type `Self`, borrowed for `'a`
    note: This where clause is required because we expect to add it as a default in the future. If adding this where clause causes your use case not to work, please visit https://rust-lang.github.io/generic-associated-types-initiative/ to give feedback (and to see the workaround).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously these spans are not as precise as they could be, and the wording can probably be improved. I was trying to give what seemed like a realistic message based on the content we currently have available

--> $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

4 changes: 3 additions & 1 deletion src/test/ui/generic-associated-types/issue-88287.rs
Original file line number Diff line number Diff line change
@@ -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> {
3 changes: 2 additions & 1 deletion src/test/ui/generic-associated-types/issue-88360.rs
Original file line number Diff line number Diff line change
@@ -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 {
2 changes: 1 addition & 1 deletion src/test/ui/generic-associated-types/issue-88360.stderr
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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<'_>;
}

173 changes: 173 additions & 0 deletions src/test/ui/generic-associated-types/self-outlives-lint.rs
Original file line number Diff line number Diff line change
@@ -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() {}
98 changes: 98 additions & 0 deletions src/test/ui/generic-associated-types/self-outlives-lint.stderr
Original file line number Diff line number Diff line change
@@ -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

8 changes: 4 additions & 4 deletions src/test/ui/generic-associated-types/streaming_iterator.rs
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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>;
}