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

Wrong Send constraint when using a trait with lifetime + associated type in async #60658

Open
carllerche opened this issue May 9, 2019 · 11 comments

Comments

@carllerche
Copy link
Member

@carllerche carllerche commented May 9, 2019

Minimal:

#![feature(async_await, await_macro)]

use std::future::Future;

pub trait Foo<'a> {
    type Future: Future<Output = ()>;
    
    fn foo() -> Self::Future;
}

struct MyType<T>;

impl<'a, T> Foo<'a> for MyType<T>
where
    T: Foo<'a>,
    T::Future: Send,
{
    type Future = Box<Future<Output = ()> + Send>;
    
    fn foo() -> Self::Future {
        Box::new(async move {
            await!(T::foo())
        })
    }
}

fn main() {
}

Out:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:21:9
   |
21 | /         Box::new(async move {
22 | |             await!(T::foo())
23 | |         })
   | |__________^ one type is more general than the other
   |
   = note: expected type `std::marker::Send`
              found type `std::marker::Send`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `playground`.

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

Compiler version: rustc 1.36.0-nightly (2019-05-07)

@Nemo157
Copy link
Member

@Nemo157 Nemo157 commented May 16, 2019

Expanding the constraint to

for<'b> <T as Foo<'b>>::Future: Send

gets past this error. I'm not sure why it needs this more general constraint though.

reproduction directly with generators

@nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented Jun 4, 2019

I suspect one can make a failure of this with impl trait alone as well, though I've not tried. I'm not sure what exactly the problem is.

@nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented Jun 4, 2019

Deferring -- not blocking stabilization. Would be good to investigate though.

@dtolnay
Copy link
Member

@dtolnay dtolnay commented Sep 18, 2019

I hit this in dtolnay/async-trait#34 and minimized to a quite similar looking minimal repro but with the associated type in argument position rather than return position.

I believe this code should compile as written, but right now I am totally stuck on what missing bound is being expected. Is there anything similar to @Nemo157's hrtb that would unblock this one?

use std::future::Future;

pub trait Trait<'a> {
    type Assoc: Send + 'static;

    fn f(x: Self::Assoc) -> Box<dyn Future<Output = ()> + Send>
    where
        'a: 'static,
        Self: Sized + 'static,
    {
        Box::new(f::<Self>(x))
    }
}

async fn f<T: Trait<'static>>(_x: T::Assoc) {
    async {}.await
}
error[E0308]: mismatched types
  --> src/main.rs:11:9
   |
11 |         Box::new(f::<Self>(x))
   |         ^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected type `std::marker::Send`
              found type `std::marker::Send`

@dtolnay dtolnay changed the title async / await + Box<Future> + Send does not compile Wrong Send constraint when using a trait with lifetime + associated type in async Sep 18, 2019
@jebrosen
Copy link
Contributor

@jebrosen jebrosen commented Oct 27, 2019

I keep running into this both with and without async-trait while trying to implement Future-returning traits in Rocket, which makes heavy use of associated types. In particular I'm currently trying to do this: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=034908e77e7fca31dfbc73fb57c2f3e5 (compare to the version with Option that does not have an associated type).

If I or someone else were to try and investigate the cause, is there any good starting point?

@chaaz
Copy link

@chaaz chaaz commented Nov 19, 2019

You can get to this error via the use of try_select, try_join, pin_mut and boxed: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0233531e1b7801aca03b4564742d5218. The error given makes it really difficult to figure out what the underlying problem is, and/or what workaround can be done to avoid it. :(

edit: an even more straightforward example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3e0b26047b48a0c62db94939556d4538

@jebrosen
Copy link
Contributor

@jebrosen jebrosen commented Nov 22, 2019

@stephaneyfx pointed out a workaround (using FutureExt::map) that appears to work in my case:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=51593d4cd22b7dc0a21d1d7c444d9210

I don't think this helps async_trait, but having this to compare to might help figure out the underlying cause.

@estebank
Copy link
Contributor

@estebank estebank commented Dec 13, 2019

@Ploppz
Copy link

@Ploppz Ploppz commented Feb 28, 2020

I don't know if it's helpful or to what degree it's related, but I get "one type is more general than the other" error that I fail to understand here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=14c3f1f5a60a8b36a52ab55776ba241e
It can be fixed if I use Box::pin instead of .boxed(), which makes me think it's a bug.

@benschulz
Copy link
Contributor

@benschulz benschulz commented Mar 24, 2020

I fail to do the mental gymnastics required to be sure, but this might be a dupe of #64552. That the HRTB works lines up well with Aaron1011's analysis over there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Linked pull requests

Successfully merging a pull request may close this issue.

None yet