"explicit lifetime required in the type of `[variable]`" loophole

Hello,
I've got myself stuck with a loophole, seemingly without an exit.
https://github.com/liquid600pgm/rapid/blob/master/src/gfx.rs#L198-L209
Line 201 reports the following error on compilation:

error[E0621]: explicit lifetime required in the type of `graphics`
   --> src/gfx.rs:201:31
    |
198 |     fn execute<D>(target: &mut glium::Frame, graphics: &mut Gfx<'c>, fn_draw: D)
    |                                                        ------------ help: add explicit lifetime `'c` to the type of `graphics`: `&'c mut gfx::Gfx<'c>`
...
201 |             target, graphics: graphics,
    |                               ^^^^^^^^ lifetime `'c` required

The problem is, when I add the explicit lifetime 'c to the type of graphics, another error appears (without solving the first one), which I don't know a solution for:
https://github.com/liquid600pgm/rapid/blob/master/src/gfx.rs#L127-L132

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'c` due to conflicting requirements
   --> src/gfx.rs:130:9
    |
130 |         GfxContext::execute(&mut target, self, drawfn);
    |         ^^^^^^^^^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 127:5...
   --> src/gfx.rs:127:5
    |
127 | /     fn run_loop<'f, D>(&mut self, drawfn: D)
128 | |         where D: Fn(&mut GfxContext) {
129 | |         let mut target = self.display.draw();
130 | |         GfxContext::execute(&mut target, self, drawfn);
131 | |         target.finish().unwrap();
132 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
   --> src/gfx.rs:130:42
    |
130 |         GfxContext::execute(&mut target, self, drawfn);
    |                                          ^^^^
note: but, the lifetime must be valid for the lifetime 'g as defined on the impl at 52:6...
   --> src/gfx.rs:52:6
    |
52  | impl<'g> Gfx<'g> {
    |      ^^
    = note: ...so that the expression is assignable:
            expected &mut gfx::Gfx<'_>
               found &mut gfx::Gfx<'g>

rustc does give me some details about the error, but I don't know how to fix it. I tried to fix the error by changing the lifetime of self, but it seems impossible to do.
Feel free to browse my code to better understand my problem.
I'm trying to come up with a solution for roughly two hours now, and still don't know how to approach it.

You'll want to introduce a second lifetime parameter on GfxContext to differentiate the lifetime of the mutable borrow of Gfx vs Gfx's own lifetime, e.g.:

pub struct GfxContext<'c, 'gfx: 'c> {
    target: &'c mut glium::Frame,
    graphics: &'c mut Gfx<'gfx>,
    properties: &'c mut GfxContextProperties<'c>
}

After that change, your draw() can be:

fn draw<D>(target: &mut glium::Frame, graphics: &mut Gfx<'_>, fn_draw: D)
        where D: Fn(&mut GfxContext)

In general, if you have a mutable borrow over some type that has its own lifetime parameter, you'll want two different lifetime parameters: one (shorter, the 'c in my example) for the mutable borrow, and the second (longer, 'gfx in the example) for the type itself. This comes up when you have mutable references, which make the type behind the reference invariant in its lifetime, giving the compiler less flexibility over the concrete lifetimes/scopes its able to pick (and thus leads to more trouble for you since it'll barf with errors :slight_smile:), especially when you also use that lifetime parameter for other fields of the struct (as in your case, 'c is also used for the other fields).

2 Likes