14
votes

I am experimenting with higher-ranked-trait bounds. In a minimal example, I created, there is a function taking a closure which takes a &str and returning a &str of the same lifetime 'a. I explicitly declared the lifetimes on the Fn trait.

fn foo(_: &for<'a> Fn(&'a str) -> &'a str) {
}

fn main() {
    foo(&|s| s);
}

This works fine. If I annotate the type of the parameter in the closure to be of type &str, I receive a lifetime error:

fn foo(_: &for<'a> Fn(&'a str) -> &'a str) {
}

fn main() {
    foo(&|s: &str| s); // explicitly specified parameter type
}

That confuses me. For several reasons.

  • Isn't the return type of the closure inferred to be of the same type as the parameter (with the same lifetime via lifetime elision)?
  • The argument of foo is univerally quantified over all possible lifetimes. Why can't the type of the lifetime be arbitrary? Isn't 'a just a placeholder for some lifetime?

It works without specifying the type explicitly, but why? How are those two versions different?

playpen code

1
I believe this may be #22557: i.e. it's a bug that the compiler isn't quite connecting the dots fully.huon
The code compiles fine as of Rust 1.23, released Jan 4, 2018.dtolnay

1 Answers

1
votes

At current version of Rust this compiles without warnings:

fn foo<T>(_: &T) where
T: for<'a> Fn(&'a str) -> &'a str
{
}

fn main() {
    foo(&|s: &str| s); // explicitly specified parameter type
}