Why can't Rust infer this closure lifetime?

I have some code that implements a trait for all Fn(&str) closures:

trait Target {}

impl<T: Fn(&str)> Target for T {}

fn takes(_: impl Target) {}

fn test() {
    takes(|_| {});
}

The function call fails to compile:

  = note: closure with signature `fn(&'2 str)` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`...
  = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2`

Rust can figure out the type, but it botches the lifetimes. But if I give the parameter a type myself, it works:

takes(|_: &str| {});

Why is that needed? Can I fix the definition somehow so Rust can infer the lifetime properly?

(Playground link)

Type inference of closures with HRTBs involved has always been pretty junky. (The Fn(&str) is equivalent to for<'a> Fn(&'a str), and those for<'a> bounds are called HRTBs, Higher Ranked Trait Bounds)

See Confusing type error due to strange inferred type for a closure argument · Issue #41078 · rust-lang/rust · GitHub

3 Likes

The only thing you can do in that regard is forgo the Target trait and require an explicit impl Fn(&str) parameter.

1 Like

Thanks. I guess I'll have to avoid traits for this then.

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.