Confused by lifetime error messages? Tell me about it!

I would like to see the lifetime errors that you encounter in your programs (along with the source that causes the error) and (ideally) the fix you eventually found. I want to use this to help make the error messages better. I am primarily thinking of those errors that begin with “cannot infer an appropriate lifetime”, but any lifetime-related error message is fair game.

I was hoping people could post comments in this thread with:

  1. a link to the source (preferably a speciic revision on github) of some project where a lifetime error occurs, preferably one that you found confusing;
  2. if available, a diff required to fix the error. If you don’t know how to fix it, maybe I can fix it for you.

Thanks!

3 Likes

I’m terribly sorry I can’t remember the example, but I recently fought with the compiler when it said cannot infer an appropriate lifetime, try adding <'a>, which upon doing so, since I was implementing a Trait, the compiler then said expected concrete lifetime, but found bound lifetime <'a>.

struct Event<'a> {
    f: &'a |data: &str|
}

error: missing lifetime specifier [E0106]

It's not obvious that the syntax for closure lifetimes is different, so the user will try the normal syntax and it won't work.

3 Likes

That is helpful nonetheless – it’s certainly true that the suggestion mechanism doesn’t take into account whether this is a trait method.

Good timing! I just found these two errors yesterday, and I have to admit that I have no idea what they mean:

Error 1

error: mismatched types: expected core::option::Option<|&mut Bencher|> but found core::option::Option<'static |&mut Bencher|:'static> (expected no bounds but found 'static)

Error 2

error: mismatched types: expected core::option::Option<|&mut Bencher|> but found core::option::Option<|&mut Bencher|> (expected concrete lifetime, but found bound lifetime parameter )

Here's a minimal code that produces similar errors:

struct Closure<'a>(||:'a);
struct ClosureOpt<'a>(Option<||:'a>);

fn new(closure: ||:'static) {
    Closure(closure);
}

// Error 1
fn opt(closure: ||:'static) {
    ClosureOpt(Some(closure));
}

fn new_with_input(closure: |&int|:'static, inputs: &[int]) {
    for input in inputs.iter() {
        Closure(|| closure(input));
    }
}

fn opt_with_input(closure: |&int|:'static, inputs: &[int]) {
    for input in inputs.iter() {
        ClosureOpt(Some(|| closure(input)));
    }
}

struct Foo;

struct FooClosure<'a>(Option<|&mut Foo|:'a>);

// Error 2
fn foo(closure: |&mut Foo, &int|:'static, inputs: &[int]) {
    for input in inputs.iter() {
        FooClosure(Some(|f| closure(f, input)));
    }
}

fn main() {}

My (hacky) solution is to call mem::transmute on the closure before storing it in the Some variant. e.g. ClosureOpt(Some(unsafe { std::mem::transmute(closure) }))

I've encountered these errors in my benchmarking library, but I haven't pushed the changes that include these issues and my hacky workarounds. So, here is a minimal reproduction of my usage pattern.

I am primarily thinking of those errors that begin with "cannot infer an appropriate lifetime"

There are six stackoverflow questions with that phrase:

Just ran into this one while writing tests. Maybe more an issue with macros, asserts, or just the way we automatically make a convenience reference to a literal, but it appears as a lifetime issue:

fn main() {
    let mut a = vec![1i,2,3];
    let mut b = a.mut_iter();
    assert_eq!(b.next(), Some(&mut 1i));
}
<anon>:4:36: 4:38 error: borrowed value does not live long enough
<anon>:4     assert_eq!(b.next(), Some(&mut 1i));
                                            ^~
<std macros>:1:1: 14:2 note: in expansion of assert_eq!
<anon>:4:5: 4:41 note: expansion site
<anon>:1:11: 5:2 note: reference must be valid for the block at 1:10...
<anon>:1 fn main() {
<anon>:2     let mut a = vec![1i,2,3];
<anon>:3     let mut b = a.mut_iter();
<anon>:4     assert_eq!(b.next(), Some(&mut 1i));
<anon>:5 }
<std macros>:2:40: 13:6 note: ...but borrowed value is only valid for the statement at 2:39; consider using a `let` binding to increase its lifetime
<std macros>:2     ($given:expr , $expected:expr) => ({
<std macros>:3         match (&($given), &($expected)) {
<std macros>:4             (given_val, expected_val) => {
<std macros>:5                 // check both directions of equality....
<std macros>:6                 if !((*given_val == *expected_val) &&
<std macros>:7                      (*expected_val == *given_val)) {
               ...
<std macros>:1:1: 14:2 note: in expansion of assert_eq!
<anon>:4:5: 4:41 note: expansion site
error: aborting due to previous error

fixable by moving the iterator’s creation into the assert:

fn main() {
    let mut a = vec![1i,2,3];
    assert_eq!(a.mut_iter().next(), Some(&mut 1i));
}

but that’s not really useful if you want to test a whole bunch of values.

This also works, and actually lets you reuse the iterator, but is of course annoying:

fn main () {
    let mut a = vec![1i,2,3];
    let mut b = a.mut_iter();
    assert_eq!(&*b.next().unwrap(),  &1);
}
1 Like

This is of limited help since I do not remember what I was doing when I got this error, but I recently received an error where the note was “note: first, the lifetime cannot outlive lifetime ReInfer(ReSkolemized(0u, BrAnon(0u)))…”". I’ll see if I can reproduce that, somehow.

Yes, I’ve seen those from time to time. They’re not supposed to happen but I know that they do…it’d be good to have a small-ish example that produces such an error message.

Thanks. Of course what you really want here is to improve the assert_eq macro (or possibly some other aspect of the system) so that the error doens’t occur in the first place…

Hey, so it took me a few days to look into this. The first error you are receiver is a bug in the compiler, I believe. When I test it with my branch that cleans up a lot of the code in this area, I no longer see that message.

The second message, well, it could also be seen as a bug in the compiler. It’s a case of inference failure – basically sometimes we’re not able to infer the types of parameters as well as we like. I filed an issue but you can workaround it by manually annotating the type of the parameter like this:

fn foo(closure: |&mut Foo, &int|:'static, inputs: &[int]) {
    for input in inputs.iter() {
        FooClosure(Some(|f: &mut Foo| closure(f, input)));
    }
}

…and thanks, I’ll see whether we can improve messages in the inference failure case.

Good to know that it gets fixed by that PR.

The workaround works here.

Thanks for taking the time to look into these issues. :+1:


BTW, I found a way to reproduce the ReSkolemized issue mentioned by @nham. Here's the STR:

struct Sample<S>(S);

impl<A, S: Vector<A>> Sample<S> {
    fn compute(&self, statistic: fn(&Sample<&[A]>) -> A) {
        unimplemented!()
    }
}

fn mean<S: Vector<f64>>(sample: &Sample<S>) -> f64 {
    unimplemented!()
}

fn main() {
    Sample(Vec::from_elem(100, 0f64)).compute(mean);
}

And the error message is:

reskolemized.rs:14:47: 14:51 error: cannot infer an appropriate lifetime for lifetime parameter `'a due to conflicting requirements
reskolemized.rs:14     Sample(Vec::from_elem(100, 0f64)).compute(mean);
                                                                 ^~~~
reskolemized.rs:14:5: 14:52 note: first, the lifetime cannot outlive the method call at 14:4...
reskolemized.rs:14     Sample(Vec::from_elem(100, 0f64)).compute(mean);
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reskolemized.rs:14:47: 14:51 note: ...so that argument is valid for the call
reskolemized.rs:14     Sample(Vec::from_elem(100, 0f64)).compute(mean);
                                                                 ^~~~
note: but, the lifetime must be valid for lifetime ReInfer(ReSkolemized(1u, BrAnon(1u)))...
reskolemized.rs:14:47: 14:51 note: ...so that traits are compatible (expected `core::slice::Vector<f64>` but found `core::slice::Vector<f64>`)
reskolemized.rs:14     Sample(Vec::from_elem(100, 0f64)).compute(mean);
                                                                 ^~~~
error: aborting due to previous error

Some things that seems odd to me in that error message:

  • It mentions the 'a lifetime, but 'a doesn't appear in the code
  • expected core::slice::Vector<f64> but found core::slice::Vector<f64>
  • ReInfer(ReSkolemized(1u, BrAnon(1u)))
1 Like

This Reddit thread is about a confusing lifetime error: http://www.reddit.com/r/rust/comments/2dp4ue/lifetime_woes_and_hashmap_benchmarks/

Another reddit thread about a lifetime issue (with a fix reported to be incoming).

I recently encountered this error. error: mismatched types: expected `&level_object::LevelObject`, found `&level_object::LevelObject` (expected &-ptr, found &-ptr) It turned out the pointer I was providing had a shorter lifetime than what was wanted, but it was hard to figure that out from this confusing error message.

Someone brought this up in the IRC last night and the error message still doesn’t make sense to me. I would expect something different.

Code:

use std::mem::transmute;

struct Cell {
    is_on: bool,
}

struct Environment<'a> {
    cells: Vec<Cell>,
    current_cell: &'a Cell,
}


impl Cell {
    fn new(status: bool) -> Cell {
        Cell {
            is_on: status,
        }
    }
}

fn main() {
    unsafe {
        let v = vec![Cell::new(false), Cell::new(false)];

        let curr = transmute::<&Cell, &Cell>(&v[0]);
        let mut env = Environment { cells: v, current_cell: curr };

        {
            let e = &mut env;
            e.current_cell = &e.cells[1];
        }

        {
            let e = &mut env;
        }
    }
}

Error message:

mutable_borrow_for_loop_2.rs:34:26: 34:29 error: cannot borrow `env` as mutable more than once at a time
mutable_borrow_for_loop_2.rs:34             let e = &mut env;
                                                         ^~~
mutable_borrow_for_loop_2.rs:29:26: 29:29 note: previous borrow of `env` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `env` until the borrow ends
mutable_borrow_for_loop_2.rs:29             let e = &mut env;
                                                         ^~~
mutable_borrow_for_loop_2.rs:36:6: 36:6 note: previous borrow ends here
mutable_borrow_for_loop_2.rs:22     unsafe {
...
mutable_borrow_for_loop_2.rs:36     }
                                    ^
error: aborting due to previous error

I would expect “cannot borrow as mutable because it is also borrowed as immutable”, but it’s likely that I’m missing something.

Here’s one I got after updating to latest master:

base/fuse.rs:21:13: 21:23 error: explicit lifetime bound required
base/fuse.rs:21   expr: &'a Expression
                            ^~~~~~~~~~

This was utterly inscrutable. I couldn’t figure it out and ended up asking about it in IRC. People correctly pointed out I needed to change the code to &'a Expression + 'a. The error message needs to be better, because without the lovely people in IRC I wouldn’t have figured this out.

Just adding an example like consider adding "+ 'a" would do wonders.

4 Likes

These ‘explicit lifetime bound required’ errors are extremely unhelpful and confusing.

It would be really useful if they included a suggestion, eg. try: &'a Foo + 'a, or T: Foo + 'a as appropriate.

Idly for anyone else who wonders where this came from; https://github.com/rust-lang/rust/issues/16462

5 Likes
struct SmoothMovement<F, T : cgmath::Vector<F>> {
      goal: T,
      current: T,            
      smoothness: F,
}

impl<F> SmoothMovement<F, cgmath::Vector<F>>{}   

src/ui/piston.rs:254:27: 254:44 error: explicit lifetime bound required
src/ui/piston.rs:254 impl<F> SmoothMovement<F, cgmath::Vector<F>> {

I’ve discovered this fixed it:

impl<F, T : cgmath::Vector<F>> SmoothMovement<F, T> {```

But the error is confusing.