-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Description
Existing code uses trait bounds to force side-conditions on associated types. For instance, IntoIterator
is defined (in part) as follows:
Original snippet from 2016 (no longer syntactically legal)
trait IntoIterator where Self::IntoIter::Item == Self::Item {
type Item;
type IntoIter: Iterator;
}
trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
}
Similarly, we can define a side-condition using higher-ranked lifetimes:
trait BorrowIterator where for<'a> &'a Self: IntoIterator {}
This is necessary when we want to implement a trait for a (non-reference) type T
, but want to require trait implementations on &'a T
where those trait implementations can refer to the borrow lifetime 'a
.
However, the former concrete trait bounds are usable as trait bounds in functions. For instance, the following will compile:
fn needs_iter<T: IntoIterator>(){}
Whereas this will fail:
fn needs_borrow_iter<T: BorrowIterator>(){}
With the error:
error: the trait bound `for<'a> &'a T: std::iter::Iterator` is not satisfied [--explain E0277]
--> <anon>:19:1
19 |> fn needs_borrow_iter<T: BorrowIterator>()
|> ^
note: `&'a T` is not an iterator; maybe try calling `.iter()` or a similar method
note: required because of the requirements on the impl of `for<'a> std::iter::IntoIterator` for `&'a T`
note: required by `BorrowIterator`
This is doubly puzzling since T: IntoIterator
doesn't require T: Iterator
.
See #34142 which shows similar issues with bounds on function definitions.
See #27113 which shows issues with 'outlives' relations in where-clauses.