Cryptic error E0623

I've recently encountered this rather hard to read lifetime error:

error[E0623]: lifetime mismatch
  --> src/lib.rs:50:28
   |
43 |     fn foo<'a, B>(&self, ay: &Ay<'a>, bs: &[B])
   |                              -------
   |                              |
   |                              these two types are declared with different lifetimes...
...
50 |                     right: Cow::Owned(ThisBee { data: Cow::Borrowed(&ay.data) }),
   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `ay` flows into `ay` here

error: aborting due to previous error

As you can see, the two types that are declared with different lifetimes are in fact the same type!

Here's a playground gist with a minimal example:

The error itself is easy enough to fix by changing Cow::Borrowed(&ay.data) to just ay.data.clone(), but I'm curious as to why the error message looks like that.

1 Like

There's a lifetime (actually 3) that has been elided from the following signature:

fn foo<'a, B>(&self, ay: &Ay<'a>, bs: &[B])

& references always have a lifetime attached, so it's more like:

fn foo<'a, B>(&'1 self, ay: &'2 Ay<'a>, bs: &'3 [B])

where '1, '2 and '3 are not valid Rust syntax, but represent lifetimes the caller may choose.

In this line:

                right: Cow::Owned(ThisBee { data: Cow::Borrowed(&ay.data) }),

the lifetime of &ay.data is derived from &'2 Ay<'a>, so the type of Cow::Borrowed(&ay.data) is Cow<'2, Data>, not Cow<'a, Data> (which is what it needs to be to type check against ThisBee<'a>). This is why the error message says data from `ay` flows into `ay` here: it's trying to tell you that data from a reference of lifetime '2 can flow into a reference of lifetime 'a, which would be bad.

The message is meant to point you in the right direction when you do something like this. But since both lifetimes are attached to the same argument in your example, the error message comes out kind of weird.

Besides cloning the Cow, another way to fix this in the example is to change the type annotation on TwoBees to <'_, '_, B, ThisBee<'_>> and let the compiler figure out that '_ is shorter than the 'a on foo.

7 Likes