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
NLL: Poor borrow checker error message when extension of borrow happens indirectly (e.g. via method) #54256
Comments
Note for team: tried it locally; the error message is the same with and without |
I've added to the RC2 milestone but I consider this a "nice to have". That said, I've been wanting for a while to have borrows be able to explain better how the reference came to be used at a particular spot — this overlaps with other sorts of region errors that could make use of a similar trace. It'd be helpful to brainstorm what we think the error should look like, I think. |
Can we maybe get a standalone example that doesn't use |
@nikomatsakis Here's a smaller example (playground link): #![feature(nll)]
struct Parent;
struct Child<'a>(Option<&'a Parent>);
// the signature implies that the child borrows the parent
fn adopt<'a>(p: &'a Parent, c: &mut Child<'a>) {
c.0 = Some(p);
}
fn main() {
let mut parents: Vec<Parent> = vec![];
let mut children: Vec<Child<'_>> = vec![];
for _ in 0..2 {
parents.push(Parent);
let p = parents.last().unwrap();
children.push(Child(None));
let c = children.last_mut().unwrap();
adopt(p, c); // comment this line to make the program compile
}
} Error:
Removing It's important to note that, even though in this example it's fairly obvious that |
Removing from the Rust 2018 milestone -- this is not a Rust 2018 blocker. |
NLL triage. Made title more informative. P-medium. |
Diagnostics triage: we believe this issue can be resolved by explaining why something is being borrowed instead of just where. Will need some digging in the NLL diagnostics machinery. |
This now produces the same error message both with and without |
I don't know if it helps, but even without the
We get the same error message:
|
I hit this using httparse, in a way that looks like this: use std::marker::PhantomData;
struct Parser<'headers, 'buf>(PhantomData<(&'headers (), &'buf ())>);
impl<'headers, 'buf> Parser<'headers, 'buf> {
fn new(_headers: &'headers mut ()) -> Self {
Self(PhantomData)
}
fn get_thing(&self) -> &str {
"nya"
}
fn parse(&mut self, _buf: &'buf [u8]) {}
}
fn main() {
let mut headers = ();
let mut buf = Vec::new();
let mut p = Parser::new(&mut headers);
p.parse(&buf);
buf.clear();
p.get_thing();
} Error:
I think that qualitatively the reason that this is confusing to me is that most of the time, if you lend something a reference, it gives it back right after. I wound up confused because in this case, the reference is made to outlive the lifetime of another value and is not given back. So a more helpful diagnostic for this particular problem needs to point out this condition being at play: a lifetime is extended by the function call. |
EDIT: Go here for a smaller example.
Code:
Error:
The crux of the problem is that at line
visit(child, desc)
,table
starts borrowingtu
because it has typeHashMap<String, SymbolDesc<'tu>>
. This preventstus.push(index.parser(source).parse()?)
because it needs a mutable borrow.I wish the error message mentioned that
table
borrowstu
because that's far from obvious. But once you see it, it's understandable why the borrow checker is not happy.The text was updated successfully, but these errors were encountered: