Confused by lifetime error messages? Tell me about it!


#1

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!


#2

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>.


#4
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.


#5

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


#6

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.


#7

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

There are six stackoverflow questions with that phrase:


#8

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);
}

#9

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.


#10

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.


#11

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…


#12

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)));
    }
}

#13

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


#14

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)))

#15

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


#17

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


#18

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.


#19

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.


#20

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.


#21

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


#22
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.