-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Why implementation of iterator is not generic enough in async context? #71671
Comments
This bit me today. Reduced test case (playground): pub trait Robot {
type Id;
}
pub type DynRobot = Box<dyn Robot<Id = u32> + Send>;
impl Robot for DynRobot {
type Id = u32;
}
struct IRobot<R: Robot> {
id: R::Id,
robot: R,
}
// stand-in for tokio::spawn
fn this_is_send<T: Send>(value: T) -> T {
value
}
fn test(source: DynRobot) {
let _my_task = this_is_send(async move {
let _my_iter = IRobot {
id: 32,
robot: source,
};
tokio::task::yield_now().await;
});
} rustc output:
|
This results in very confusing errors sometimes multiple function calls removed from the change. /*
error: implementation of `Iterator` is not general enough
--> src/platform/mod.rs:13:9
|
13 | tokio::spawn(Thing::task(thing.clone()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Iterator` is not general enough
|
= note: `Iterator` would have to be implemented for the type `std::slice::Iter<'0, i32>`, for any lifetime `'0`...
= note: ...but `Iterator` is actually implemented for the type `std::slice::Iter<'1, i32>`, for some specific lifetime `'1`
error: implementation of `FnOnce` is not general enough
--> src/platform/mod.rs:13:9
|
13 | tokio::spawn(Thing::task(thing.clone()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'0 i32) -> impl futures::Future<Output = ()>` must implement `FnOnce<(&i32,)>`, for any lifetime `'0`...
= note: ...but it actually implements `FnOnce<(&i32,)>`
*/
use std::{sync::Arc, time::Duration};
use futures::{future::join_all, StreamExt};
struct Thing{}
impl Thing {
pub async fn new() -> Arc<Self> {
let thing = Arc::new(Thing{});
tokio::spawn(Thing::task(thing.clone()));
//Thing::task(thing.clone()).await; //This compiles
thing
}
pub async fn task(self : Arc<Self>) {
self.task_inner().await;
}
pub async fn task_inner(&self){
let v = vec![1,2,3];
let futs = v.iter() // make this into_iter() and it works
.map(|a| async move {});
//uncomment this and it works
//let futs : Vec<_> = futs.collect();
//always works:
//join_all(futs).await;
//results in error all the way in new()
let stream = futures::stream::iter(futs).buffer_unordered(10);
let results = stream.collect::<()>().await;
}
} Notably this only occurs with borrowed iterators, collecting or using into_iter fixes the issue. One question is, should task_inner compile at all? Rustc doesn't have an issue with calling it outside of a tokio::spawn. |
Is there any explanation for the cause of this? This seems to be a very frequently reported issue, and I didn't see any plausible explanation from the rust-lang team, other than just keep cross linking the similar issue in different threads. Can't believe this is still happening after 4 years! @tmandry |
Cross posting stackoverflow because it's look like a compiler bug/limitation.
Given the following snippet:
I get the following errors:
I was expecting no error because the lifetimes seem to be correct to me. Note that removing
main()
or removing the code insidefrom_bar()
both eliminate the errors. Not only that, the error messages are also very strange. They may be related to a regression in the compiler, though more than that they seem to be in the wrong place (maybe related).Version
rustc 1.43.0 (4fb7144ed 2020-04-20)
:Maybe related #64650
The text was updated successfully, but these errors were encountered: