Open carllerche opened 5 years ago
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.
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.
Deferring -- not blocking stabilization. Would be good to investigate though.
I hit this in https://github.com/dtolnay/async-trait/issues/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`
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?
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
@stephaneyfx pointed out a workaround (using FutureExt::map
) that appears to work in my case:
I don't think this helps async_trait
, but having this to compare to might help figure out the underlying cause.
Triage, no change in the output.
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.
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.
error[E0277]: `(dyn Future<Output = ()> + Send + 'static)` cannot be unpinned
--> src/main.rs:16:5
|
16 | type Future = Box<dyn Future<Output = ()> + Send>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `(dyn Future<Output = ()> + Send + 'static)`
|
= note: consider using `Box::pin`
= note: required because of the requirements on the impl of `Future` for `Box<(dyn Future<Output = ()> + Send + 'static)>`
note: required by a bound in `Foo::Future`
--> src/main.rs:4:25
|
4 | type Future: Future<Output = ()>;
| ^^^^^^^^^^^ required by this bound in `Foo::Future`
error: implementation of `Send` is not general enough
--> src/main.rs:19:9
|
19 | / Box::new(async move {
20 | | T::foo().await
21 | | })
| |__________^ implementation of `Send` is not general enough
|
= note: `<T as Foo<'0>>::Future` must implement `Send`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `<T as Foo<'a>>::Future`
Updated reproducer: (playground)
use core::pin::Pin;
use std::future::Future;
pub trait Foo<'a> {
type Future: Future<Output = ()>;
fn foo() -> Self::Future;
}
struct MyType<T>(T);
impl<'a, T> Foo<'a> for MyType<T>
where
T: Foo<'a>,
T::Future: Send,
{
type Future = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
fn foo() -> Self::Future {
Box::pin(async move {
T::foo().await
})
}
}
produces:
error: lifetime may not live long enough
--> src/lib.rs:21:9
|
12 | impl<'a, T> Foo<'a> for MyType<T>
| -- lifetime `'a` defined here
...
21 | / Box::pin(async move {
22 | | T::foo().await
23 | | })
| |__________^ cast requires that `'a` must outlive `'static`
error: higher-ranked lifetime error
--> src/lib.rs:21:9
|
21 | / Box::pin(async move {
22 | | T::foo().await
23 | | })
| |__________^
|
= note: could not prove `Pin<Box<[async block@src/lib.rs:21:18: 23:10]>>: CoerceUnsized<Pin<Box<(dyn Future<Output = ()> + Send + 'b)>>>`
error: could not compile `playground` due to 2 previous errors
as noted in https://github.com/rust-lang/rust/issues/60658#issuecomment-493043548, replacing T::Future: Send
with for<'b> <T as Foo<'b>>::Future: Send
makes the error go away.
Update: See https://github.com/rust-lang/rust/issues/60658#issuecomment-1509321859 for the latest reproducer
Minimal:
Out:
Compiler version:
rustc 1.36.0-nightly (2019-05-07)