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

Bad Error Message: error[E0277]: the trait bound T: Generator<ResumeTy> is not satisfied #79648

Open
Tracked by #110338
keithmss opened this issue Dec 2, 2020 · 11 comments
Labels
A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints 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

@keithmss
Copy link

keithmss commented Dec 2, 2020

error message

Hello! This is a bug report for a confusing/bad error message:

   Compiling bug v0.1.0 (E:\Users\keith\Documents\Projects\bug)
error[E0277]: the trait bound `T: Generator<ResumeTy>` is not satisfied

error[E0308]: mismatched types
  --> src\main.rs:76:25
   |
14 |             .filter_map(|r| async { r.ok() })
   |                                   ----------
   |                                   |
   |                                   the expected generator
   |                                   the found generator
...
76 |     let foobar_runner = tokio::spawn(async move {
   |                         ^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected opaque type `impl futures::Future`
              found opaque type `impl futures::Future`

error[E0308]: mismatched types
  --> src\main.rs:76:25
   |
15 |             .filter_map(|m| async move { Some(Foo::new(m)) })
   |                                        ---------------------
   |                                        |
   |                                        the expected generator
   |                                        the found generator
...
76 |     let foobar_runner = tokio::spawn(async move {
   |                         ^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected opaque type `impl futures::Future`
              found opaque type `impl futures::Future`

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `bug`

To learn more, run the command again with --verbose.

code

I apologize that the following probably isn't the easiest way to trigger it. I am relatively new to Rust and am just now working with Generics and Lifetimes now which is how I got here. The following is a very stripped down version of my code (it compiles without the commented line).

main.rs:

use core::future;
use futures::stream::{self, StreamExt};
use parking_lot::RwLock;
use std::borrow::Cow;
use std::sync::Arc;

struct Bar {}

impl Bar {
    async fn get_foo<'a>(&self) -> Vec<Foo<'a>> {
        let results: Vec<Result<String, ()>> =
            vec![Ok("shoutout to `impl Fox for Salix` for this vector".to_string()); 10];
        let foo: Vec<Foo<'a>> = stream::iter(results)
            .filter_map(|r| async { r.ok() })
            .filter_map(|m| async move { Some(Foo::new(m)) })
            .filter(|m| future::ready(test_foo(m.as_str()))) // Code compiles without this line
            .collect()
            .await;
        foo
    }

    async fn new() -> Arc<Self> {
        Arc::new(Self {})
    }
}

struct Foo<'a> {
    raw: Cow<'a, str>,
}

impl<'a> Foo<'a> {
    fn as_str(&self) -> &str {
        &self.raw
    }

    fn new<T>(raw: T) -> Foo<'a>
    where
        T: Into<Cow<'a, str>>,
    {
        Foo { raw: raw.into() }
    }
}

struct FooBar<'a> {
    bar: Arc<Bar>,
    foo: RwLock<Vec<Foo<'a>>>,
}

impl<'a> FooBar<'a> {
    async fn get_foo(&self) -> Vec<Foo<'a>> {
        let foo: Vec<Foo<'a>> = self.bar.get_foo().await;
        foo
    }

    async fn new(bar: Arc<Bar>) -> Arc<FooBar<'a>> {
        let foobar = FooBar {
            bar: bar.clone(),
            foo: RwLock::new(Vec::new()),
        };
        Arc::new(foobar)
    }

    async fn run(&self) {
        let new_foo: Vec<Foo<'a>> = self.get_foo().await;
        {
            let mut foo = self.foo.write();
            *foo = new_foo;
        }
    }
}

#[tokio::main]
async fn main() {
    let bar = Bar::new().await;
    let foobar = FooBar::new(bar).await;
    let foobar_runner = tokio::spawn(async move {
        foobar.run().await;
    })
    .await;
}

fn test_foo(foo: &str) -> bool {
    println!("{}", foo);
    true
}

Meta

rustc --version --verbose:

PS E:\Users\keith\Documents\Projects\bug> rustc --version --verbose
rustc 1.48.0 (7eac88abb 2020-11-16)
binary: rustc
commit-hash: 7eac88abb2e57e752f3302f02be5f3ce3d7adfb4
commit-date: 2020-11-16
host: x86_64-pc-windows-msvc
release: 1.48.0
LLVM version: 11.0

