I think there's still something confusing going on here, so I made this post to explain it.
There's also an alternative fix at the end of this post, if you'd prefer to skip ahead.
Note how the trait definition and your implementation differ:
trait Foo { fn foo<'s>(&'s self) -> &'s str; }
impl<'a> Foo for MyType<'a> { fn foo<'s>(&'s self) -> &'a str { self.0 } }
// -------- ^^
In the trait definition, the returned &'s str is only valid for as long as &'s self is valid, and uses of the returned value keep *self borrowed. That's what the matching lifetimes mean. And that is how all compiling implementations of the trait act when used elsewhere, which is why your OP had an error.
But in your implementation, you return &'a str (the ^^ underlined part). The typical meaning of this method signature is that the return value may be valid longer than the &'s self, and uses of the returned value do not keep *self borrowed. But because all compiling implementations act like the trait definition, that's not what happens when you call the method in main.
@nerditation's suggestion changes the trait definition to look like your implementation, which fixes the error in the OP.
Even knowing about what I just wrote, there's still something unintuitive going on here: If the signatures mean different things in the OP, why is the implementation allowed to compile at all?
First note that the &'a str you return in the implementation can't be valid for less than the &'s self. The reason is the --- underlined part: there is a &'s MyType<'a> in the signature, which means the method has an implied 'a: 's bound.
Because of this, the implementation is more general than the trait definition. It satisfies everything that the trait needs to. And such implementations are allowed so that you can do things like this:
// If you elide all the lifetimes, it corresponds to:
impl<'a> Add<&'a str> for Whatever {
type Output = Whatever;
// Takes `'r` (unrelated to `'a`), but the trait says it takes `&'a str`!
fn add<'r>(self, rhs: &'r str) -> Self::Output {
Whatever
}
}
Instead of
// The lifetimes are the same in this version, matching the trait definition
impl<'a> Add<&'a str> for Whatever {
type Output = Whatever;
fn add(self, rhs: &'a str) -> Self::Output {
Whatever
}
}
(The first one is more common because it's what you get when you elide all lifetimes.)
It allows the programmer to be a bit sloppier and think about lifetimes less (so arguably this is a complication added to the language in an attempt to be simpler).
Perhaps the OP, where you used 'a instead of eliding things, should fire a warning lint that lets you know the more general implementation can't be taken advantage of.
There is a concept of refinement which allows consumers of traits that use -> impl Trait to take advantage of some aspects of specific implementations which are more general than the trait, when the implementer has opted into allowing that. For example:
trait Example {
fn f(&self) -> impl Sized;
fn g(&self) -> impl Sized;
}
impl Example for () {
// Reveal the exact return type to consumers
#[allow(refining_impl_trait)]
fn f(&self) -> i32 { 0 }
// Promise that the return type is always `Send` to consumers
#[allow(refining_impl_trait)]
fn g(&self) -> impl Sized + Send {}
}
fn these_compile_by_taking_advantage_of_refinement() {
let _: i32 = ().f();
let _: &dyn Send = &().g();
}
fn these_fail<T: Example>(t: T) {
let _: i32 = t.f();
let _: &dyn Send = &t.g();
}
Personally I think it would be great if we got refinement for lifetimes, so that you could have fixed the issue by adding #[allow(refining_impl_trait)] to your implementation. But so far, we cannot; that kind of refinement is not implemented in the compiler.
However, you can accomplish something similar by shadowing the trait method with an inherent method (which is preferred by method dispatch).
// New
impl<'a> MyType<'a> {
fn foo(&self) -> &'a str {
self.0
}
}
// You can keep this one. I've made the signature look how it will act.
impl<'a> Foo for MyType<'a> {
fn foo(&self) -> &str {
self.0
}
}
That also fixes the OP.