rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.33k stars 12.58k forks source link

error: `X` does not live long enough doesn't provide enough context #111852

Open frederikhors opened 1 year ago

frederikhors commented 1 year ago

REPRODUCTION: https://www.rustexplorer.com/b/oe3uh4

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()
    | |____________^

Some code:

fn query_teams<'a>(
    user: &'a str,
    db: &'a mut impl Executor,
    store: Option<Store>,
    with_player: bool,
) -> BoxFuture<'a, Store> {
    async move {
        dbg!("I'm:", user);

        let mut store = store.unwrap_or_default();

        let mut query = sqlx::QueryBuilder::new(r#"SELECT "teams".*" FROM "teams"#);

        let teams = query
            .build_query_as::<Team>()
            .fetch_all(db.as_executor())
            .await
            .unwrap();

        for team in teams {
            store.teams.insert(team.id.to_string(), team);
        }

        if with_player {
            store = query_players(user, db, Some(store), false).await;
        }

        store
    }
    .boxed()
}
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()
    | |____________^

Meta

rustc 1.69.0 (84c898d65 2023-04-16)
binary: rustc
commit-hash: 84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc
commit-date: 2023-04-16
host: x86_64-pc-windows-msvc
release: 1.69.0
LLVM version: 15.0.7
fee1-dead commented 1 year ago

simplified a bit using perses, still need to eliminate the dependency though.

use futures::future::{BoxFuture, FutureExt};

trait Executor: Send {
    type Executor<'this>: sqlx::PgExecutor<'this>
    where
        Self: 'this;
    fn as_executor(&mut self) -> Self::Executor<'_>;
}

struct Store {}

#[derive(sqlx::FromRow)]
struct Team {}

fn query_teams(user: &str, db: impl Executor, store: Store) -> BoxFuture<Store> {
    async move {
        let query = sqlx::QueryBuilder::new(r#"SELECT "teams".*" FROM "teams"#);
        query
            .build_query_as::<Team>()
            .fetch_all(db.as_executor())
            .await;
        store
    }
    .boxed()
}
WaffleLapkin commented 1 year ago

Here is, what I believe is, the root cause/MCVE of this issue (play):

trait G: Send {
    type Gat<'l>: Send
    where
        Self: 'l;

    fn as_gat(&self) -> Self::Gat<'_>;
}

fn a(g: impl G) {
    let _: &dyn Send = &async move {
        let _gat = g.as_gat();
        async{}.await
    };
}

It looks like this is what happens:

  1. Proving async{}: Send requires that typeof(_gat): Send (because it lives across an .await point)
  2. typeof(_gat): Send requires Self: 'l
  3. impl G: 'l is the problem
QuineDot commented 1 year ago

Removing where Self: 'l from the GAT works around the issue.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1cb323c9dbbf99bd8cba8870286fc19d

WaffleLapkin commented 1 year ago

@QuineDot note that this is not always possible, sometimes such bound is required.