Lifetime problem within closure

my code

pub struct PistonRenderContext<'a> {
    c: Context,
    g: &'a mut G2d<'a>,
    arguments: &'a RenderArgs,
    device: &'a gfx_device_gl::Device,
}

impl<'a> PistonRenderContext<'a> {
    fn new(
        c: Context,
        g: &'a mut G2d<'a>,
        arguments: &'a RenderArgs,
        device: &'a mut gfx_device_gl::Device,
    ) -> PistonRenderContext<'a> {
        PistonRenderContext{c, g, arguments, device }
    }
}
// within some function
            Loop::Render(render_args) => {
                self.window.draw_2d(&event, |c, g, device| {
                    clear([1.0; 4], g);
                    let ctx = PistonRenderContext::new(c, g, &render_args, device);
                    game.render(&ctx, resources);
                });
            }

the error :

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/abstraction/piston_abstraction.rs:94:31
   |
94 |                     let ctx = PistonRenderContext::new(c, g, &render_args, device);
   |                               ^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #4 defined on the body at 92:45...
  --> src/abstraction/piston_abstraction.rs:92:45
   |
92 |                   self.window.draw_2d(&event, |c, g, device| {
   |  _____________________________________________^
93 | |                     clear([1.0; 4], g);
94 | |                     let ctx = PistonRenderContext::new(c, g, &render_args, device);
95 | |                     game.render(&ctx, resources);
96 | |                 });
   | |_________________^
note: ...so that reference does not outlive borrowed content
  --> src/abstraction/piston_abstraction.rs:94:76
   |
94 |                     let ctx = PistonRenderContext::new(c, g, &render_args, device);
   |                                                                            ^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #3 defined on the body at 92:45...
  --> src/abstraction/piston_abstraction.rs:92:45
   |
92 |                   self.window.draw_2d(&event, |c, g, device| {
   |  _____________________________________________^
93 | |                     clear([1.0; 4], g);
94 | |                     let ctx = PistonRenderContext::new(c, g, &render_args, device);
95 | |                     game.render(&ctx, resources);
96 | |                 });
   | |_________________^
note: ...so that the expression is assignable
  --> src/abstraction/piston_abstraction.rs:94:59
   |
94 |                     let ctx = PistonRenderContext::new(c, g, &render_args, device);
   |                                                           ^
   = note: expected `&mut gfx_graphics::back_end::GfxGraphics<'_, gfx_device_gl::Resources, gfx_device_gl::command::CommandBuffer>`
              found `&mut gfx_graphics::back_end::GfxGraphics<'_, gfx_device_gl::Resources, gfx_device_gl::command::CommandBuffer>`

error: aborting due to previous error; 2 warnings emitted

I do not understand the error and I do not understand why the thing do not work
In my opinion lifetime is completely fine

Off the top of my head, Iā€™m noticing this kind of pattern here which is almost never the correct thing to do in Rust

&'a mut G2d<'a>

try introducing a second lifetime parameter 'b to PistonRenderContext and using

&'a mut G2d<'b>
2 Likes

It seems like your code has at once too many and too few lifetimes: PistonRenderContext has only one lifetime parameter but it uses it 4 times. That's implausible. If you're just spamming 'a because the compiler told you a lifetime was required, you're probably putting it in places where it doesn't belong. That will lead to confusing errors like this.

You can sometimes get better error messages from the compiler if you don't tell it to unify any lifetimes:

pub struct PistonRenderContext<'a, 'g2d, 'args, 'device> {
    c: Context,
    g: &'g2d mut G2d<'a>,
    arguments: &'args RenderArgs,
    device: &'device gfx_device_gl::Device,
}

This gives the compiler maximum freedom to choose whatever lifetimes make things work.

Four lifetime parameters is a lot for one struct. You might want to look at ways to reduce the amount of borrowing going on here (for example, by using Arc instead).

3 Likes