Recursive async functions don't internally implement auto traits
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
fn spawn<F: Send>(_f: F) {}
pub async fn recur() {
spawn(recur())
}
I expected to see this happen: Compiles successfully.
Instead, this happened:
error: cannot check whether the hidden type of opaque type satisfies auto traits
--> src/lib.rs:4:11
|
4 | spawn(recur())
| ----- ^^^^^^^
| |
| required by a bound introduced by this call
|
note: opaque type is declared here
--> src/lib.rs:3:1
|
3 | pub async fn recur() {
| ^^^^^^^^^^^^^^^^^^^^
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
--> src/lib.rs:3:14
|
3 | pub async fn recur() {
| ^^^^^
note: required by a bound in `spawn`
--> src/lib.rs:1:13
|
1 | fn spawn<F: Send>(_f: F) {}
| ^^^^ required by this bound in `spawn`
It seems like recursive async functions only externally implement auto traits like Send. If you require Send inside its own body, then the function does not compile. This is extra unfortunate because recursive async functions require indirection, and one way of achieving that is by spawning it on a multithreaded executor. The diagnostic is also unhelpful. I'm not sure what it's actually for, but it sounds impossible to apply to this situation. The real solution I found is to manually desugar the async function into a regular function that returns an impl Future + Send:
fn spawn<F: Send>(_f: F) {}
pub fn recur() -> impl core::future::Future<Output = ()> + Send {
async {
spawn(recur())
}
}
However, it would be ideal if the original was allowed as-is.
This is similar to #119727 but without the cycle error.
This was originally found in URLO: With tokio, “future returned by ‘a’ is not ‘Send’”, with tiny example
Meta
rustc 1.79.0-nightly 2024-03-24 from play.rust-lang.org
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the minimal recursive async example from the issue and compare it with the manually desugared version returning impl Future + Send. Investigate how rustc handles auto traits for the hidden future type during recursive async-body checking. Done means the original example compiles with the required Send bound and no misleading diagnostic.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100