Weird borrowcheck error unless I add a type annotation

The following code (MRE'ized from my actual code) fails to compile with E0597 "uni does not live long enough", but compiles fine if I add a &_ type annotation to the closure. What is going on? Some implicit HRTB shenanigans? Based on E0597 it would never ever have occurred to me to try the solution, luckily I found it more or less by accident. :exploding_head: (Playground)

trait Shader<Uni> {
    fn shade(_: Uni);
}

struct Context<Sh> {
    shader: Sh,
}

impl<U, F: Fn(U)> Shader<U> for F {
    fn shade(_: U) {}
}

fn render<'u, Uni, Sh>(_u: &'u Uni, _ctx: &mut Context<Sh>)
where
    Sh: Shader<&'u Uni>,
{
}

fn main() {
    
    let mut ctx = Context { shader: |_| {} }; // FAILS
    //let mut ctx = Context { shader: |_: &_| {} }; // WORKS

    for _ in 1..1 {
        let uni = 42;
        render(&uni, &mut ctx);
//             ^^^^  -------- borrow later used here
//             |
//             borrowed value does not live long enough
    }
//  - `uni` dropped here while still borrowed
}

An observation to make things even more confusing:

If I change the failing line to

let mut ctx = Context { shader: |_: ()| {} };

Then the error that yields makes clear that the compiler can infer that the type of the parameter to the closure is supposed to be &{integer} (as opposed to e.g. {integer}).

With closures and type inference... it tends to be the case that |_| can only infer a reference type with a single fixed lifetime, whereas |_: &_| makes the closure generic over the reference's lifetime. At least unless the compiler already got a sufficiently “visible” hint as to what type the closure must be at the point it was defined.[1] I couldn't tell you why thats the case, but it's a useful thing to know.


  1. E. g. something like a Fn trait bound with a generic lifetime (i. e. a HRTB) directly on the function the closure is passed to ↩︎

1 Like

In other words, |_| { ... } is inferred to be |_: &'some_specific_lifetime _| {...}, while |_: &_| { ... } - to be (pseudo-Rust) for <'a> |_: &'a _| { ... }.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.