Cargo.toml:

[package]
name = "bug"
version = "0.1.0"
authors = ["keith miller"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
futures           = "0.3.8"
parking_lot       = "0.11.1"
tokio = { version = "0.2.22", features = ["macros", "rt-threaded", "time"] }

This is my first bug report for a project of this size. Please let me know if you need me to modify anything. Thank you!

@keithmss keithmss added the C-bug Category: This is a bug. label Dec 2, 2020
@SNCPlay42
Copy link
Contributor

Reduced some (but it'd be nice to remove the futures dependency):

use futures::stream;
use futures::stream::StreamExt;
use std::future;
struct Bar {}
impl Bar {
    async fn get_foo<'a>(&self) -> Vec<Foo<'a>> {
        let results = vec![()];
        let foo: Vec<Foo<'a>> = stream::iter(results)
            .filter_map(|_| async move { Some(Foo::new()) })
            .filter(|m| future::ready(true))
            .collect()
            .await;
        foo
    }
}
struct Foo<'a> {
    _use_a: &'a (),
}
impl<'a> Foo<'a> {
    fn new() -> Foo<'a> {
        Foo { _use_a: &() }
    }
}
fn demand_is_send<T>(t: T)
where
    T: Send,
{
}
fn main() {
    let bar = Bar {};
    demand_is_send(async move { bar.get_foo().await })
}

@rustbot label A-async-await A-diagnostics

@rustbot rustbot added A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints labels Dec 3, 2020
@SNCPlay42
Copy link
Contributor

