-
Notifications
You must be signed in to change notification settings - Fork 13.3k
error[E0391]: cycle detected when computing type of async fn #78649
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
Comments
A bit of a weird error message:
|
I think this is expected behavior? You can't have recursive async functions: https://www.reddit.com/r/rust/comments/cbdxxm/why_are_recursive_async_fns_forbidden/ |
The error message is pretty bad, though. |
@jyn514 this is not a recursive function. |
For reference, the following very similar code snippet compiles just fine, and should be equivalent (modulo a Pin and some marker traits): async fn foo() {
Box::new(async {
foo().await;
});
} |
Discussed during the wg-async-foundations meeting. It seems the difference in the examples could be coming from the signature of fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a + Send>> ...demanding More spelunking will be needed to figure out where exactly the cycle is coming from and how hard it will be to avoid. |
I don't think is important to prioritize this one given that the async wg is already on it. |
Any update on this? |
Posting it here for the sake of visibility: in #87850 I've showcased a minimal repro of actually the issue here: featuring an auto-trait constraint on an existential type triggers this error (at least at the definition site of the existential; haven't checked beyond that). |
I'm going to spend some time looking at this over the next async team sprint. @rustbot claim |
I'm finally getting around to looking at this today. Here's a standalone test case: use std::future::Future;
use std::pin::Pin;
fn boxed<'a, F, T>(x: F) -> Pin<Box<dyn Future<Output = T> + Send + 'a>>
where
F: Future<Output = T> + Sized + Send + 'a,
{
Box::pin(x)
}
async fn foo() {
boxed(async {
foo().await;
});
}
fn main() {
let _ = foo();
} The query stack when cycle comes up is:
If I remove the I'm a little surprised to see that borrow checking is needed to find the type of |
I guess you'd like a
In this instance, however, maybe an approach would be for the query that checks whether an existential implements an auto-trait to temporarily "cache the 'does it impl the auto-trait'" query with a positive answer? As in:
I know it's pretty wave-handed, so I apologize if that's not how this compiler stuff works: the way I've understood it (which may be wrong!), is that currently the For completeness regarding that algorithm, if
|
Thanks for the suggestions, @danielhenrymantilla! After thinking about this some more, I think this is going to take some much more significant changes that I'm ready to make right now. I'm going to shelve this issue for now. |
This issue is preventing ergonomic recursive async functions. At the moment, one would have to write (writing from memory here, but you get the idea): fn foo() -> BoxFuture<()> {
Box::pin(async move {
foo().await
}) as BoxFuture<()>
} with this issue resolved, one could move the boxing down to only recursive calls: async fn foo() {
(Box::pin(foo()) as BoxFuture<()>).await
} This is not only more ergonomic, but also it is truly zero cost, while the current workaround is not (you always pay for the dynamic dispatch even when you don't recurse). I found a workaround that is zero cost: async fn foo() {
#[inline(always)]
fn foo_recurse() -> futures::future::BoxFuture<()> {
Box::pin(foo())
}
foo_recurse().await
} I find it really interesting that this works, but manually inlining the function triggers the bug. |
I tried this code:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=19653eea2af1dd97a8d48126dfd7d683
I expected it to compile, but it gave the following error:
edit:
With one minor change, it compiles:
There are no rules that would explain why the first should fail when this succeeds.
The text was updated successfully, but these errors were encountered: