Rust: diagnostic for naive recursive async functions is really unfriendly

Created on 9 Jul 2019  路  7Comments  路  Source: rust-lang/rust

The following Rust source (playground):

#![feature(async_await)]

async fn foo(n: usize) {
    if n > 0 {
        foo(n - 1).await;
    }
}

fn main() {
}

gives the error:

error[E0720]: opaque type expands to a recursive type
 --> src/main.rs:3:24
  |
3 | async fn foo(n: usize) {
  |                        ^ expands to self-referential type
  |
  = note: expanded type is `std::future::GenFuture<[static generator@src/main.rs:3:24: 7:2 n:usize {usize, bool, impl std::future::Future, ()}]>`

We could be a lot clearer.


A-async-await AsyncAwait-Focus F-async_await T-compiler

Most helpful comment

In addition to adding specific output for async fn, it would also be good to stop outputing "self-referential type" in any context, and instead use "recursive type" as this error message does at one point. Nowadays, "self-referential" is used very often to mean they have references pointing into themselves, rather than how it is being used here, and someone who googles it will get very unhelpful results. I imagine this fix would just be a search and replace.

All 7 comments

@rustbot claim

I think an error like

error[E0720]: recursion is not supported in async fn
 --> src/main.rs:3:24
  |
3 | async fn foo(n: usize) {
  |                        ^ async fn cannot invoke themselves directly
  |
  = note: to create a recursive async fn, you must rewrite to return a boxed future
  = for more information, see https://rust-lang.github.io/async-book/index.html

I suspect we can intercept that "opaque type" error and check on the origin field of the opaque type, looking for AsyncFn

In addition to adding specific output for async fn, it would also be good to stop outputing "self-referential type" in any context, and instead use "recursive type" as this error message does at one point. Nowadays, "self-referential" is used very often to mean they have references pointing into themselves, rather than how it is being used here, and someone who googles it will get very unhelpful results. I imagine this fix would just be a search and replace.

It looks like the error is issued here:

https://github.com/rust-lang/rust/blob/b8ec4c4d11ede0fba333a0474ed473dbe82aacf1/src/librustc_typeck/check/mod.rs#L1317-L1331

That function is invoked from here:

https://github.com/rust-lang/rust/blob/b8ec4c4d11ede0fba333a0474ed473dbe82aacf1/src/librustc_typeck/check/mod.rs#L1379-L1384

In that caller's location, we can access the argument to the Existential variant, which is a ExistTy struct. That struct has a field origin that tell us where the existential type came from. If we pass that field into the original function I cited, it can check if this is an async function and alter the error message wording.

I presume use a new error number rather than E0720?

Was this page helpful?
0 / 5 - 0 ratings