Hello, I'm facing a problem with GATs when implementing a trait for a type that has lifetime arguments. Here is a minimal example where implementing Trait
for Easy
works well, but implementing Trait
for Hard
doesn't work:
#![feature(generic_associated_types)]
use std::borrow::Cow;
use std::ops::Deref;
trait Trait {
type Gat<'a>: Deref<Target = Self>;
fn func(src: &str) -> Self::Gat<'_>;
}
#[derive(Clone)]
struct Easy(String);
impl Trait for Easy {
type Gat<'a> = Cow<'a, Self>;
fn func(src: &str) -> Self::Gat<'_> {
Cow::Owned(Easy(src.to_owned()))
}
}
#[derive(Clone)]
struct Hard<'b>(&'b str);
impl<'b> Trait for Hard<'b> {
type Gat<'a> = Cow<'a, Self>;
fn func(src: &str) -> Self::Gat<'_> {
Cow::Owned(Hard(src))
}
}
Errors:
error[E0477]: the type `Hard<'b>` does not fulfill the required lifetime
--> src/lib.rs:25:20
|
25 | type Gat<'a> = Cow<'a, Self>;
| ^^^^^^^^^^^^^
|
note: type must outlive the lifetime `'a` as defined here as required by this binding
--> src/lib.rs:25:14
|
25 | type Gat<'a> = Cow<'a, Self>;
| ^^
For more information about this error, try `rustc --explain E0477`.
I tried adding where Self: 'a
(see also #87479), but without success:
#![feature(generic_associated_types)]
use std::borrow::Cow;
use std::ops::Deref;
trait Trait {
- type Gat<'a>: Deref<Target = Self>;
+ type Gat<'a>: Deref<Target = Self>
+ where
+ Self: 'a;
fn func(src: &str) -> Self::Gat<'_>;
}
#[derive(Clone)]
struct Easy(String);
impl Trait for Easy {
- type Gat<'a> = Cow<'a, Self>;
+ type Gat<'a> = Cow<'a, Self>
+ where
+ Self: 'a;
fn func(src: &str) -> Self::Gat<'_> {
Cow::Owned(Easy(src.to_owned()))
}
}
#[derive(Clone)]
struct Hard<'b>(&'b str);
impl<'b> Trait for Hard<'b> {
- type Gat<'a> = Cow<'a, Self>;
+ type Gat<'a> = Cow<'a, Self>
+ where
+ Self: 'a;
fn func(src: &str) -> Self::Gat<'_> {
Cow::Owned(Hard(src))
}
}
This gives the same error.
I even tried something like this:
#![feature(generic_associated_types)]
use std::borrow::Cow;
use std::ops::Deref;
trait Trait {
type Gat<'a>: Deref<Target = Self>
where
Self: 'a;
- fn func(src: &str) -> Self::Gat<'_>;
+ fn func<'a>(src: &'a str) -> Self::Gat<'a>
+ where
+ Self: 'a;
}
#[derive(Clone)]
struct Easy(String);
impl Trait for Easy {
type Gat<'a> = Cow<'a, Self>
where
Self: 'a;
- fn func(src: &str) -> Self::Gat<'_> {
+ fn func<'a>(src: &'a str) -> Self::Gat<'a>
+ where
+ Self: 'a,
+ {
Cow::Owned(Easy(src.to_owned()))
}
}
#[derive(Clone)]
struct Hard<'b>(&'b str);
impl<'b> Trait for Hard<'b> {
type Gat<'a> = Cow<'a, Self>
where
Self: 'a;
- fn func(src: &str) -> Self::Gat<'_> {
+ fn func<'a>(src: &'a str) -> Self::Gat<'a>
+ where
+ Self: 'a,
+ {
Cow::Owned(Hard(src))
}
}
But then I get:
error: lifetime may not live long enough
--> src/lib.rs:41:9
|
33 | impl<'b> Trait for Hard<'b> {
| -- lifetime `'b` defined here
...
37 | fn func<'a>(src: &'a str) -> Self::Gat<'a>
| -- lifetime `'a` defined here
...
41 | Cow::Owned(Hard(src))
| ^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'b`
= note: requirement occurs because of the type `Cow<'_, Hard<'_>>`, which makes the generic argument `Hard<'_>` invariant
= note: the enum `Cow<'a, B>` is invariant over the parameter `B`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Simply adding 'a: 'b
as the compiler suggested gives me error[E0276]: impl has stricter requirements than trait
, of course.
My question is: Can I implement Trait
for Hard<'_>
and how can I do it? Maybe I'm just misunderstanding how lifetimes work in this case? Or is this something where the compiler doesn't work properly (yet)?