yoshuawuyts/futures-concurrency
View on GitHubConcurrentStream: issues with `Send` and `Sync` bounds
Open
#195 opened on Sep 29, 2024
help wanted
Repository metrics
- Stars
- (497 stars)
- PR merge metrics
- (PR metrics pending)
Description
There appears to be some invariance introduced by the IntoConcurrentStream and Map implementation that confuses the compiler for the Send and Sync autotraits
The following:
use futures_concurrency::concurrent_stream::{ConcurrentStream, IntoConcurrentStream};
fn assert_value_send_sync<T: Send + Sync>(_v: &T) {}
async fn iterative_method(context: &str) -> Vec<String> {
let vec: Vec<u32> = Vec::new();
let mut acc = Vec::new();
for item in vec {
acc.push(handle_item(&item, &context).await);
}
acc
}
async fn concurrent_method(context: &str) -> Vec<String> {
let vec: Vec<u32> = Vec::new();
vec.into_co_stream()
.map(|d| async move { handle_item(&d, &*context).await })
.collect()
.await
}
async fn handle_item(item: &u32, context: &str) -> String {
format!("{context}: {item}")
}
fn main() {
let context = String::new();
let iterative = async {
iterative_method(&context).await;
};
assert_value_send_sync(&iterative);
let concurrent = async {
concurrent_method(&context).await;
};
assert_value_send_sync(&concurrent);
}
fails with the error:
rror[E0308]: mismatched types
--> src/main.rs:36:5
|
17 | .map(|d| async move { handle_item(&d, &*context).await })
| ----------
| |
| the expected `async` block
| the found `async` block
...
36 | assert_value_send_sync(&concurrent);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected `async` block `{async block@src/main.rs:17:18: 17:28}`
found `async` block `{async block@src/main.rs:17:18: 17:28}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
note: the lifetime requirement is introduced here
--> src/main.rs:3:30
|
3 | fn assert_value_send_sync<T: Send + Sync>(_v: &T) {}
| ^^^^
error[E0308]: mismatched types
--> src/main.rs:36:5
|
17 | .map(|d| async move { handle_item(&d, &*context).await })
| ----------
| |
| the expected `async` block
| the found `async` block
...
36 | assert_value_send_sync(&concurrent);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected `async` block `{async block@src/main.rs:17:18: 17:28}`
found `async` block `{async block@src/main.rs:17:18: 17:28}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
note: the lifetime requirement is introduced here
--> src/main.rs:3:37
|
3 | fn assert_value_send_sync<T: Send + Sync>(_v: &T) {}
| ^^^^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `future-concurrency-repro` (bin "future-concurrency-repro") due to 2 previous errors
I can't make a minimal reproducer, but I first encountered this error message, which I think it's the same issue. To me this suggests this might even be a bug in rustc. Even if it isn't a bug, the error message makes no sense and should be fixed.
error: implementation of `Send` is not general enough
--> src/main.rs:348:34
|
348 | .route("/dashboard/:id", post(dashboard_post))
| ^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&str`
= note: ...but `Send` is actually implemented for the type `&'0 str`, for some specific lifetime `'0`