Point out source of recursion

This commit is contained in:
Michael Goulet 2023-11-08 07:19:01 +00:00
parent 82a2215481
commit 199af7cef0
13 changed files with 139 additions and 41 deletions

View File

@ -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),

View File

@ -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()
};

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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