Confused by lifetime error messages? Tell me about it!

Excellent, that worked (also fixed “&self” -> “&mut self” in insert_word()). Apparently I was confused about when you need to add a lifetime parameter to the function itself, versus just to the formal parameters of the function. The explanation re:shadowing is helpful. Cheers!

Lifetime shadowing should probably be a warning in its own right.

The answer, I suspect is to remove the redundant <'a> from the method, which in fact introduces a new lifetime parameter that shadows the one from the impl:

    fn insert_word<'a>(&self, s: &'a str) {
    //            ^~~~ remove this

I suspect that the suggestion the compiler is giving you is "correct", in that in its mind it is telling you to change from the 'a declared on the method to the 'a declared on the impl, but of course it doesn't take shadowing into account.

I have been intending for some time to introduce an RFC forbidding such shadowing. This examples reminds me of that intention!

1 Like

Lifetime shadowing like this is definitely one of my most frequent user errors with lifetimes. I eagerly await such an RFC!

Just for reference, this seems to solve it.

trait SomeTrait {
    fn say_hello(&self);
}

struct SomeStruct;

impl SomeTrait for SomeStruct {
    fn say_hello(&self) {
        println!("EH")
    }
}

struct AnotherStruct<'a> {
    some_trait: Box<SomeTrait + 'a>,
}

A little off-topic, but while we’re on the topic of lifetimes, I feel that there just isn’t enough documentation about it. The official ownership guide is quite inadequate - it barely covers the basics and while it explains theoretically why the borrow checker needs lifetimes, it fails to cover the uses practically. I mean, being fairly new to rust, whenever I try looking at the rust or servo source, half the places where lifetimes are used just go over my head. I saw the + syntax for lifetimes for the first time in this thread!

So, it would be really nice if someone who understands lifetimes would edit the guide and send in a PR. I, for one, would be really happy. In the meantime, could someone point out any other good resources for understanding lifetimes? There are sometimes hidden gems in the mailing list archives/reddit threads/IRC logs and if any of you guys know of any such places, please share them here (or better yet, create a new thread for it).

This produces a confusing error due to a mismatch between seg and the type for the keys in the map. I think. Something like that.

let map = (|| {
    let mut map = HashMap::new();
    map.insert("imo", "in my opinion");
    map
})();

for line in std::io::stdin().lock().lines().map(|l| l.unwrap()) {
    println!("{}", line.split(' ')
        .map(|seg| if map.contains_key(seg) {
            map[seg.as_slice()].to_string()
        } else {
            seg.to_string()
        }).collect::<Vec<String>>().connect(" "));
}

I spent a while on this while trying to implement an interator:

$ rustc check.rs 
check.rs:29:5: 31:6 error: method `next` has an incompatible type for trait: expected concrete lifetime, found bound lifetime parameter  [E0053]
check.rs:29     fn next(&mut self) -> Option<&Node<'a>> {
check.rs:30         Some(&self.root.nodes[0])
check.rs:31     }
check.rs:29:45: 31:6 note: expected concrete lifetime is the lifetime 'a as defined on the block at 29:44
check.rs:29     fn next(&mut self) -> Option<&Node<'a>> {
check.rs:30         Some(&self.root.nodes[0])
check.rs:31     }
error: aborting due to previous error

After reading the documentation, I had absolutely no idea what concrete or bound lifetime parameters are. Too add to my confusion, consider:

  • fn next(&mut self) -> Option<&Node<'a>> {
  • fn next(&'a mut self) -> Option<&Node<'a>> {
  • fn next(&'a mut self) -> Option<&'a Node<'a>> {
  • fn next(&mut self) -> Option<&'a Node<'a>> {

The first three give the same error message, the final one compiles. The full fixed code (n-ary tree with a useless iterator):

pub struct Node<'a> {
    pub val: &'a str,
    pub nodes: Vec<Node<'a>>,
}
impl<'a> Node<'a> {
    fn iter(&'a self) -> NodeIter<'a> {
        NodeIter {
            root: self,
            cur: 0,
        }
    }
}
struct NodeIter<'a> {
    root: &'a Node<'a>,
    cur: uint,
}
impl <'a> Iterator<&'a Node<'a>> for NodeIter<'a> {
    fn next(&mut self) -> Option<&'a Node<'a>> {
        Some(&self.root.nodes[0])
    }
}

Going off topic a bit: per prasoon2211, I’d really like the lifetime guide to go into more detail (In addition to ‘+’ and concrete and bound lifetimes, I can’t see any mention of ‘:’), either with some more complex examples or theory. For example I don’t know the difference is between all parameters being 'a and the following which also compiles (something to do with the lifetime of the reference being defined by the caller?):

impl<'b, 'c> Iterator<&'b Node<'c>> for NodeIter<'c> {
    fn next<'a>(&mut self) -> Option<&'a Node<'c>> {
        let tok: &'a Node<'c> = &self.root.nodes[0];
        return Some(tok);
    }
}

Edit: after playing some more, it seems that putting 'a everywhere is fine…if you’re then willing to accept the viral effect of having to annotate all your functions when you want an iterator (because it asserts an unnecessarily strong condition for the lifetime of values). By adding appropriate additional lifetimes I’m able to relax the conditions to get an iterator in an unannotated function.

I’m a total newbie so forgive me for the simple example, but perhaps a newbie error will help you improve the error message for other newbies. I have read the various docs but how this is all supposed to work is still not clear to me.

I am trying to make a simple lexer struct which borrows a user-provided io::Buffer (I probably need a mut in there but just to keep things simple…):

struct Reader<'a> {
    buf: &'a io::Buffer,
}

