6

Here's my minimum reproducible example:

use axum::{extract::State, Json, Router};
use diesel::pg::Pg;
use diesel_async::{
    pooled_connection::bb8::Pool,
    AsyncConnection, AsyncPgConnection, RunQueryDsl,
};

fn main() {
    // body omitted for brevity
}

pub type AsyncPool = Pool<AsyncPgConnection>;

fn router() -> Router<AsyncPool> {
    use axum::routing::*;
    Router::new().route("/create", post(create))
}

async fn create(State(db): State<AsyncPool>) -> Result<Json<()>, ()> {
    let mut conn = db.get().await.unwrap();
    let user = create_user(&mut conn).await?;

    Ok(Json(user))
}

// actual return types omitted for brevity
async fn create_user(conn: &mut impl AsyncConnection<Backend = Pg>) -> Result<(), ()> {
    // error doesn't happen without this line, which is even more confusing
    diesel::dsl::sql_query("real query omitted for brevity")
        .execute(conn)
        .await
        .unwrap();
    Ok(())
}

Trying to compile this on Rust 1.70 gives the following error:

error: implementation of `Deref` is not general enough
  --> src/main.rs:27:36
   |
27 |     Router::new().route("/create", post(create))
   |                                    ^^^^^^^^^^^^ implementation of `Deref` is not general enough
   |
   = note: `Deref` would have to be implemented for the type `bb8::api::PooledConnection<'0, AsyncDieselConnectionManager<AsyncPgConnection>>`, for any lifetime `'0`...
   = note: ...but `Deref` is actually implemented for the type `bb8::api::PooledConnection<'1, AsyncDieselConnectionManager<AsyncPgConnection>>`, for some specific lifetime `'1`

I already don't understand why this error is happening, because the implementations of Deref and DerefMut for bb8::PooledConnection look general enough to me:

impl<'a, M> Deref for PooledConnection<'a, M>
where
    M: ManageConnection,
{
    type Target = M::Connection;

    fn deref(&self) -> &Self::Target {
        &self.conn.as_ref().unwrap().conn
    }
}

impl<'a, M> DerefMut for PooledConnection<'a, M>
where
    M: ManageConnection,
{
    fn deref_mut(&mut self) -> &mut M::Connection {
        &mut self.conn.as_mut().unwrap().conn
    }
}

But what's even more confusing is that the error goes away if I don't call diesel_async::run_query_dsl::RunQueryDsl::execute() on the connection object inside of create_user, OR if I call .deref_mut() manually:

// calling deref_mut manually makes the error go away. why?
let user = create_user(conn.deref_mut()).await?;

Why is this compile error happening, and why does it go away under these circumstances? How is it possible that calling execute() is able to implicitly place additional lifetime constraints on the parameter conn?

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
laptou
  • 6,389
  • 2
  • 28
  • 59
  • 1
    This looks like a bug of the compiler to me, maybe you should try opening an issue. – jthulhu Jun 08 '23 at 20:21
  • Yes the error message indicates that this is another instance of a long known compiler bug related to async code and lifetimes. It should be possible to workaround that by just not using a generic `&mut impl AsyncConnection` type as function parameter, but rather the specific `&mut AsyncPgConnection` type. – weiznich Jun 09 '23 at 08:47
  • @weiznich If this bug is already known, would you be able to point me to the GitHub issue that tracks it? I don't really know what to type into Google. – laptou Jun 09 '23 at 16:42
  • I think https://github.com/rust-lang/rust/issues/101794 might be one of the issues that track this kind of restrictions. – weiznich Jun 30 '23 at 10:11

0 Answers0