This does not work because B: LendingIterator<Item<'_> = A::Item<'_>> is not valid -- anonymous lifetimes cannot be used in this way. However, if I try to use HRTB it still does not compile:
impl<A, B> LendingIterator for Either<A, B>
where
A: LendingIterator,
B: for<'a> LendingIterator<Item<'a> = A::Item<'a>>,
{
/* ... */
}
I think that the error makes sense, because we should express the fact that A: 'a, or in other words the bound is not valid for every lifetime 'a.
I think the HRTB can't be fulfilled because the Item<'a> is limited to cases where Self: 'a, while the HRTB is unlimited. And due to the issue 87479 lint, you can't make the GAT unlimited. I don't think this particular example is cited yet; probably you could mention it.
Thank you so much!
The issue with HRTB was exactly the one I was thinking, but I was not aware of the workaround you mentioned. It is a very clever solution!
I feel like the issue here isn’t the Self: 'a bound (that one is actually really useful for a LendingIterator trait) and more the fact that GATs don’t have any syntax for specifying the Item type being equal to something else.
The typical workaround that keeps the Self: 'a bound works, too. Hrtb-based workaround do support such an the kind of equality constraint that GATs don’t have any syntax for. I hope this problem is tracked somewhere already, but I haven’t looked.
Here’s a workaround that keeps the Self: 'a bound: Rust Playground
Using this approach, it should even be possible to write the implementation for the GAT-based trait, by using a helper-trait: Rust Playground
For the record, you can also use some custom type-equality trait here: Rust Playground
error[E0582]: binding for associated type `To` references lifetime `'a`, which does not appear in the trait input types
--> src/lib.rs:16:38
|
16 | for<'a> A::Item<'a>: TypeIsEqual<To = B::Item<'a>>,
| ^^^^^^^^^^^^^^^^
ehm… well, that error is certainly really weird, but – I can add an additional but somehow seemingly useless lifetime argument to make this work… Rust Playground
Or actually… a trait synonym fixes the error, too: Rust Playground
See here for some more information about how to use such a type-equality helper trait.