Skip to content

Commit 389aee6

Browse files
Point out source of recursion
1 parent 00739bd commit 389aee6

9 files changed

+74
-25
lines changed

compiler/rustc_hir/src/hir.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,10 @@ pub enum CoroutineKind {
15311531

15321532
impl CoroutineKind {
15331533
pub fn is_fn_like(self) -> bool {
1534-
matches!(self, CoroutineKind::Async(CoroutineSource::Fn) | CoroutineKind::Gen(CoroutineSource::Fn))
1534+
matches!(
1535+
self,
1536+
CoroutineKind::Async(CoroutineSource::Fn) | CoroutineKind::Gen(CoroutineSource::Fn)
1537+
)
15351538
}
15361539
}
15371540

compiler/rustc_middle/src/values.rs

+34-10
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
136136
_guar: ErrorGuaranteed,
137137
) -> Self {
138138
let guar = if cycle_error.cycle[0].query.dep_kind == dep_kinds::layout_of
139-
&& let Some(def_id) = cycle_error.cycle[0].query.ty_def_id
140-
&& let Some(def_id) = def_id.as_local()
141-
&& matches!(tcx.def_kind(def_id), DefKind::Coroutine)
139+
&& let Some(def_id) = cycle_error.cycle[0].query.ty_def_id
140+
&& let Some(def_id) = def_id.as_local()
141+
&& matches!(tcx.def_kind(def_id), DefKind::Coroutine)
142142
{
143143
let hir = tcx.hir();
144144
let coroutine_kind = hir
@@ -154,13 +154,37 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
154154
} else {
155155
tcx.def_span(def_id)
156156
};
157-
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
158-
.span_label(span, "recursive `async fn`")
159-
.note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
160-
.note(
161-
"consider using the `async_recursion` crate: https://crates.io/crates/async_recursion",
162-
)
163-
.emit()
157+
let mut diag = struct_span_err!(
158+
tcx.sess,
159+
span,
160+
E0733,
161+
"recursion in an `async fn` requires boxing"
162+
);
163+
diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future");
164+
diag.note(
165+
"consider using the `async_recursion` crate: https://crates.io/crates/async_recursion",
166+
);
167+
let mut called = false;
168+
for (i, frame) in cycle_error.cycle.iter().enumerate() {
169+
if frame.query.dep_kind != dep_kinds::layout_of {
170+
continue;
171+
}
172+
let Some(frame_def_id) = frame.query.ty_def_id else {
173+
continue;
174+
};
175+
if !matches!(tcx.def_kind(frame_def_id), DefKind::Coroutine) {
176+
continue;
177+
}
178+
let frame_span = frame
179+
.query
180+
.default_span(cycle_error.cycle[(i + 1) % cycle_error.cycle.len()].span);
181+
if frame_span.is_dummy() {
182+
continue;
183+
}
184+
diag.span_label(frame_span, if called { "...which calls this" } else { "recursive call here" });
185+
called = true;
186+
}
187+
diag.emit()
164188
} else {
165189
report_cycle(tcx.sess, cycle_error).emit()
166190
};

tests/ui/async-await/in-trait/async-recursive-generic.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ error[E0733]: recursion in an `async fn` requires boxing
22
--> $DIR/async-recursive-generic.rs:8:5
33
|
44
LL | async fn foo_recursive(&self, n: usize) -> T {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
...
7+
LL | self.foo_recursive(n - 1).await
8+
| ------------------------------- recursive call here
69
|
7-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
10+
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
811
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
912

1013
error: aborting due to previous error

tests/ui/async-await/in-trait/async-recursive.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ error[E0733]: recursion in an `async fn` requires boxing
22
--> $DIR/async-recursive.rs:8:5
33
|
44
LL | async fn foo_recursive(&self, n: usize) -> i32 {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
...
7+
LL | self.foo_recursive(n - 1).await
8+
| ------------------------------- recursive call here
69
|
7-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
10+
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
811
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
912

1013
error: aborting due to previous error

tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ error[E0733]: recursion in an `async fn` requires boxing
22
--> $DIR/indirect-recursion-issue-112047.rs:32:5
33
|
44
LL | async fn second(self) {
5-
| ^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
5+
| ^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
7+
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
88
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
99

1010
error: aborting due to previous error

tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ error[E0733]: recursion in an `async fn` requires boxing
22
--> $DIR/mutually-recursive-async-impl-trait-type.rs:5:1
33
|
44
LL | async fn rec_1() {
5-
| ^^^^^^^^^^^^^^^^ recursive `async fn`
5+
| ^^^^^^^^^^^^^^^^
6+
LL | rec_2().await;
7+
| ------------- recursive call here
8+
...
9+
LL | rec_1().await;
10+
| ------------- ...which calls this
611
|
7-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
12+
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
813
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
914

1015
error: aborting due to previous error

tests/ui/async-await/recursive-async-impl-trait-type.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ error[E0733]: recursion in an `async fn` requires boxing
22
--> $DIR/recursive-async-impl-trait-type.rs:5:1
33
|
44
LL | async fn recursive_async_function() -> () {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
LL |
7+
LL | recursive_async_function().await;
8+
| -------------------------------- recursive call here
69
|
7-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
10+
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
811
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
912

1013
error: aborting due to previous error

tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,12 @@ error[E0733]: recursion in an `async fn` requires boxing
113113
--> $DIR/recursive-impl-trait-type-indirect.rs:73:5
114114
|
115115
LL | move || {
116-
| ^^^^^^^ recursive `async fn`
116+
| ^^^^^^^
117+
LL |
118+
LL | let x = coroutine_hold();
119+
| - recursive call here
117120
|
118-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
121+
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
119122
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
120123

121124
error[E0720]: cannot resolve opaque type

tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
error[E0733]: recursion in an `async fn` requires boxing
22
--> $DIR/indirect-recursion-issue-112047.rs:21:9
33
|
4+
LL | t.recur().await;
5+
| --------------- ...which calls this
6+
...
47
LL | async move { recur(self).await; }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
8+
| ^^^^^^^^^^^^^-----------------^^^
9+
| |
10+
| recursive call here
611
|
7-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
12+
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
813
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
914

1015
error: aborting due to previous error

0 commit comments

Comments
 (0)