Why does this `impl Executor` does not live long enough?

REPRODUCTION: undefined | Rust Explorer

I apologize in advance if the code seems confusing or complex for no apparent reason: this is just a minimal example compared to the real code (which is much more complex and bigger).

I would like to understand why this error:

error: `impl Executor` does not live long enough
   --> src/main.rs:136:5
    |
136 | /     async move {
137 | |         dbg!("I'm:", user);
138 | |
139 | |         let mut store = store.unwrap_or_default();
...   |
169 | |     }
170 | |     .boxed()
    | |____________^

The reason I'm using the trait Executor is because I need to use both DB connections and transactions in my services layer (represented here by team_list).

I can change everything in this code, the trait too.

Can you help me?

Ignoring where the 'static constraint comes from, but perhaps addressing the problem...

I see you already doing this elsewhere:

impl<E: 'static + Executor> TeamTrait for Repo<E> {

The corresponding bound where you're getting an error would be:

    db: &'a mut (impl Executor + 'static),

If it's reasonable that Executor never needs to hold on to something borrowed, you could

-pub trait Executor: Send + Sync {
+pub trait Executor: Send + Sync + 'static {

And then it will be implied everywhere, and you can use

impl<E: Executor> TeamTrait for Repo<E> {
// ...
    db: &'a mut impl Executor,
3 Likes

Wow. This seems to work! But now I'm terrified of what might happen in the future with this change.

If you remove Send from the Boxing the future is fine with lifetimes. Not that you would find that useful in full program.

Why does an error prompt when there is no 'static added? Thank you for your reply

I have tested and found that the db.as_executor() passed in when calling fetch_all caused the lifetime check to fail.
Is it because of the lifetime 'this defined in the associated type, or because of the lifetime restriction in sqlx::executor::Executor<'c> ? Thank you for your reply

I believe it's some form of this bug.

For example.

1 Like

Thank you very much for your reply. I have been thinking about this issue for a long time.

More directly, probably.

Based on comments in that bug, removing the where Self: 'this bound on the GAT may also work around the issue.

pub trait Executor: Send + Sync {
    type Executor<'this>: Send + Sync; // + sqlx::PgExecutor<'this>

    fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_> { e }
2 Likes

This unfortunately doesn't seem to work: undefined | Rust Explorer.

Looks like you didn't add the disable lint method?

Wow. It works! https://www.rustexplorer.com/b/onioi4.

But, can you please explain why it works?

And why are you commenting // + sqlx::PgExecutor<'this>?

BTW you're amazingly good!

My original reply is too far out of cache for me to be sure, but I probably just got something I could recreate in the playground, didn't see why it shouldn't logically work, found the issues and read them to try and understand more, read

This code worked with some earlier version of nightly Rust (without the where Self: 'a bound, and before where Self: 'a was required in the GAT). Unfortunately I do not remember which version that was (a few weeks ago).

in one of the issues and tried disabling the lint that requires the bound (which isn't something you should need special knowledge to do if it was better designed IMNSHO) and removing the bound in my reproduction, and it worked.

I guess that's a long-winded way of saying I can't explain why it works, but had enough experience and tenacity to find a workaround that at least compiled (so might work in your actual use case).

Almost surely that was so I didn't have to try and mock up PgExecutor<'_> in the playground, and I just failed to uncomment it in my comment here.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.