The T: Generator<ResumeTy> error is gone on nightly (bisected to #73905) but the confusing type mismatch error remains

@tmandry
Copy link
Member

tmandry commented Dec 3, 2020

Further minimized for the remaining error.. playground

use futures::stream;
use futures::stream::StreamExt;
use std::future::{self, Future};

fn get_foo<'a>() -> impl Future<Output = Vec<()>> + 'a {
    async {
        let results = vec![()];
        let foo: Vec<()> = stream::iter(results)
            .filter_map(|_| async move { Some(()) })
            .filter(|m| future::ready(true))
            .collect()
            .await;
        foo
    }
}
fn demand_is_send<T>(t: T)
    where T: Send
{}
fn main() {
    demand_is_send(get_foo())
}

Haven't tried removing the futures dep yet.

@tmandry tmandry added the AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. label Dec 11, 2020
@frxstrem
Copy link

frxstrem commented Dec 21, 2020

I think I came across the same issue, but with a slightly different snippet of code:

use futures::future::{join, ready, Future};
use futures::stream::{self, StreamExt};

fn f() -> impl Future<Output = ()> + Send {
    async {
        let a = &();
        join(
            stream::empty().for_each(|_: ()| async { drop(a) }),
            ready(()),
        )
        .await;
    }
}
error[E0308]: mismatched types
  --> src/lib.rs:4:11
   |
4  | fn f() -> impl Future<Output = ()> + Send {
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
...
8  |             stream::empty().for_each(|_: ()| async { drop(a) }),
   |                                                    -----------
   |                                                    |
   |                                                    the expected generator
   |                                                    the found generator
   |
   = note: expected opaque type `impl futures::Future`
              found opaque type `impl futures::Future`

Playground

When compiling on stable, I'm also getting the error about T: Generator<ResumeTy>.

Curiously, the usage of join (or the join! macro) seems necessary to trigger the error message in this case, as just awaiting the future directly compiles just fine.

@SNCPlay42
Copy link
Contributor

SNCPlay42 commented Dec 21, 2020

One-crate repro: (playground)

use std::future::Future;
use std::marker::PhantomData;

trait Stream {
    type Item;
}

struct Filter<St: Stream> {
    pending_item: St::Item,
}

fn filter<St: Stream>(_: St) -> Filter<St> {
    unimplemented!();
}

struct FilterMap<Fut, F> {
    f: F,
    pending: PhantomData<Fut>,
}

impl<Fut, F> Stream for FilterMap<Fut, F>
where
    F: FnMut() -> Fut,
    Fut: Future,
{
    type Item = ();
}

pub fn get_foo() -> impl Future + Send {
    async {
        let _y = &();
        let _x = filter(FilterMap {
            f: || async move { *_y },
            pending: PhantomData,
        });
        async {}.await;
    }
}

nagisa added a commit to standard-ai/hedwig-rust that referenced this issue Mar 17, 2021
Turns out having anything with any sort of lifetime in stream/sink
chains will trigger nasty issues such as
rust-lang/rust#79648 which is pretty difficult
to figure out how to work around.

Making `Topic` a newtype erases the lifetime from the type, making it
significantly easier to work with in thsoe contexts.
nagisa added a commit to standard-ai/hedwig-rust that referenced this issue Mar 18, 2021
Turns out having anything with any sort of lifetime in stream/sink
chains will trigger nasty issues such as
rust-lang/rust#79648 which is pretty difficult
to figure out how to work around.

Making `Topic` a newtype erases the lifetime from the type, making it
significantly easier to work with in thsoe contexts.
nagisa added a commit to standard-ai/hedwig-rust that referenced this issue Mar 18, 2021
Turns out having anything with any sort of lifetime in stream/sink
chains will trigger nasty issues such as
rust-lang/rust#79648 which is pretty difficult
to figure out how to work around.

Making `Topic` a newtype erases the lifetime from the type, making it
significantly easier to work with in thsoe contexts.
nagisa added a commit to standard-ai/hedwig-rust that referenced this issue Mar 18, 2021
Turns out having anything with any sort of lifetime in stream/sink
chains will trigger nasty issues such as
rust-lang/rust#79648 which is pretty difficult
to figure out how to work around.

Making `Topic` a newtype erases the lifetime from the type, making it
significantly easier to work with in thsoe contexts.
@SNCPlay42
Copy link
Contributor

This and #71723 look like the same thing.

rnarubin pushed a commit to rnarubin/hedwig-rust that referenced this issue Mar 29, 2021
Turns out having anything with any sort of lifetime in stream/sink
chains will trigger nasty issues such as
rust-lang/rust#79648 which is pretty difficult
to figure out how to work around.

Making `Topic` a newtype erases the lifetime from the type, making it
significantly easier to work with in thsoe contexts.
@peku33
Copy link

peku33 commented Apr 10, 2021

Is there any progress or workaround for this?

@estebank
Copy link
Contributor

CC #82921

@estebank
Copy link
Contributor

Triage: current output (the bound being pointed at is new):

error[E0308]: mismatched types
  --> src/main.rs:20:5
   |
9  |             .filter_map(|_| async move { Some(()) })
   |                                        ------------
   |                                        |
   |                                        the expected `async` block
   |                                        the found `async` block
...
20 |     demand_is_send(get_foo())
   |     ^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected opaque type `impl futures::Future`
              found opaque type `impl futures::Future`
note: the lifetime requirement is introduced here
  --> src/main.rs:17:14
   |
17 |     where T: Send
   |              ^^^^

@estebank
Copy link
Contributor

estebank commented Aug 15, 2022

Triage: Current output (fallout from NLL stabilization):

error: higher-ranked lifetime error
  --> src/main.rs:20:5
   |
20 |     demand_is_send(get_foo())
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: could not prove for<'r, 's> impl futures::Future<Output = Vec<()>>: std::marker::Send

@tmandry tmandry moved this to On deck in wg-async work Dec 8, 2022
@Noratrieb Noratrieb added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 5, 2023
@estebank
Copy link
Contributor

Current output:

error[E0308]: mismatched types
  --> src/main.rs:20:5
   |
9  |             .filter_map(|_| async move { Some(()) })
   |                             -----------------------
   |                             |
   |                             the expected `async` block
   |                             the found `async` block
...
20 |     demand_is_send(get_foo())
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected `async` block `{async block@src/main.rs:9:29: 9:52}`
              found `async` block `{async block@src/main.rs:9:29: 9:52}`
note: the lifetime requirement is introduced here
  --> src/main.rs:17:14
   |
17 |     where T: Send
   |              ^^^^

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 A-diagnostics Area: Messages for errors, warnings, and lints 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.

8 participants