5

Here is trivial reproduction (nightly rustc as of 2-feb-23):

fn main() { let closure = |_v| {}; // this one works fine // let closure = |_v: &_| {}; { let x = 1; closure(&x); } { let y = 1; closure(&y); } } 

The error is:

6 | let x = 1; | - binding `x` declared here 7 | closure(&x); | ^^ borrowed value does not live long enough 8 | } | - `x` dropped here while still borrowed ... 11 | closure(&y); | ------- borrow later used here 

Which doesn't make sense, as variable x is not captured by the closure, but is just an argument passed by reference.

Providing an explicit reference for the closure parameter _v: &_ solves the issue, but shouldn't it be inferred automatically?

Is it some bug/limitation of the borrow checker? Or I'm missing something more fundamental here?

1 Answer 1

5

This looks like it could be a bug with type inference to me.

I think what is happening is

fn main() { let closure = |_v| {}; { let x = 1; // Lifetime `a begins closure(&x); // closure is inferred to be fn(&'a i32) // Lifetime 'a end } { let y = 1; // Lifetime `b begins closure(&y); // attempt to call closure fn(&'a i32) with &'b i32 // Lifetime 'b end } } 

but defining the closure as

let closure = |_v: &'_ i32| {}; 

Stops the compiling from inferring its lifetime and uses hrtb as it should.

Sign up to request clarification or add additional context in comments.

3 Comments

I definitely seems to be an inferred lifetime issue as moving a into the same scope as the closure definition also fixes it. play.rust-lang.org/…
This may be a bug, but a well-known one and a fix isn't easy. Note that sometimes even declaring the parameter as a reference doesn't work; for these cases, we have the unstable for<'a> |v: &'a i32| syntax.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.