Error message is:

main.rs:8:14: 8:24 error: explicit lifetime bound required
main.rs:8     buf: &'a io::Buffer,
                       ^~~~~~~~~~

I understand that you need a lifetime bound on the borrow. I think this is due to me not understanding how traits work. The error message is especially confusing because you can see the 'a right there.

I figured out you can do

struct Reader<'a, B: io::Buffer> {
  buf: &B,
}

for a statically-dispatched trait but I expected the earlier version to be possible too.

A lifetime bound is &io::Buffer + 'a

I agree though that the error could be improved. Maybe an example in it would be helpful.

FYI adding 'a everywhere causes shadowing

someone on stackoverflow found something that i think belongs here: http://stackoverflow.com/questions/28031155/is-my-borrow-checker-drunk

Consider the following code:

pub trait Foo<'t> {
    type Bar: 't;
}

pub struct FooBar<'t, F> {
    f: F
}

impl<'t, F> Foo<'t> for FooBar<'t, F>
where F: Foo<'t>,
      <F as Foo<'t>>::Bar: 't {
    type Bar = <F as Foo<'t>>::Bar;
}

And the output for rustc 1.0.0-nightly (458a6a2f6 2015-01-25 21:20:37 +0000):

src\lib.rs:9:1: 13:2 error: the associated type `<F as Foo<'_>>::Bar` may not live long enough [E0309]
src\lib.rs:9 impl<'t, F> Foo<'t> for FooBar<'t, F>
src\lib.rs:10 where F: Foo<'t>,
src\lib.rs:11       <F as Foo<'t>>::Bar: 't {
src\lib.rs:12     type Bar = <F as Foo<'t>>::Bar;
src\lib.rs:13 }
src\lib.rs:9:1: 13:2 help: consider adding an explicit lifetime bound `<F as Foo<'_>>::Bar: 't`...
src\lib.rs:9 impl<'t, F> Foo<'t> for FooBar<'t, F>
src\lib.rs:10 where F: Foo<'t>,
src\lib.rs:11       <F as Foo<'t>>::Bar: 't {
src\lib.rs:12     type Bar = <F as Foo<'t>>::Bar;
src\lib.rs:13 }
src\lib.rs:9:1: 13:2 note: ...so that the declared lifetime parameter bounds are satisfied
src\lib.rs:9 impl<'t, F> Foo<'t> for FooBar<'t, F>
src\lib.rs:10 where F: Foo<'t>,
src\lib.rs:11       <F as Foo<'t>>::Bar: 't {
src\lib.rs:12     type Bar = <F as Foo<'t>>::Bar;
src\lib.rs:13 }

But there is an explicit lifetime bound just as the help recommends! (Or is this a bug? It looks similar to #21520.)

I was surprised that declaring a lifetime on a struct doesn't enforce it, even if I use that lifetime on self and other arguments in a method.

sorry this is not a complete file (I don’t have it in version control yet). As said in the comment in the gist, there are two structs for which I’m trying to implement the Iterator trait, one immutable and one mutable, and the mutable one fails with a lifetime error message, though they’re very, very similar in implementation.

There was a bit of input that might be useful on this reddit thread:

error: borrowed value does not live long enough

pub struct C_API_wrapper<'a> {
    handle: *mut c_void,
    _marker: &'a std::marker::PhantomData<[u8]>,
}

