about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/util.rs45
-rw-r--r--compiler/rustc_middle/src/values.rs58
-rw-r--r--tests/ui/async-await/in-trait/async-recursive-generic.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive-generic.stderr9
-rw-r--r--tests/ui/async-await/in-trait/async-recursive.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive.stderr9
-rw-r--r--tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs2
-rw-r--r--tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr15
-rw-r--r--tests/ui/async-await/recursive-async-impl-trait-type.rs2
-rw-r--r--tests/ui/async-await/recursive-async-impl-trait-type.stderr9
-rw-r--r--tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr15
13 files changed, 139 insertions, 41 deletions
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 74dba41647b..f11a24543f3 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -729,16 +729,43 @@ impl<'tcx> TyCtxt<'tcx> {
             DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method",
             DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
                 match coroutine_kind {
-                    hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => {
-                        "async closure"
-                    }
-                    hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
-                        "async gen closure"
-                    }
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::Async,
+                        hir::CoroutineSource::Fn,
+                    ) => "async fn",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::Async,
+                        hir::CoroutineSource::Block,
+                    ) => "async block",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::Async,
+                        hir::CoroutineSource::Closure,
+                    ) => "async closure",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::AsyncGen,
+                        hir::CoroutineSource::Fn,
+                    ) => "async gen fn",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::AsyncGen,
+                        hir::CoroutineSource::Block,
+                    ) => "async gen block",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::AsyncGen,
+                        hir::CoroutineSource::Closure,
+                    ) => "async gen closure",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::Gen,
+                        hir::CoroutineSource::Fn,
+                    ) => "gen fn",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::Gen,
+                        hir::CoroutineSource::Block,
+                    ) => "gen block",
+                    hir::CoroutineKind::Desugared(
+                        hir::CoroutineDesugaring::Gen,
+                        hir::CoroutineSource::Closure,
+                    ) => "gen closure",
                     hir::CoroutineKind::Coroutine(_) => "coroutine",
-                    hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
-                        "gen closure"
-                    }
                 }
             }
             _ => def_kind.descr(def_id),
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 0179829cc46..3e3aa821b4e 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -138,7 +138,8 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
         let guar = if cycle_error.cycle[0].query.dep_kind == dep_kinds::layout_of
             && let Some(def_id) = cycle_error.cycle[0].query.ty_def_id
             && let Some(def_id) = def_id.as_local()
-            && matches!(tcx.def_kind(def_id), DefKind::Closure)
+            && let def_kind = tcx.def_kind(def_id)
+            && matches!(def_kind, DefKind::Closure)
             && let Some(coroutine_kind) = tcx.coroutine_kind(def_id)
         {
             // FIXME: `def_span` for an fn-like coroutine will point to the fn's body
@@ -150,13 +151,56 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
             } else {
                 tcx.def_span(def_id)
             };
