Trait associated type with lifetime parameter => unconstrained lifetime

An associated type in a trait has a lifetime. Now compiler requires this lifetime somewhere, but impl<'a> causes an error of unconstrained type. How can this be fixed? Playground link.

trait Worker {
    type Task;
    type Output;
    fn work(&mut self, task: &Self::Task) -> Result<Self::Output, Box<dyn Error>>;
}

struct Dataset;

struct MyWorker {
    dataset: Arc<Dataset>,
}

struct Item;
struct TaskInput<'a> {
    item: &'a Item // item is stored inside Dataset, and is referenced here
}

struct TaskOutput<'a> {
    task: TaskInput<'a>
}

impl<'a> Worker for MyWorker {
 // ^^^^ here it causes error
    type Task = TaskInput<'a>;
    type Output = TaskOutput<'a>;
    fn work(&mut self, task: &Self::Task) -> Result<Self::Output, Box<dyn Error>> {
        todo!()
    }
}

You need to add the lifetime somewhere. Just fixing your playground, a good place to put the lifetime would be the Worker trait. Example. You could also use GATs. Or add a marker to your MyWorker.

2 Likes

A third (unlikely) option is adding it to the implementing type.

(Jinx :sweat_smile:)

2 Likes

Just to expand upon the cause a bit, a given type (with all generic parameters realized) can only implement a given trait (with all generic parameters realized) once. Additionally, just like a type parameter can only represent a single concrete type, a non-generic associated type can only represent a single concrete type. (And types that differ by lifetime, even if they only differ by lifetime, are distinct types.)

In the OP, there are no generic parameters on the trait or implementing type (or associated types).

So <MyWorker as Worker>:::Task must be a single type. But you were attempting to make it represent, depending on how you think about it,

  • an infinite amount of types (one per lifetime)
  • a type constructor which takes a lifetime as an input and produces a type

The original name for GATs was "associated type constructors", and that's one of the ways to fix the error (while still just having a single implementation).

The rule for parameters of the impl<...> being constrained is basically that they must be unambiguous given the implementing type (with all generic parameters realized) and the implemented trait (with all generic parameters realized). So another two fixes are to make the lifetime a generic parameter of the implementing type, or of the trait. Then there's an implementation per lifetime.

2 Likes