2
votes

Take the following example (Playground):

#![feature(generic_associated_types)]
#![allow(incomplete_features)]

trait Produce {
    type CustomError<'a>;

    fn produce<'a>(&'a self) -> Result<(), Self::CustomError<'a>>;
}

struct GenericProduce<T> {
    val: T,
}

struct GenericError<'a, T> {
    producer: &'a T,
}

impl<T> Produce for GenericProduce<T> {
    type CustomError<'a> = GenericError<'a, T>;

    fn produce<'a>(&'a self) -> Result<(), Self::CustomError<'a>> {
        Err(GenericError{producer: &self.val})
    }
}

The GenericError has a lifetime to allow it to take Produce as a reference. However, this code doesn't compile. It gives me the error:

error[E0309]: the parameter type `T` may not live long enough
  --> src/lib.rs:19:5
   |
18 | impl<T> Produce for GenericProduce<T> {
   |      - help: consider adding an explicit lifetime bound...: `T: 'a`
19 |     type CustomError<'a> = GenericError<'a, T>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds

This error makes sense to me because the GenericError doesn't have any restriction telling it that T must be 'a. I'm having trouble figuring out how to solve the problem though. Perhaps my generic lifetimes are misplaced?

The feature of the trait I wish to capture is that any Produce::CustomError should be able to capture self in a return. Perhaps I am going about this in the wrong way?

1
The generic_associated_types feature does not, currently, work. It just enables the syntax, but it doesn't enable the compiler to type check anything. It may be the case that when the feature is actually implemented this will work. - trentcl
I guess it is very much in progress? github.com/rust-lang/rust/issues/44265 - chub500

1 Answers

-1
votes

The same trait without generic_associated_types takes the lifetime in the trait itself.

trait Produce<'a> {
    type CustomError;

    fn produce(&'a self) -> Result<(), Self::CustomError>;
}

struct GenericProduce<T> {
    val: T,
}

struct GenericError<'a, T> {
    producer: &'a T,
}

impl<'a, T: 'a> Produce<'a> for GenericProduce<T> {
    type CustomError = GenericError<'a, T>;

    fn produce(&'a self) -> Result<(), Self::CustomError> {
        Err(GenericError{producer: &self.val})
    }
}

This tells the impl upfront that T that it must be 'a.