Implementing ToOwned ('a -> 'static) for an enum containing Cow<'a, str> causes unmet lifetime requirement

Context

Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=de1286b8bce0dfb840a5fc0b50df25ad

I was reading this other SO post, which was saying you can convert a struct containing a Cow to have a 'static lifetime. Based on that post, I then tried the following:

use std::borrow::Cow;

enum S<'a> {
    A(Cow<'a, str>),
    B(i32)
}

impl ToOwned for S<'_> {
    type Owned = S<'static>;
    
    fn to_owned(&self) -> Self::Owned {
        match *self {
            S::A(s) => S::A(Cow::Owned(s.clone().into_owned())),
            S::B(i) => S::B(i)
        }
    }
}

fn main() {
    let s = S::A("a".into());
    let s = s.to_owned();
}

and got the following error

error: incompatible lifetime on type
   --> src/main.rs:9:18
    |
9   |     type Owned = S<'static>;
    |                  ^^^^^^^^^^
    |
note: because this has an unmet lifetime requirement
note: the lifetime `'_` as defined here...
   --> src/main.rs:8:20
    |
8   | impl ToOwned for S<'_> {
    |                    ^^
note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`

Questions

  • How exactly are lifetimes coming into play here if I’m converting the Cow into the owned version?
  • What’s the right approach to getting this to work?

>Solution :

TL;DR: You cannot implement ToOwned for that; use an inherent method.


ToOwned::Owned has a bound:

type Owned: Borrow<Self>;

So we need S<'static> to impl Borrow<S<'a>> for any 'a.

…except this impl cannot be written:

error[E0119]: conflicting implementations of trait `std::borrow::Borrow<S<'static>>` for type `S<'static>`
  --> src/main.rs:19:1
   |
19 | impl<'a> Borrow<S<'a>> for S<'static> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T> Borrow<T> for T
             where T: ?Sized;

…because it conflicts with the blanket implementation Borrow<T> for T where 'a is 'static.

The compiler error without this impl is an outcome of the fact that the compiler sees that there is an impl<'a> Borrow<S<'a>> for S<'static> (the abovementioned blanket implementation), it is just that it constrains 'a: 'static. And so the compiler tries to prove 'a: 'static, and fails. This is an example of the compiler being over-smart, causing a confusing error message.

Leave a Reply