Lifetime compile issues

Lifetime compile issues and I have just pasted the relevant sections. Code that is structured as follows:

pub async fn foo(&self) {
   let mut map_handle = self.state_map.write().await;
   for _i in 0 .. 100 {
          if something {
                // do some stuff.
                self.call_me(&mut map_handle).await;
          } else {
                self.call_me(&mut map_handle).await;
          }
    }
}

async fn call_me(&self, map_handle: &mut RwLockWriteGuard<HashMap<Key, Value,RandomState>>) {
}

This code doesn't compile and I get the following error:

error[E0521]: borrowed data escapes outside of associated function
   --> w_utils/src/source.rs:472:30
    |
469 |         &self,
    |         -----
    |         |
    |         self is a reference that is only valid in the associated function body
    |         let's call the lifetime of this reference '1
...
472 |         let mut map_handle = self.state_map.write().await;
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^
    |                              |
    |                              self escapes the associated function body here
    |                              argument requires that '1 must outlive 'static

I don't understand this. Could someone please enlighten me?

What's the type of state_map? Perhaps you could provide the whole struct definition of the Self type.

I'm case state_map's type isn't a commonly known type, the signature of write would also be of interest.

Thanks.

struct MyStruct {
     state_map : RwLock<HashMap<Key, Value>>,
}

RwLock is from async_std. Does that help?

this line is suspicious, either state_map.write() uses 'static in it's signature, or maybe you are trying to spawn the future into a multi thread executor, i.e., are you calling spawn(self.foo())?

This struct is implemented as a Singleton using Once. Given that, is that what you mean by trying to spawn a future into a multi threaded executor? I am not explicitly calling spawn(). What is the problem if this is indeed the case?

no, I was refering tokio::spawn. it seams to me, your call_me function might have some elided lifetime which is assumed to be 'static by the compiler. I remember the lock guard has a lifetime argument to it, try annotate:

async fn call_me<'a>(&'a self, map_handle: &mut RwLockWriteGuard<'a, HashMap<Key, Value,RandomState>>) {
}

please note the &mut RwLockWriteGuard cannot have the same lifetime, otherwise, the lock guard will be self borrowed.

The signature

in and by itself is already an error:

error[E0726]: implicit elided lifetime not allowed here
  --> src/main.rs:30:42
   |
30 | async fn call_me(&self, map_handle: &mut RwLockWriteGuard<HashMap<Key, Value, RandomState>>) {
   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected lifetime parameter
   |
help: indicate the anonymous lifetime
   |
30 | async fn call_me(&self, map_handle: &mut RwLockWriteGuard<'_, HashMap<Key, Value, RandomState>>) {
   |                                                           +++

Despite this error, the compiler assumes “'static” in the missing place as some “reasonable” default and continues compilation (in order to be more helpful and display more than just one error message) resulting in the additional error message

error[E0521]: borrowed data escapes outside of method
  --> src/main.rs:23:17
   |
18 | pub async fn foo(&self) {
   |                  -----
   |                  |
   |                  `self` is a reference that is only valid in the method body
   |                  let's call the lifetime of this reference `'1`
...
23 |                 self.call_me(&mut map_handle).await;
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                 |
   |                 `self` escapes the method body here
   |                 argument requires that `'1` must outlive `'static`

However, fixing the problem as suggested with the signature RwLockWriteGuard<'_, HashMap<Key, Value, RandomState>> will eliminate both errors. So the second error about “borrowed data escapes outside of method” was nothing but a red herring. (All assuming that my mock-up of your situation is accurate.)

4 Likes