-            struct_span_err!(tcx.sess.dcx(), span, E0733, "recursion in an `async fn` requires boxing")
-                .span_label(span, "recursive `async fn`")
-                .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
-                .note(
+            let mut diag = struct_span_err!(
+                tcx.sess.dcx(),
+                span,
+                E0733,
+                "recursion in {} {} requires boxing",
+                tcx.def_kind_descr_article(def_kind, def_id.to_def_id()),
+                tcx.def_kind_descr(def_kind, def_id.to_def_id()),
+            );
+            for (i, frame) in cycle_error.cycle.iter().enumerate() {
+                if frame.query.dep_kind != dep_kinds::layout_of {
+                    continue;
+                }
+                let Some(frame_def_id) = frame.query.ty_def_id else {
+                    continue;
+                };
+                let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else {
+                    continue;
+                };
+                let frame_span = frame
+                    .query
+                    .default_span(cycle_error.cycle[(i + 1) % cycle_error.cycle.len()].span);
+                if frame_span.is_dummy() {
+                    continue;
+                }
+                if i == 0 {
+                    diag.span_label(frame_span, "recursive call here");
+                } else {
+                    let coroutine_span = if frame_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_descr(frame_def_id)),
+                    );
+                }
+            }
+            if matches!(
+                coroutine_kind,
+                hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::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",
-                )
-                .emit()
+                );
+            }
+            diag.emit()
         } else {
             report_cycle(tcx.sess, cycle_error).emit()
         };
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.rs b/tests/ui/async-await/in-trait/async-recursive-generic.rs
index c6031ce28d1..33eb2b2de13 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.rs
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.rs
@@ -6,7 +6,7 @@ trait MyTrait<T> {
 
 impl<T> MyTrait<T> for T where T: Copy {
     async fn foo_recursive(&self, n: usize) -> T {
-        //~^ ERROR recursion in an `async fn` requires boxing
+        //~^ ERROR recursion in an async fn requires boxing
         if n > 0 {
             self.foo_recursive(n - 1).await
         } else {
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.stderr
index 11489c18ad4..37de274565d 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.stderr
@@ -1,10 +1,13 @@
-error[E0733]: recursion in an `async fn` requires boxing
+error[E0733]: recursion in an async fn requires boxing
   --> $DIR/async-recursive-generic.rs:8:5
    |
 LL |     async fn foo_recursive(&self, n: usize) -> T {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |             self.foo_recursive(n - 1).await
+   |             ------------------------------- recursive call here
    |
-   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = 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
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/async-await/in-trait/async-recursive.rs b/tests/ui/async-await/in-trait/async-recursive.rs
index 09f1ffe499e..2534c43413e 100644
--- a/tests/ui/async-await/in-trait/async-recursive.rs
+++ b/tests/ui/async-await/in-trait/async-recursive.rs
@@ -6,7 +6,7 @@ trait MyTrait {
 
 impl MyTrait for i32 {
     async fn foo_recursive(&self, n: usize) -> i32 {
-        //~^ ERROR recursion in an `async fn` requires boxing
+        //~^ ERROR recursion in an async fn requires boxing
         if n > 0 {
             self.foo_recursive(n - 1).await
         } else {
diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.stderr
index 58796285726..6b99c516c3b 100644
--- a/tests/ui/async-await/in-trait/async-recursive.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive.stderr
@@ -1,10 +1,13 @@
-error[E0733]: recursion in an `async fn` requires boxing
+error[E0733]: recursion in an async fn requires boxing
   --> $DIR/async-recursive.rs:8:5
    |
 LL |     async fn foo_recursive(&self, n: usize) -> i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |             self.foo_recursive(n - 1).await
+   |             ------------------------------- recursive call here
    |
-   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = 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
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs
index d38ba1a569b..fedc814b041 100644
--- a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs
+++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs
@@ -2,7 +2,7 @@
 // Test that impl trait does not allow creating recursive types that are
 // otherwise forbidden when using `async` and `await`.
 
-async fn rec_1() { //~ ERROR recursion in an `async fn`
+async fn rec_1() { //~ ERROR recursion in an async fn
     rec_2().await;
 }
 
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 dd53075be60..3f2ee4150da 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
@@ -1,10 +1,19 @@
-error[E0733]: recursion in an `async fn` requires boxing
+error[E0733]: recursion in an async fn requires boxing
   --> $DIR/mutually-recursive-async-impl-trait-type.rs:5:1
    |
 LL | async fn rec_1() {
-   | ^^^^^^^^^^^^^^^^ recursive `async fn`
+   | ^^^^^^^^^^^^^^^^
+LL |     rec_2().await;
+   |     ------------- recursive call here
    |
-   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+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
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.rs b/tests/ui/async-await/recursive-async-impl-trait-type.rs
index edc4cb8ac5d..9351ee53f07 100644
--- a/tests/ui/async-await/recursive-async-impl-trait-type.rs
+++ b/tests/ui/async-await/recursive-async-impl-trait-type.rs
@@ -3,7 +3,7 @@
 // otherwise forbidden when using `async` and `await`.
 
 async fn recursive_async_function() -> () {
-    //~^ ERROR recursion in an `async fn` requires boxing
+    //~^ ERROR recursion in an async fn requires boxing
     recursive_async_function().await;
 }
 
diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.stderr
index 969258f84ed..cec92c54f01 100644
--- a/tests/ui/async-await/recursive-async-impl-trait-type.stderr
+++ b/tests/ui/async-await/recursive-async-impl-trait-type.stderr
@@ -1,10 +1,13 @@
-error[E0733]: recursion in an `async fn` requires boxing
+error[E0733]: recursion in an async fn requires boxing
   --> $DIR/recursive-async-impl-trait-type.rs:5:1
    |
 LL | async fn recursive_async_function() -> () {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     recursive_async_function().await;
+   |     -------------------------------- recursive call here
    |
-   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = 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
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
index 0dabba26468..16a9012958e 100644
--- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
+++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
@@ -109,14 +109,14 @@ LL |
 LL |     (substs_change::<&T>(),)
    |     ------------------------ returning here with type `(impl Sized,)`
 
-error[E0733]: recursion in an `async fn` requires boxing
+error[E0733]: recursion in a coroutine requires boxing
   --> $DIR/recursive-impl-trait-type-indirect.rs:73:5
    |
 LL |     move || {
-   |     ^^^^^^^ recursive `async fn`
-   |
-   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
-   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+   |     ^^^^^^^
+LL |
+LL |         let x = coroutine_hold();
+   |             - recursive call here
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:86:26
diff --git a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs
index 3637f416c7b..7a2ea881b64 100644
--- a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs
+++ b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs
@@ -19,7 +19,7 @@ impl Recur for () {
 
     fn recur(self) -> Self::Recur {
         async move { recur(self).await; }
-        //~^ ERROR recursion in an `async fn` requires boxing
+        //~^ ERROR recursion in an async block requires boxing
     }
 }
 
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 aa352b326c6..5427ebe92ad 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,10 +1,19 @@
-error[E0733]: recursion in an `async fn` requires boxing
+error[E0733]: recursion in an async block requires boxing
   --> $DIR/indirect-recursion-issue-112047.rs:21:9
    |
 LL |         async move { recur(self).await; }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
+   |         ^^^^^^^^^^^^^-----------------^^^
+   |                      |
+   |                      recursive call here
    |
-   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+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
 
 error: aborting due to 1 previous error