Cannot infer an appropriate lifetime for autoref due to conflicting requirements when iterating over a HashMap


#1

Hello,
I’m currently going through a lot of pain with lifetimes. I have no idea on how to deal with those annoying ‘conflicting requirements’, here is an example of what I mean:


(click ‘show original’ for the whole problematic snippet)

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
   --> src/gfx/graphics.rs:155:18
    |
155 |             self.add_sampler(name.as_str(), name.as_str());
    |                  ^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 150:5...
   --> src/gfx/graphics.rs:150:5
    |
150 | /     pub fn load_data(&mut self, data: &'g Data) {
151 | |         for (name, img) in data.images.iter() {
152 | |             self.add_texture(name, img);
153 | |         }
...   |
156 | |         }
157 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
   --> src/gfx/graphics.rs:155:13
    |
155 |             self.add_sampler(name.as_str(), name.as_str());
    |             ^^^^
note: but, the lifetime must be valid for the lifetime 'g as defined on the impl at 54:6...
   --> src/gfx/graphics.rs:54:6
    |
54  | impl<'g> Gfx<'g> {
    |      ^^
    = note: ...so that the types are compatible:
            expected &mut gfx::graphics::Gfx<'_>
               found &mut gfx::graphics::Gfx<'g>

I don’t know what’s causing that, and how can I fix this, and I wasn’t able to create a MVCE.
I have no idea on what to do with those conflicting requirements, maybe you could give me some advice on dealing with them?


#2
pub fn add_sampler(&'g mut self, name: &'g str, texture: &'g str)

You shouldn’t use 'g for the self borrow - use an elided lifetime instead. In fact, you don’t need any explicit lifetimes here, and it doesn’t look like texture is used at all?

The immediate problem is load_data() holds a mutable borrow of self for some elided lifetime, but it’s being asked to borrow self for 'g - that’s not possible.

You’re going to run into a second problem, which is you’re iterating over textures field, causing self to be borrowed, and then calling add_texture(), which also requires a mutable borrow - that won’t work. You’ll need to rethink the API or impl - that issue is discussed in https://users.rust-lang.org/t/blog-post-series-after-nll-whats-next-for-borrowing-and-lifetimes


#3

After reading that post, I rethinked the API to make it a little more universal(? I don’t know how to call this change):

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
   --> src/gfx/graphics.rs:132:42
    |
132 |         for (name, tex) in self.textures.iter() {
    |                                          ^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 128:5...
   --> src/gfx/graphics.rs:128:5
    |
128 | /     pub fn load_data(&mut self, data: &'g Data) {
129 | |         for (name, img) in data.images.iter() {
130 | |             self.add_texture(name.as_str(), &img);
131 | |         }
...   |
134 | |         }
135 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
   --> src/gfx/graphics.rs:132:28
    |
132 |         for (name, tex) in self.textures.iter() {
    |                            ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'g as defined on the impl at 54:6...
   --> src/gfx/graphics.rs:54:6
    |
54  | impl<'g> Gfx<'g> {
    |      ^^
    = note: ...so that the expression is assignable:
            expected gfx::samplers::Sampler<'g>
               found gfx::samplers::Sampler<'_>

I still don’t understand how to deal with those lifetime/borrow problems.


#4

The problem here is tex.sampler() returns a Sampler whose lifetime parameter is tied to the (short-lived) borrow of tex, but you’re trying to store it in the textures field, which requires the Sampler to have the 'g lifetime - this is the discrepancy the compiler complains about.

I’m not familiar with glium so I don’t know how this type of thing is intended to be done. Its Sampler type wants to borrow the data: https://docs.rs/glium/0.22.0/glium/uniforms/struct.Sampler.html. So perhaps the data flow needs to be different - you store the texture types in the field, but then combine that texture with a short lived borrow of the sampler data instead of storing the sampler and the texture together.