Where does the 'static bound come from in this error implementing AsRef

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9464032759b98a6fea8f4405965fbc46

trait SomeTrait {}
struct Inner;
struct Outer {
    inner: Inner,
}
impl SomeTrait for Inner {}

impl AsRef<dyn SomeTrait> for Outer {
    fn as_ref(&self) -> &dyn SomeTrait {
        &self.inner
    }
}
error: `impl` item signature doesn't match `trait` item signature
   --> src/lib.rs:9:5
    |
9   |     fn as_ref(&self) -> &dyn SomeTrait {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Outer) -> &dyn SomeTrait`
    |
    = note: expected `fn(&Outer) -> &(dyn SomeTrait + 'static)`
               found `fn(&Outer) -> &dyn SomeTrait`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output

The error says the compiler expected &(dyn SomeTrait + 'static). Where does that 'static come from? It's not part of the AsRef trait as far as I can tell.

This is a simplified version; original problem at Consolidate two session types into one connection type by jsha · Pull Request #99 · abetterinternet/crustls · GitHub.

1 Like

This is the relevant page in the reference.
Lifetime elision - The Rust Reference

Your code is thus equivalent to

trait SomeTrait {}
struct Inner;
struct Outer {
    inner: Inner,
}
impl SomeTrait for Inner {}

impl AsRef<dyn SomeTrait + 'static> for Outer {
    fn as_ref<'a>(&'a self) -> &'a (dyn SomeTrait + 'a) {
        &self.inner
    }
}

One way to fix this is by changing it to

trait SomeTrait {}
struct Inner;
struct Outer {
    inner: Inner,
}
impl SomeTrait for Inner {}

impl AsRef<dyn SomeTrait + 'static> for Outer {
    fn as_ref<'a>(&'a self) -> &'a (dyn SomeTrait + 'static) {
        &self.inner
    }
}

which can, using lifetime elision, be simplified back to

trait SomeTrait {}
struct Inner;
struct Outer {
    inner: Inner,
}
impl SomeTrait for Inner {}

impl AsRef<dyn SomeTrait> for Outer {
    fn as_ref(&self) -> &(dyn SomeTrait + 'static) {
        &self.inner
    }
}

You can also generalize this implementation to

trait SomeTrait {}
struct Inner;
struct Outer {
    inner: Inner,
}
impl SomeTrait for Inner {}

impl<'a> AsRef<dyn SomeTrait + 'a> for Outer {
    fn as_ref(&self) -> &(dyn SomeTrait + 'a) {
        &self.inner
    }
}

if you like. But it doesn’t give you too much, because you can coerce the &(dyn SomeTrait + 'static) into anything you like anyways:

fn convert<'a, 'r>(r: &'r (dyn SomeTrait + 'static)) -> &'r (dyn SomeTrait + 'a) {
    r
}
3 Likes

In addition to the above -- Recall that owned values always satisfy 'static because it's impossible to observe them outside their scope. Therefore, (dyn SomeTrait + 'static) is a completely valid description of Outer.inner, and by extension, &'a (dyn SomeTrait + 'static) is a completely valid description of (&'a self).inner.

Best link I could quickly find: Static - Rust By Example
and rust-blog/common-rust-lifetime-misconceptions.md at master · pretzelhammer/rust-blog · GitHub

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.