Fred Hors
Fred Hors

Reputation: 4156

Why this signature is not inferred?

This code works:

async fn player_create<'a>(
    &'a self,
    team_id: &'a str,
    _input: &'a PlayerInput,
    lambda: &'a Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer> {
    let tx = Arc::new(Mutex::new(self.pool.begin().await.unwrap()));

    let shirt_next_value = Box::new({
        let tx = tx.clone();

        move |model: &'a str,
              name: &'a str| -> Pin<Box<dyn Future<Output = Result<i64>> + Send>> {
            let tx = tx.clone();

            Box::pin(async move {
                self::Shirt::shirt_get_next_and_increase(
                    self,
                    &mut *tx.lock().await,
                    team_id,
                    model,
                    name,
                )
                .await
            })
        }
    });

    let domain_player = lambda(PlayerCreateLambdaArgs {
        shirt_next_value,
    })
    .await?;

    let mut res = PgPlayer::insert(&mut *tx.lock().await, team_id, &domain_player).await?;

    Arc::try_unwrap(tx).unwrap().into_inner().commit().await?;

    Ok(res.into())
}

but I would like to remove the -> Pin<Box<dyn Future<Output = Result<i64>> + Send>> line, so I did:

async fn player_create<'a>(
    &'a self,
    team_id: &'a str,
    _input: &'a PlayerInput,
    lambda: &'a Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer> {
    let tx = Arc::new(Mutex::new(self.pool.begin().await.unwrap()));

    let shirt_next_value = Box::new({
        let tx = tx.clone();

        move |model: &'a str, name: &'a str| {
            let tx = tx.clone();

            Box::pin(async move {
                self::Shirt::shirt_get_next_and_increase(
                    self,
                    &mut *tx.lock().await,
                    team_id,
                    model,
                    name,
                )
                .await
            })
        }
    });

    let domain_player = lambda(PlayerCreateLambdaArgs {
        shirt_next_value,
    })
    .await?;

    let mut res = PgPlayer::insert(&mut *tx.lock().await, team_id, &domain_player).await?;

    Arc::try_unwrap(tx).unwrap().into_inner().commit().await?;

    Ok(res.into())
}

but if I remove it the error is:

error[E0271]: expected `[closure@src\main.rs:40:13: 41:33]` to be a closure that returns `Pin<Box<dyn std::future::Future<Output = Result<i64, common::error::Error>> + std::marker::Send>>`, but it returns `Pin<Box<impl std::future::Future<Output = Result<i64, common::error::Error>>>>`
   |
46 |                   Box::pin(async move {
   |  _____________________________________-
47 | |                     self::Shirt::shirt_get_next_and_increase(
48 | |                         self,
49 | |                         &mut *tx.lock().await,
...  |
54 | |                     .await
55 | |                 })
   | |_________________- the found `async` block
...
63 |               shirt_next_value,
   |               ^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::future::Future`, found opaque type
   |
72 |   pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
   |                                             ------------------------------- the found opaque type
   |
   = note: expected struct `Pin<Box<dyn std::future::Future<Output = Result<i64, common::error::Error>> + std::marker::Send>>`
              found struct `Pin<Box<impl std::future::Future<Output = Result<i64, common::error::Error>>>>`
   = note: required for the cast from `[closure@src\main.rs:40:13: 41:33]` to the object type `dyn FnOnce(&str, &str) -> Pin<Box<dyn std::future::Future<Output = Result<i64, common::error::Error>> + std::marker::Send>> + Sync + std::marker::Send`

Why?

Upvotes: 0

Views: 67

Answers (1)

attempt0
attempt0

Reputation: 834

The problem can be simplied to the following:

use std::any::Any;

fn test(a: &Box<dyn Any>) {}

fn main() {
    let a = Box::new(5);
    test(&a);
}

This is due to the fact that the type won't implicitly convert to dynamic dispatch.

You can solve it by specifying the conversion to the type you want.

use std::any::Any;

fn test(a: &Box<dyn Any>) {}

fn main() {
    let a = Box::new(5) as _;
    test(&a);
}

Upvotes: 1

Related Questions