-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Description
Please excuse the lack of specificity in the title, it reflects my lack of understanding what is going on here.
Here's a distilled example of what I'm going for:
trait FooMut {
type Baz: 'static;
fn bar<'a, I>(self, iterator: &'a I)
where
for<'b> &'b I: IntoIterator<Item = &'b &'a Self::Baz>;
}
struct DelegatingFooMut<T>
where
T: FooMut,
{
delegate: T,
}
impl<T> FooMut for DelegatingFooMut<T>
where
T: FooMut,
{
type Baz = DelegatingBaz<T::Baz>;
fn bar<'a, I>(self, collection: &'a I)
where
for<'b> &'b I: IntoIterator<Item = &'b &'a Self::Baz>,
{
let collection = collection.into_iter().map(|b| &b.delegate);
self.delegate.bar(&collection)
}
}
struct DelegatingBaz<T> {
delegate: T,
}
(Play)
This fails to compile (on stable and nightly) with:
error[E0271]: type mismatch resolving `for<'b> <&'b I as std::iter::IntoIterator>::Item == &'b &<T as FooMut>::Baz`
--> src/main.rs:17:23
|
17 | self.delegate.bar(&collection)
| ^^^ expected struct `DelegatingBaz`, found associated type
|
= note: expected type `&&'a DelegatingBaz<<T as FooMut>::Baz>`
found type `&&<T as FooMut>::Baz`
error[E0308]: mismatched types
--> src/main.rs:17:27
|
17 | self.delegate.bar(&collection)
| ^^^^^^^^^^^ expected type parameter, found struct `std::iter::Map`
|
= note: expected type `&I`
found type `&std::iter::Map<<&I as std::iter::IntoIterator>::IntoIter, [closure@src/main.rs:15:53: 15:68]>`
I played around a bit and found that changing the bar
implementation to the following does compile:
fn bar<'a, I>(self, collection: &'a I) where for <'b> &'b I: IntoIterator<Item= &'b &'a Self::Baz> {
let collection: Vec<&<T as FooMut>::Baz> = collection.into_iter().map(|b| &b.delegate).collect();
self.delegate.bar::<Vec<&<T as FooMut>::Baz>>(&collection)
}
(Play)
But only with the turbo-fish on the call to self.delegate.bar
; if I remove the turbo-fish it once again fails to compile:
fn bar<'a, I>(self, collection: &'a I) where for <'b> &'b I: IntoIterator<Item= &'b &'a Self::Baz> {
let collection: Vec<&<T as FooMut>::Baz> = collection.into_iter().map(|b| &b.delegate).collect();
self.delegate.bar(&collection)
}
(Play)
This surprised me. From the error it seems like the compiler infers the type-parameter on the call to the delegate to be the same as the type parameter on the outer (delegating) method. I am not completely sure if this is a bug or intended behavior. If this isn't a bug I was hoping someone would perhaps be able to give me some insight into the what and why and a possible work-around.
While collecting into a Vec
works as a workaround for now, I would really like to avoid having to allocate. I'm assuming that I might be able to make the original example work if I can work out a type for a turbo-fish there, but std::iter::Map
seems to take the concrete type of its closure as a type parameter and I cannot figure out how to represent that in the turbo-fish type (if that's possible at all).