Skip to content
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

borrowed value does not live long enough in closure #76627

Open
95th opened this issue Sep 12, 2020 · 4 comments
Open

borrowed value does not live long enough in closure #76627

95th opened this issue Sep 12, 2020 · 4 comments
Labels
A-closures Area: closures (`|args| { .. }`) C-bug Category: This is a bug.

Comments

@95th
Copy link
Contributor

95th commented Sep 12, 2020

From Stackoverflow:

https://stackoverflow.com/questions/63856055/borrow-checker-complains-for-closure-inside-loop-if-type-not-provided-explicitly

I tried this code:

fn f1(v: &str) {
}

fn main() {
    let c = |v| f1(v);
    for _ in 0..1 {
        let s = String::new();
        c(&s);
    }
}

I expected to see this happen: Code compiles

Instead, this happened: Got below error:

   |
10 |         c(&s);
   |         - ^^ borrowed value does not live long enough
   |         |
   |         borrow later used here
11 |     }
   |     - `s` dropped here while still borrowed

But if I add explicit type to closure, code compiles let c = |v: &str| f1(v);

Meta

rustc --version --verbose:

cargo 1.46.0 (149022b1d 2020-07-17)
release: 1.46.0
commit-hash: 149022b1d8f382e69c1616f6a46b69ebf59e2dea
commit-date: 2020-07-17
@95th 95th added the C-bug Category: This is a bug. label Sep 12, 2020
@95th
Copy link
Contributor Author

95th commented Sep 23, 2020

Minimized a bit:

fn main() {
    let c = |v| {};
    for _ in 0..1 {
        let s = ();
        c(&s);
    }
}

@95th
Copy link
Contributor Author

95th commented Sep 23, 2020

Running below gives error:

fn main() {
    let c = |v| {};
    x(c);
    y(c);
    for _ in 0..1 {
        let s = ();
        c(&s);
    }
}

fn x<F>(_: F) where for<'a> F: FnMut(&'a ()) {}
fn y<'a, F>(_: F) where F: FnMut(&'a ()) {}

gives:

error[E0308]: mismatched types
 --> src/main.rs:3:5
  |
3 |     x(c);
  |     ^ one type is more general than the other
  |
  = note: expected type `std::ops::FnOnce<(&'a (),)>`
             found type `std::ops::FnOnce<(&(),)>`

but running below gives no error:

fn main() {
    let c = |v: &()| {};
    x(c);
    y(c);
    for _ in 0..1 {
        let s = ();
        c(&s);
    }
}

fn x<F>(_: F) where for<'a> F: FnMut(&'a ()) {}
fn y<'a, F>(_: F) where F: FnMut(&'a ()) {}

Seems like an inference problem.

@camelid camelid added the A-closures Area: closures (`|args| { .. }`) label Sep 24, 2020
@viluon
Copy link

viluon commented Nov 7, 2021

I think I ran into this issue a couple of hours ago. The following does not compile:

fn main() {
    struct Ref<'a>(&'a ());
    let closure = |x| Ref(x);

    while let Some(x) = None {
        closure(&x);
    }
}
error[E0597]: `x` does not live long enough
 --> src/main.rs:6:17
  |
6 |         closure(&x);
  |         ------- ^^ borrowed value does not live long enough
  |         |
  |         borrow later used here
7 |     }
  |     - `x` dropped here while still borrowed

(playground)

However, change while let to if let and it compiles.

-    while let Some(x) = None {
+    if let Some(x) = None {
         closure(&x);

However, duplicate the if let statement and it again does not compile.

     if let Some(x) = None {
         closure(&x);
     }
+
+    if let Some(x) = None {
+        closure(&x);
+    }
error[E0597]: `x` does not live long enough
  --> src/main.rs:6:17
   |
6  |         closure(&x);
   |                 ^^ borrowed value does not live long enough
7  |     }
   |     - `x` dropped here while still borrowed
...
10 |         closure(&x);
   |         ------- borrow later used here

(playground)

You can fix either of the failing examples by adding a lifetime-polymorphic type annotation to the closure:

-    let closure = |x| Ref(x);
+    let closure: for<'a> fn(&'a ()) -> Ref<'a> = |x| Ref(x);

or by manually inlining the closure:

-        closure(&x);
+        Ref(&x);

@martin-t
Copy link

martin-t commented Nov 7, 2021

Could this be related to #86921 ? There is at least some superficial similarity in that closure lifetimes are not inferred correctly although in this case the error is at the call site while in #86921 the declaration itself is rejected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: closures (`|args| { .. }`) C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

4 participants