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

Bug when using .flatten() method that has Item = &'a T when calling async function inside loop #126044

Open
Tracked by #110338
p0lunin opened this issue Jun 5, 2024 · 5 comments
Labels
A-async-await Area: Async & Await A-auto-traits Area: auto traits (e.g., `auto trait Send {}`) A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. D-confusing Diagnostics: Confusing error or lint that should be reworked.

Comments

@p0lunin
Copy link

p0lunin commented Jun 5, 2024

I tried this code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f560d75b3eb32ab6d2e0e51590b0337f

I expected to see this happen: code compiles

Instead, this happened: error: implementation of std::marker::Send is not general enough

Meta

rustc --version --verbose:

rustc 1.77.1 (7cf61ebde 2024-03-27)
binary: rustc
commit-hash: 7cf61ebde7b22796c69757901dd346d0fe70bd97
commit-date: 2024-03-27
host: x86_64-unknown-linux-gnu
release: 1.77.1
LLVM version: 17.0.6

Bug exists on beta and nightly versions also.

Backtrace

error: implementation of `std::marker::Send` is not general enough
  --> src/main.rs:63:5
   |
63 |     tokio::spawn(join_with_cancellation(f, cancellation.clone()));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `std::marker::Send` is not general enough
   |
   = note: `std::marker::Send` would have to be implemented for the type `&CancellationToken`
   = note: ...but `std::marker::Send` is actually implemented for the type `&'0 CancellationToken`, for some specific lifetime `'0`

I have working example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=19183aa875e3dadf501f3b6bdfb61ce4.

It seems like the reason is combination of .flatten() method that has Item = &'a T when calling async function inside loop. If you try to remove .await from the line 33, it compiles. If you try to remove .flatten() as in second link - it compiles.

Also, the error seems kinda random. The pattern is as follows:

   = note: ...but `std::marker::Send` is actually implemented for the type `&'0 T`, for some specific lifetime `'0`

But every time I change the code, the compiler shows another T type in error hint.

@p0lunin p0lunin added the C-bug Category: This is a bug. label Jun 5, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jun 5, 2024
@theemathas
Copy link
Contributor

Here's minimized code that causes a different but similarly confusing error message. Unsure if this still preserves the essence of the original code.

async fn listen() {
    let things: Vec<Vec<i32>> = vec![];
    for _ in things.iter().map(|n| n.iter()).flatten() {
        // comment this line and everything compiles
        async {}.await;
    }
}

fn require_send<T: Send>(_x: T) {}

fn foo() {
    let future = listen();
    require_send(future);
}

Playground link

Error message:

   Compiling playground v0.0.1 (/playground)
error: implementation of `FnOnce` is not general enough
  --> src/lib.rs:13:5
   |
13 |     require_send(future);
   |     ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&'0 Vec<i32>) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec<i32>,)>`, for any two lifetimes `'0` and `'1`...
   = note: ...but it actually implements `FnOnce<(&Vec<i32>,)>`

error: could not compile `playground` (lib) due to 1 previous error

@Kolsky
Copy link

Kolsky commented Jun 7, 2024

Both fn iter<T>(v: &Vec<T>) -> Iter<'_, T> { v.iter() } replacing closure and .flat_map(|n| n.iter()) make the code compile. The difference between FlatMap and Flatten is that the first one unifies lifetimes of returned U: IntoIterators, and the other tries to unify Map::<I, F: Fn(_) -> _>::Items, but F isn't higher ranked closure, and as such it fails to do so. Feel free to correct me if I'm wrong.

@veera-sivarajan
Copy link
Contributor

@rustbot label -needs-triage +A-diagnostics +A-Async-Await +A-auto-traits +A-traits +D-confusing

@rustbot rustbot added A-async-await Area: Async & Await A-auto-traits Area: auto traits (e.g., `auto trait Send {}`) A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system D-confusing Diagnostics: Confusing error or lint that should be reworked. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Jun 8, 2024
@theemathas
Copy link
Contributor

This doesn't use closures and has the same issue.

async fn listen() {
    let things: Vec<Vec<i32>> = vec![];
    for _ in things.iter().map(id).flatten() {
        // comment this line and everything compiles
        async {}.await;
    }
}

fn id<T>(x: T) -> T { x }

fn require_send<T: Send>(_x: T) {}

fn foo() {
    let future = listen();
    require_send(future);
}
   Compiling playground v0.0.1 (/playground)
error: implementation of `FnOnce` is not general enough
  --> src/lib.rs:15:5
   |
15 |     require_send(future);
   |     ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
   |
   = note: `fn(&'0 Vec<i32>) -> &'0 Vec<i32> {id::<&'0 Vec<i32>>}` must implement `FnOnce<(&'1 Vec<i32>,)>`, for any two lifetimes `'0` and `'1`...
   = note: ...but it actually implements `FnOnce<(&Vec<i32>,)>`

error: could not compile `playground` (lib) due to 1 previous error

@traviscross
Copy link
Contributor

@rustbot labels +AsyncAwait-Triaged

We discussed this in the async meeting today. We think this is probably related to:

@rustbot rustbot added the AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. label Jul 11, 2024
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-auto-traits Area: auto traits (e.g., `auto trait Send {}`) A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. D-confusing Diagnostics: Confusing error or lint that should be reworked.
Projects
None yet
Development

No branches or pull requests

6 participants