pub fn new<'a>(slice: &'a [u8]) -> C_API_wrapper {
  C_API_wrapper {
    handle: c_api(slice.as_ptr()),
    _marker: &std::marker::PhantomData::<[u8]>,
  }
}

I've tried to read the docs, but I can't comprehend what they're saying (if somebody could explain it without covariance jargon, that'd be great).

This is a lifetime error in the following code snippet. I can fix it by either adding a semicolon at the end of the match, or not having the VecCell enum variant. I’m not quite certain why having the Ref causes the lifetime message. This is as small as I could get it to still fail:

use std::cell::Ref;

pub trait Chunk {
    fn data<'a>(&'a self) -> Data<'a>;
}

pub enum Data<'a> {
    Unimportant,

    // Uncomment Ptr, and comment out VecCell to eliminate the error.
    VecCell(Ref<'a, Option<Vec<u8>>>),
    // Ptr(&'a [u8]),
}

struct PlainChunk;

impl Chunk for PlainChunk {
    fn data<'a>(&'a self) -> Data<'a> {
        Data::Unimportant
    }
}

fn main() {
    let c1 = PlainChunk;

    match c1.data() {
        _ => ()
    }
    // A semicolon here will also remove the error.
    // ;
}

Upon compilation I get:

chunk.rs:26:11: 26:13 error: `c1` does not live long enough
chunk.rs:26     match c1.data() {
                      ^~
chunk.rs:23:11: 31:2 note: reference must be valid for the destruction scope surrounding block at 23:10...
chunk.rs:23 fn main() {
chunk.rs:24     let c1 = PlainChunk;
chunk.rs:25 
chunk.rs:26     match c1.data() {
chunk.rs:27         _ => ()
chunk.rs:28     }
            ...
chunk.rs:24:24: 31:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 24:23
chunk.rs:24     let c1 = PlainChunk;
chunk.rs:25 
chunk.rs:26     match c1.data() {
chunk.rs:27         _ => ()
chunk.rs:28     }
chunk.rs:29     // A semicolon here will also remove the error.
            ...
error: aborting due to previous error

Again, I don’t quite understand the error, and I’m not sure if this is an unclear error message, an actual bug, or both.

@d3zd3z It is a known bug:

1 Like

I asked about this on irc and thought I understood what was going on. I posted a simplified version on reddit and kibwen got different results when building it by hand, which reconfused me.

The code that originally triggered the discussion was:

impl Clause {
    fn constrained_to(&self, result: &Vec<Value>) -> Vec<Value> {
        match *self {
            Clause::Tuple(ref source) => {
                let mut relation = source.constrained_to(result);
                relation.drain().map(|tuple| Value::Tuple(tuple)).collect()
            },
            Clause::Relation(ref source) => {
                let relation = source.constrained_to(result);
                vec![Value::Relation(relation)]
            },
            Clause::Call(ref call) => {
                let value = call.eval(result);
                vec![value]
            }
        }
    }
}

This gives:

   Compiling eve v0.0.1 (file:///home/jamie/eve/runtime)
src/solver.rs:92:17: 92:25 error: `relation` does not live long enough
src/solver.rs:92                 relation.drain().map(|tuple| Value::Tuple(tuple)).collect()
                                 ^~~~~~~~
src/solver.rs:90:43: 93:14 note: reference must be valid for the destruction scope surrounding expression at 90:42...
src/solver.rs:90             &Clause::Tuple(ref source) => {
src/solver.rs:91                 let mut relation = source.constrained_to(result);
src/solver.rs:92                 relation.drain().map(|tuple| Value::Tuple(tuple)).collect()
src/solver.rs:93             },
src/solver.rs:91:61: 93:14 note: ...but borrowed value is only valid for the block suffix following statement 0 at 91:60
src/solver.rs:91                 let relation = source.constrained_to(result);
src/solver.rs:92                 relation.drain().map(|tuple| Value::Tuple(tuple)).collect()
src/solver.rs:93             },
error: aborting due to previous error
Could not compile `eve`.

Both of these modifications work fine:

            Clause::Tuple(ref source) => {
                let relation = source.constrained_to(result);
                relation.into_iter().map(|tuple| Value::Tuple(tuple)).collect()
            },
            Clause::Tuple(ref source) => {
                let mut relation = source.constrained_to(result);
                let result = relation.drain().map(|tuple| Value::Tuple(tuple)).collect();
                result
            },