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?

Andrey Hanin
  • 113
  • 7

1 Answers1

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.

pigeonhands
  • 3,066
  • 15
  • 26
  • 2
    I have [opened an issue](https://github.com/rust-lang/rust/issues/107589). – pigeonhands Feb 02 '23 at 09:47
  • 1
    I definitely seems to be an inferred lifetime issue as moving `a` into the same scope as the closure definition also fixes it. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=66d000d43378f6b8046b557fcf390072 – pigeonhands Feb 02 '23 at 09:52
  • 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. – Chayim Friedman Feb 02 '23 at 13:05