Skip to content

diagnostic for naive recursive async functions is really unfriendly #62539

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
nikomatsakis opened this issue Jul 9, 2019 · 7 comments
Closed
Assignees
Labels
A-async-await Area: Async & Await AsyncAwait-Polish Async-await issues that are part of the "polish" area T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jul 9, 2019

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.

@nikomatsakis nikomatsakis added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-async-await Area: Async & Await AsyncAwait-Polish Async-await issues that are part of the "polish" area labels Jul 9, 2019
@gilescope
Copy link
Contributor

@rustbot claim

@nikomatsakis
Copy link
Contributor Author

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

@nikomatsakis
Copy link
Contributor Author

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

@withoutboats
Copy link
Contributor

withoutboats commented Jul 9, 2019

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.

@nikomatsakis
Copy link
Contributor Author

It looks like the error is issued here:

fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, span: Span) {
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
let mut err = struct_span_err!(
tcx.sess, span, E0720,
"opaque type expands to a recursive type",
);
err.span_label(span, "expands to self-referential type");
if let ty::Opaque(..) = partially_expanded_type.sty {
err.note("type resolves to itself");
} else {
err.note(&format!("expanded type is `{}`", partially_expanded_type));
}
err.emit();
}
}

That function is invoked from here:

hir::ItemKind::Existential(..) => {
let def_id = tcx.hir().local_def_id(it.hir_id);
let substs = InternalSubsts::identity_for_item(tcx, def_id);
check_opaque(tcx, def_id, substs, it.span);
}

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.

Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this issue Jul 18, 2019
…sion, r=eddyb

Self-referencial type now called a recursive type

As per Boat's suggestion - rust-lang#62539, this makes the error message clearer.
@gilescope
Copy link
Contributor

I presume use a new error number rather than E0720?

Centril added a commit to Centril/rust that referenced this issue Jul 28, 2019
…Centril

Explicit error message for async recursion.

Attempt at clearer error message when async recusion is attempted. In response to rust-lang#62539 (and rust-lang#53690).
@Centril
Copy link
Contributor

Centril commented Jul 29, 2019

Fixed in #62871.

@Centril Centril closed this as completed Jul 29, 2019
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-async-await Area: Async & Await AsyncAwait-Polish Async-await issues that are part of the "polish" area T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants