Figuring out how to compile without elided lifetimes


#1

I’m trying to figure out how to write this snippet of code without using lifetime elision, and am stumped so far. The code compiles fine with lifetime elision, but I can’t find any combination of sticking 'as and 'bs around that makes it compile once there is a lifetime parameter specified in FnOnce(HasAReference).

struct Example;

struct HasAReference<'o> {
    r: &'o Example
}

impl Example {
    pub fn use_mutable_self(&mut self) { }

    pub fn works_with_elision<F>(&mut self, f: F) where F: FnOnce(HasAReference) {
        f(HasAReference{ r: self });
        self.use_mutable_self();
    }
}

Here are the things I’ve tried:

  • This works, but has no explicit lifetime parameter on the HasAReference:
    pub fn works_with_some_elision<'a, F>(&'a mut self, f: F) where F: FnOnce(HasAReference)
  • In this one, the use_mutable_self call is disallowed because self is already borrowed
    pub fn unelided_1<'a, F>(&'a mut self, f: F) where F: FnOnce(HasAReference<'a>) {
  • This one complains about conflicting requirements:
    pub fn unelided_2<'a, 'b, F>(&'a mut self, f: F) where F: FnOnce(HasAReference<'b>) {

Every other combination of things I’ve tried gives one of these messages or the other. I’ve put my attempts so far in the playpen here.

(I am not trying to use explicit lifetimes for the heck of it – I have a more complicated thing that elision won’t work for, and this is my minimized-but-still-baffling example.)

I appreciate any help!


#2

It looks like it needs to be this, but I don’t have a good understanding of why yet:

    pub fn works_with_elision<'a, F>(&'a mut self, f: F) where 
        F: for<'b> FnOnce(HasAReference<'b>) {
        f(HasAReference { r: self });
        self.use_mutable_self();
    }

See the RFC for higher-ranked trait bounds for an explanation (I think).


#3

Thanks! That is not something I would have figured out any time soon.