Skip to content

Lifetime error messages could be improved. #9716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
orenbenkiki opened this issue Oct 4, 2013 · 4 comments
Closed

Lifetime error messages could be improved. #9716

orenbenkiki opened this issue Oct 4, 2013 · 4 comments
Labels
A-lifetimes Area: Lifetimes / regions

Comments

@orenbenkiki
Copy link

Here's an example I just got:

src/anthill/execution/kind.rs:124:32: 125:29 error: cannot infer an appropriate lifetime due to conflicting requirements
src/anthill/execution/kind.rs:124                                 dictionary.name_to_kind.find(&name)
src/anthill/execution/kind.rs:125                             };
src/anthill/execution/kind.rs:124:32: 124:55 note: first, the lifetime cannot outlive the expression at 124:32...
src/anthill/execution/kind.rs:124                                 dictionary.name_to_kind.find(&name)
                                                                  ^~~~~~~~~~~~~~~~~~~~~~~
src/anthill/execution/kind.rs:124:32: 124:55 note: ...due to the following expression
src/anthill/execution/kind.rs:124                                 dictionary.name_to_kind.find(&name)
                                                                  ^~~~~~~~~~~~~~~~~~~~~~~
src/anthill/execution/kind.rs:124:32: 125:29 note: but, the lifetime must be valid for the method call at 124:32...
src/anthill/execution/kind.rs:124                                 dictionary.name_to_kind.find(&name)
src/anthill/execution/kind.rs:125                             };
src/anthill/execution/kind.rs:124:32: 124:55 note: ...due to the following expression
src/anthill/execution/kind.rs:124                                 dictionary.name_to_kind.find(&name)
                                                                  ^~~~~~~~~~~~~~~~~~~~~~~

Now, I'm developing some experience with lifetimes so I have some intuition about what I did wrong. And I appreciate the effort that went into this error message! But still, saying "the lifetime can't outlive the expression X in location Y because it must be valid at the function call at exactly the same expression X in the same location Y" - that's not exactly explaining things in a way that is understandable to a newcomer (which I still am).

Perhaps there's a better way to phrase the problem, and possibly eliminate the duplications?

@alexcrichton
Copy link
Member

cc #12238

@nwin
Copy link
Contributor

nwin commented May 4, 2014

I totally agree. The current error messages are too vague. If one is not familiar with the language, it takes ages to figure out what is wrong. To give a concrete example:

pub trait BufferMe {
     fn from_buffer<'a>(buffer: &'a[u8]) -> Self;
}
pub struct Buffer<'a> {
    buffer: &'a[u8]
}

impl<'c> BufferMe for Buffer<'c> {
    // Lifetime 'a at the function is now shadowing
    fn from_buffer<'b>(buffer: &'b[u8]) -> Buffer<'b> {
        Buffer {
            buffer: buffer
        }
    }
}
fn main() {}

Gives the error message

test.rs:10:5: 14:6 error: method `from_buffer` has an incompatible type: expected concrete lifetime, but found bound lifetime parameter &'a 
test.rs:10     fn from_buffer<'b>(buffer: &'b[u8]) -> Buffer<'b> {
test.rs:11         Buffer {
test.rs:12             buffer: buffer
test.rs:13         }
test.rs:14     }
test.rs:10:55: 14:6 note: expected concrete lifetime is the lifetime &'c  as defined on the block at 10:54
test.rs:10     fn from_buffer<'b>(buffer: &'b[u8]) -> Buffer<'b> {
test.rs:11         Buffer {
test.rs:12             buffer: buffer
test.rs:13         }
test.rs:14     }

I named the relevant lifetime 'a, 'b and 'c to make my point. In my original code, they were of course all called 'a, such that I had no clue what was going on.

The first error message only gives a hint when you rename the lifetimes, but even then it is hard to figure out why he wants 'a and not 'b. It should be written where the lifetime 'a in question is defined. On top of that one should give a hint that the trait itself might be annotated with a lifetime as well. On top of that it is totally possible to shadow the lifetime of the trait with the definition in the function signature:

pub trait BufferMe<'a> {
     fn from_buffer<'a>(buffer: &'a[u8]) -> Self;
}

In that case a warning should be given that it is shadowed.

The second message is partially wrong because there is no &'c defined at 10:54. There is only a 'c introduced at 8:6.

@andrewrk
Copy link

andrewrk commented Nov 3, 2014

rust newbie here. I just got this one trying to upgrade rgtk to work with rust-nightly:

src/glib/traits.rs:46:5: 46:48 help: consider using an explicit lifetime parameter as shown: fn connect<'a>(&self, signal: Box<T>)
src/glib/traits.rs:46     fn connect<'a>(&self, signal: Box<T>) -> () {
                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/glib/traits.rs:49:22: 49:47 error: mismatched types: expected `gtk::signals::Signal<'a>`, found `gtk::signals::Signal<'a>` (lifetime mismatch)
src/glib/traits.rs:49         let signal = signal as Box<Signal<'a>>;

The types it is saying are mismatched are identical, and the suggested code change is identical to the original code.

@steveklabnik
Copy link
Member

So, this issue is pretty vague. It's true that we have room to improve errors, but since the OP didn't give any code, I can't see if it's gotten better.

@nwin's has, though. With the different names:

hello.rs:10:5: 14:6 error: method `from_buffer` has an incompatible type for trait:
 expected bound lifetime parameter 'a,
    found concrete lifetime [E0053]
hello.rs:10     fn from_buffer<'b>(buffer: &'b[u8]) -> Buffer<'b> {
hello.rs:11         Buffer {
hello.rs:12             buffer: buffer
hello.rs:13         }
hello.rs:14     }
hello.rs:10:5: 14:6 help: run `rustc --explain E0053` to see a detailed explanation
error: aborting due to previous error

and with all of them being 'a, which is what the original confusion was about:

hello.rs:10:20: 10:22 error: lifetime name `'a` shadows a lifetime name that is already in scope [E0496]
hello.rs:10     fn from_buffer<'a>(buffer: &'a[u8]) -> Buffer<'a> {
                               ^~
hello.rs:8:6: 8:8 note: shadowed lifetime `'a` declared here
hello.rs:8 impl<'a> BufferMe for Buffer<'a> {
                ^~
error: aborting due to previous error

whoo, shadowing!

As such, I'm going to give this issue a close. If any of you still have specific code with bad errors, please make new issues for them, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions
Projects
None yet
Development

No branches or pull requests

5 participants