What's going on with Higher Rank Trait Bounds

This is an example using HRTB:

struct S {
	var1: i32,
	var2: i32,
}

impl S
{
    fn extract<F>(&self, f: F) -> &i32
      where F: Fn(&S) -> &i32
    {
        f(self)
    }
}

fn main() {
    let var = S { var1: 1, var2: 2};
    let ptr_to_var1 = var.extract(| s | &s.var1);
    println!("{}", ptr_to_var1);
}

We know that the where clause in extract function actually means: where F: for <'f> Fn(&'f S) -> &'f i32.

But if I wrote as below, it still compiles by latest version of rustc [rustc 1.21.0-nightly (c11f689d2 2017-08-29)].

impl S
{
    fn extract<'a, F>(&'a self, f: F) -> &'a i32
      where F: Fn(&'a S) -> &'a i32
    {
        f(self)
    }
}

fn ext(s: &S) -> &i32 { &s.var2 }

fn main() {
    let var = S { var1: 1, var2: 2};
    let ptr_to_var1 = var.extract(ext);
    println!("{}", ptr_to_var1);
}

And I remember that this piece of code was rejected by compiler several months ago. I don't know what's happened in this period, could anyone can explain that? When should I use a HRTB while not using lifetime ellision?

The 2nd version happens to compile due to normal lifetimes of arguments - caller (i.e. main) owns the S value and selects the lifetime for the struct (the 'a lifetime) that fits.

To see the need for HRTB try to create a fresh S inside extract and pass that to the closure - that should fail without HRTB.

Thank you. Your test case is very helpful for me to understand HRTB.

I'm still curious why my test case doesn't compile several months ago. Does that mean there was a bug before and now it is fixed?

I tried running both of your code samples with Rust 1.0.0 (from May 2015) and they both worked. Can you remember anything that was different in the code before?

Thanks. There must be something important I misremembered. Maybe the lifetime was associated with the struct but not the method.

Thank you all ! I think I understand HRTB better than before.