Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent lifetime inference with return impl Future/BoxFuture and higher ranked lifetimes #135619

Open
weiznich opened this issue Jan 17, 2025 · 0 comments
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.

Comments

@weiznich
Copy link
Contributor

Compiling base line version: https://github.com/weiznich/diesel_async/blob/buggy_lifetimes/src/run_query_dsl/mod.rs#L783-L817

I encountered several inconsistent errors while working on the linked code:

Variant 1: (Remove the async move block and box the future directly)

impl<'b, Changes, Output, Tab, V> UpdateAndFetchResults<Changes, Output>
    for crate::AsyncPgConnection
where
    Output: Send + 'static,
    Changes:
        Copy + AsChangeset<Target = Tab> + Send + diesel::associations::Identifiable<Table = Tab>,
    Tab: diesel::Table + diesel::query_dsl::methods::FindDsl<Changes::Id> + 'b,
    diesel::dsl::Find<Tab, Changes::Id>: IntoUpdateTarget<Table = Tab, WhereClause = V>,
    diesel::query_builder::UpdateStatement<Tab, V, Changes::Changeset>:
        diesel::query_builder::AsQuery,
    diesel::dsl::Update<Changes, Changes>: methods::LoadQuery<'b, Self, Output>,
    V: Send + 'b,
    Changes::Changeset: Send + 'b,
    Tab::FromClause: Send,
{
    fn update_and_fetch<'life0, 'async_trait>(
        &'life0 mut self,
        changeset: Changes,
    ) -> BoxFuture<'async_trait, QueryResult<Output>>
    where
        Changes: 'async_trait,
        Changes::Changeset: 'async_trait,
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        diesel::update(changeset)
            .set(changeset)
            .get_result(self)
            .boxed()
    }
}

Results in the following compilation error:

error: lifetime may not live long enough
   --> src/run_query_dsl/mod.rs:809:9
    |
784 |   impl<'b, Changes, Output, Tab, V> UpdateAndFetchResults<Changes, Output>
    |        -- lifetime `'b` defined here
...
799 |       fn update_and_fetch<'life0, 'async_trait>(
    |                                   ------------ lifetime `'async_trait` defined here
...
809 | /         diesel::update(changeset)
810 | |             .set(changeset)
811 | |             .get_result(self)
812 | |             .boxed()
    | |____________________^ method was supposed to return data with lifetime `'async_trait` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'async_trait`

Variant 2: Use impl Future for the return type

impl<'b, Changes, Output, Tab, V> UpdateAndFetchResults<Changes, Output>
    for crate::AsyncPgConnection
where
    Output: Send + 'static,
    Changes:
        Copy + AsChangeset<Target = Tab> + Send + diesel::associations::Identifiable<Table = Tab>,
    Tab: diesel::Table + diesel::query_dsl::methods::FindDsl<Changes::Id> + 'b,
    diesel::dsl::Find<Tab, Changes::Id>: IntoUpdateTarget<Table = Tab, WhereClause = V>,
    diesel::query_builder::UpdateStatement<Tab, V, Changes::Changeset>:
        diesel::query_builder::AsQuery,
    diesel::dsl::Update<Changes, Changes>: methods::LoadQuery<'b, Self, Output>,
    V: Send + 'b,
    Changes::Changeset: Send + 'b,
    Tab::FromClause: Send,
{
    fn update_and_fetch<'life0, 'async_trait>(
        &'life0 mut self,
        changeset: Changes,
    ) -> impl Future<Output = QueryResult<Output>> + Send + 'async_trait
    where
        Changes: 'async_trait,
        Changes::Changeset: 'async_trait,
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        async move {
            diesel::update(changeset)
                .set(changeset)
                .get_result(self)
                .await
        }
        .boxed()
    }
}

Error:

error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
   --> src/run_query_dsl/mod.rs:784:6
    |
784 | impl<'b, Changes, Output, Tab, V> UpdateAndFetchResults<Changes, Output>
    |      ^^ unconstrained lifetime parameter

I would expect all three code variations to be the "same" in terms of involved lifetimes, but two of them do not compile with rather surprising errors.

Meta

rustc --version --verbose:

rustc 1.86.0-nightly (99db2737c 2025-01-16)
binary: rustc
commit-hash: 99db2737c91d1e4b36b2ffc17dcda5878bcae625
commit-date: 2025-01-16
host: x86_64-unknown-linux-gnu
release: 1.86.0-nightly
LLVM version: 19.1.7
Backtrace

<backtrace>

@weiznich weiznich added the C-bug Category: This is a bug. label Jan 17, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jan 17, 2025
@lolbinarycat lolbinarycat added the A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. label Jan 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.
Projects
None yet
Development

No branches or pull requests

3 participants