rusttraitsserdeassociated-types

expected associated type, found type parameter


I faced an issue with associated types... I found similar questions on SO, like these ones:

But while being pretty close to my case, they are not the same...

So I have a trait with associated type:

trait Generator {
    type Item;
    fn next(&mut self) -> Self::Item;
}

And another trait with generic method which takes first one as a type parameter:

trait Iterator {
    fn iterate<T>(&self, generator: T) -> T::Item
        where T: Generator;
}

So far everything OK. Now i want to make a struct and implement Iterator trait for it.

struct Baz<R> {      // I want my struct to keep data of the same type as my associated type
    data: Vec<R>,    // So i make my struct generic 
}

impl<R> Iterator for Baz<R>
{
    fn iterate<T>(&self, generator: T) -> T::Item
        where T: Generator<Item = R>     // And specify associated type constraint for generic method
    {
        generator.next()
    }
}

And now I'm getting an error:

error[E0271]: type mismatch resolving `<T as Generator>::Item == R`
  --> src/main.rs:20:28
   |
17 | impl<R> Iterator for Baz<R>
   |      - this type parameter
...
20 |         where T: Generator<Item = R>
   |                            ^^^^^^^^ expected associated type, found type parameter `R`
   |
   = note: expected associated type `<T as Generator>::Item`
               found type parameter `R`
   = note: you might be missing a type parameter or trait bound
note: the requirement `<T as Generator>::Item == R` appears on the `impl`'s method `iterate` but not on the corresponding trait's method
  --> src/main.rs:9:8
   |
8  | trait Iterator {
   |       -------- in this trait
9  |     fn iterate<T>(&self, generator: T) -> T::Item
   |        ^^^^^^^ this trait's method doesn't have the requirement `<T as Generator>::Item == R`

I figured out that to fix it, i have to make my Iterator trait generic and specify constraint in trait definition:

trait Iterator<R> {
    fn iterate<T>(&self, generator: T) -> T::Item
        where T: Generator<Item = R>;
}

And also update impl block:

impl<R> Iterator<R> for Baz<R>
{
    ...
}

But unfortunately, these traits are from a 3rd-party library so I can't update their source code (specifically, it's SeqAccess trait from Serde library).

Is there any way to declare associated type constraint in such a case without adding type parameter to trait itself?


Solution

  • No, this is not something you can do. Consider that other functions accepting impl Iterator would not be aware of this newly-added constraint and so they could pass a Generator whose Item type doesn't match your constraint. The signature of the function in Iterator imposes no constraint on the type of generated items, so consumers of the trait are free to use any Generator at all.