diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 26bf9ec8be8ad..8b992ce810b8e 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -161,13 +161,6 @@ impl<'tcx, T> Value> for Result> tcx.def_kind_descr_article(def_kind, def_id.to_def_id()), tcx.def_kind_descr(def_kind, def_id.to_def_id()), ); - if matches!(coroutine_kind, hir::CoroutineKind::Async(_)) { - diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future"); - diag.note( - "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion", - ); - } - let mut called = false; for (i, frame) in cycle_error.cycle.iter().enumerate() { if frame.query.dep_kind != dep_kinds::layout_of { continue; @@ -175,7 +168,8 @@ impl<'tcx, T> Value> for Result> let Some(frame_def_id) = frame.query.ty_def_id else { continue; }; - if !matches!(tcx.def_kind(frame_def_id), DefKind::Coroutine) { + let def_kind = tcx.def_kind(frame_def_id); + if !matches!(def_kind, DefKind::Coroutine) { continue; } let frame_span = frame @@ -184,8 +178,26 @@ impl<'tcx, T> Value> for Result> if frame_span.is_dummy() { continue; } - diag.span_label(frame_span, if called { "...which calls this" } else { "recursive call here" }); - called = true; + if i == 0 { + diag.span_label(frame_span, "recursive call here"); + } else { + let coroutine_span: Span = if tcx + .coroutine_kind(frame_def_id) + .expect("expected coroutine to have a coroutine_kind").is_fn_like() { + tcx.def_span(tcx.parent(frame_def_id)) + } else { + tcx.def_span(frame_def_id) + }; + let mut multispan = MultiSpan::from_span(coroutine_span); + multispan.push_span_label(frame_span, "...leading to this recursive call"); + diag.span_note(multispan, format!("which leads to this {}", tcx.def_kind_descr(def_kind, frame_def_id))); + } + } + if matches!(coroutine_kind, hir::CoroutineKind::Async(_)) { + diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future"); + diag.note( + "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion", + ); } diag.emit() } else { diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr index cd3712c47ba0f..af0844ff3e213 100644 --- a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr @@ -5,10 +5,14 @@ LL | async fn rec_1() { | ^^^^^^^^^^^^^^^^ LL | rec_2().await; | ------------- recursive call here -... -LL | rec_1().await; - | ------------- ...which calls this | +note: which leads to this async fn + --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:1 + | +LL | async fn rec_2() { + | ^^^^^^^^^^^^^^^^ +LL | rec_1().await; + | ------------- ...leading to this recursive call = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion diff --git a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr index 7b4c6339f9ef3..ca06b62487957 100644 --- a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr +++ b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr @@ -1,14 +1,18 @@ error[E0733]: recursion in an async block requires boxing --> $DIR/indirect-recursion-issue-112047.rs:21:9 | -LL | t.recur().await; - | --------------- ...which calls this -... LL | async move { recur(self).await; } | ^^^^^^^^^^^^^-----------------^^^ | | | recursive call here | +note: which leads to this async fn + --> $DIR/indirect-recursion-issue-112047.rs:13:1 + | +LL | async fn recur(t: impl Recur) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | t.recur().await; + | --------------- ...leading to this recursive call = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion