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

Async fn disagrees on its own return type ("one of the expected opaque types" vs "one of the found opaque types") #82921

Open
Tracked by #110338
dtolnay opened this issue Mar 9, 2021 · 3 comments
Labels
A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@dtolnay
Copy link
Member

dtolnay commented Mar 9, 2021

The following is a minimal repro.

use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use core::task::{Context, Poll};

async fn f() {}

pub fn fail<'a>() -> Box<dyn Future<Output = ()> + Send + 'a> {
    Box::new(async { new(|| async { f().await }).await })
}

fn new<A, B>(_a: A) -> F<A, B>
where
    A: Fn() -> B,
{
    F { _i: PhantomData }
}

trait Stream {
    type Item;
}

struct T<A, B> {
    _a: PhantomData<A>,
    _b: PhantomData<B>,
}

impl<A, B> Stream for T<A, B>
where
    A: Fn() -> B,
{
    type Item = B;
}

struct F<A, B>
where
    A: Fn() -> B,
{
    _i: PhantomData<<T<A, B> as Stream>::Item>,
}

impl<A, B> Future for F<A, B>
where
    A: Fn() -> B,
{
    type Output = ();
    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
        unimplemented!()
    }
}
error[E0308]: mismatched types
  --> src/main.rs:9:5
   |
6  | async fn f() {}
   |              -
   |              |
   |              checked the `Output` of this `async fn`, one of the expected opaque types
   |              checked the `Output` of this `async fn`, one of the found opaque types
...
9  |     Box::new(async { new(|| async { f().await }).await })
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   | 
  ::: .rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:61:43
   |
61 | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
   |                                           -------------------------------
   |                                           |
   |                                           one of the expected opaque types
   |                                           one of the found opaque types
   |
   = note: while checking the return type of the `async fn`
   = note: while checking the return type of the `async fn`
   = note: expected opaque type `impl Future`
              found opaque type `impl Future`

Note that rearranging fn fail to the following hides the issue and compiles. But my expectation would be that this does the exact same thing either way, with or without hiding the async block behind a named function.

-     Box::new(async { new(|| async { f().await }).await })
+     async fn wrap() { new(|| async { f().await }).await }
+     Box::new(wrap())

Various other very surprising transformations also hide the issue. For example:

  impl<A, B> Stream for T<A, B>
- where
-     A: Fn() -> B,
  {
      type Item = B;
  }

or:

-     Box::new(async { new(|| async { f().await }).await })
+     Box::new(async { new(|| f()).await })

or:

- pub fn fail<'a>() -> Box<dyn Future<Output = ()> + Send + 'a> {
+ pub fn fail() -> Box<dyn Future<Output = ()> + Send + 'static> {

I believe this is a compiler bug because none of the above transformations should have effect on whether this code compiles.

@dtolnay dtolnay added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. A-async-await Area: Async & Await labels Mar 9, 2021
@SNCPlay42
Copy link
Contributor

This looks like #79648.

@estebank
Copy link
Contributor

Triage, current output:

error: higher-ranked lifetime error
 --> src/lib.rs:9:5
  |
9 |     Box::new(async { new(|| async { f().await }).await })
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: could not prove `for<'r, 's> Box<impl for<'r> Future<Output = ()>>: CoerceUnsized<Box<(dyn Future<Output = ()> + Send + 's)>>`

@w4
Copy link

w4 commented Sep 21, 2022

I've also managed to trigger this by passing a reference into Itertools::unique after it going through a filter_map within an async block that needs to be coerced into dyn Future + Send, I'm not exactly sure what the interaction is here:

use std::{future::Future, pin::Pin};
use futures;
use itertools::Itertools;

fn test() -> Pin<Box<dyn Future<Output = ()> + Send>> {
    Box::pin(async move {
        futures::future::join_all(
            std::iter::empty::<&u64>()
                .filter_map(|_v| None)
                .unique()
                .map(abc),
        )
        .await;
    })
}

async fn abc(v: &u64) -> u64 {
    *v
}

(playground)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
Status: On deck
Development

Successfully merging a pull request may close this issue.

5 participants