Skip to content

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

Open
@dtolnay

Description

@dtolnay

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Status

    On deck

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions