mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-21 12:13:12 +00:00
Make cycle error more resilient to where it starts
Also don't recomment recursive_async crate anymore Co-authored-by: lcnr <rust@lcnr.de>
This commit is contained in:
parent
fa2ff51ace
commit
841184bcae
@ -11,6 +11,7 @@ use rustc_query_system::Value;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Write;
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
|
||||
@ -135,73 +136,79 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
|
||||
cycle_error: &CycleError,
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
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()
|
||||
&& 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
|
||||
// due to interactions between the desugaring into a closure expr and the
|
||||
// def_span code. I'm not motivated to fix it, because I tried and it was
|
||||
// not working, so just hack around it by grabbing the parent fn's span.
|
||||
let span = if coroutine_kind.is_fn_like() {
|
||||
tcx.def_span(tcx.local_parent(def_id))
|
||||
} else {
|
||||
tcx.def_span(def_id)
|
||||
};
|
||||
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))
|
||||
let mut cycle: VecDeque<_> = cycle_error.cycle.iter().collect();
|
||||
|
||||
let guar = 'search: {
|
||||
for _ in 0..cycle.len() {
|
||||
if cycle[0].query.dep_kind == dep_kinds::layout_of
|
||||
&& let Some(def_id) = cycle[0].query.ty_def_id
|
||||
&& let Some(def_id) = def_id.as_local()
|
||||
&& 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
|
||||
// due to interactions between the desugaring into a closure expr and the
|
||||
// def_span code. I'm not motivated to fix it, because I tried and it was
|
||||
// not working, so just hack around it by grabbing the parent fn's span.
|
||||
let span = if coroutine_kind.is_fn_like() {
|
||||
tcx.def_span(tcx.local_parent(def_id))
|
||||
} else {
|
||||
tcx.def_span(frame_def_id)
|
||||
tcx.def_span(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)),
|
||||
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.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[(i + 1) % cycle.len()].span);
|
||||
if frame_span.is_dummy() {
|
||||
continue;
|
||||
}
|
||||
if i == 0 {
|
||||
diag.span_label(frame_span, "recursive call here");
|
||||
} else {
|
||||
let coroutine_span: 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)),
|
||||
);
|
||||
}
|
||||
}
|
||||
// FIXME: We could report a structured suggestion if we had
|
||||
// enough info here... Maybe we can use a hacky HIR walker.
|
||||
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");
|
||||
}
|
||||
break 'search diag.emit();
|
||||
} else {
|
||||
cycle.rotate_left(1);
|
||||
}
|
||||
}
|
||||
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",
|
||||
);
|
||||
}
|
||||
diag.emit()
|
||||
} else {
|
||||
report_cycle(tcx.sess, cycle_error).emit()
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,6 @@ LL | self.foo_recursive(n - 1).await
|
||||
| ------------------------------- recursive call here
|
||||
|
|
||||
= 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
|
||||
|
||||
|
@ -8,7 +8,6 @@ LL | self.foo_recursive(n - 1).await
|
||||
| ------------------------------- recursive call here
|
||||
|
|
||||
= 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
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// edition: 2021
|
||||
|
||||
// Test doesn't fail until monomorphization time, unfortunately.
|
||||
// build-fail
|
||||
//~^^ ERROR cycle detected when computing layout of
|
||||
|
||||
fn main() {
|
||||
let _ = async {
|
||||
@ -31,6 +32,7 @@ where
|
||||
C: First,
|
||||
{
|
||||
async fn second(self) {
|
||||
//~^ ERROR recursion in an async fn requires boxing
|
||||
self.first().await.second().await;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
error[E0391]: cycle detected when computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`
|
||||
error[E0733]: recursion in an async fn requires boxing
|
||||
--> $DIR/indirect-recursion-issue-112047.rs:34:5
|
||||
|
|
||||
= note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`...
|
||||
= note: ...which requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`...
|
||||
= note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<<<A as First>::Second as Second>::{opaque#0}>`...
|
||||
= note: ...which again requires computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`, completing the cycle
|
||||
= note: cycle used when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:6:13: 8:6}`
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
LL | async fn second(self) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
For more information about this error, try `rustc --explain E0733`.
|
||||
|
@ -14,7 +14,6 @@ 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
|
||||
|
||||
|
@ -8,7 +8,6 @@ LL | recursive_async_function().await;
|
||||
| -------------------------------- recursive call here
|
||||
|
|
||||
= 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
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
error[E0733]: recursion in a coroutine requires boxing
|
||||
--> $DIR/recursive-coroutine-indirect.rs:6:5
|
||||
|
|
||||
LL | move || {
|
||||
| ^^^^^^^
|
||||
LL | let x = coroutine_hold();
|
||||
| - recursive call here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0733`.
|
11
tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr
Normal file
11
tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0733]: recursion in a coroutine requires boxing
|
||||
--> $DIR/recursive-coroutine-indirect.rs:6:5
|
||||
|
|
||||
LL | move || {
|
||||
| ^^^^^^^
|
||||
LL | let x = coroutine_hold();
|
||||
| - recursive call here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0733`.
|
13
tests/ui/impl-trait/recursive-coroutine-indirect.rs
Normal file
13
tests/ui/impl-trait/recursive-coroutine-indirect.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// revisions: current next
|
||||
//[next] compile-flags: -Znext-solver
|
||||
#![feature(coroutines)]
|
||||
#![allow(unconditional_recursion)]
|
||||
fn coroutine_hold() -> impl Sized {
|
||||
move || { //~ ERROR recursion in a coroutine requires boxing
|
||||
let x = coroutine_hold();
|
||||
yield;
|
||||
x;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,6 +1,5 @@
|
||||
// Test that impl trait does not allow creating recursive types that are
|
||||
// otherwise forbidden.
|
||||
|
||||
#![feature(coroutines)]
|
||||
#![allow(unconditional_recursion)]
|
||||
|
||||
@ -69,15 +68,6 @@ fn substs_change<T: 'static>() -> impl Sized {
|
||||
(substs_change::<&T>(),)
|
||||
}
|
||||
|
||||
fn coroutine_hold() -> impl Sized {
|
||||
move || {
|
||||
//~^ ERROR
|
||||
let x = coroutine_hold();
|
||||
yield;
|
||||
x;
|
||||
}
|
||||
}
|
||||
|
||||
fn use_fn_ptr() -> impl Sized {
|
||||
// OK, error already reported
|
||||
fn_ptr()
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:7:22
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:6:22
|
||||
|
|
||||
LL | fn option(i: i32) -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -10,7 +10,7 @@ LL | if i < 0 { None } else { Some((option(i - 1), i)) }
|
||||
| returning here with type `Option<(impl Sized, i32)>`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:12:15
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:11:15
|
||||
|
|
||||
LL | fn tuple() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -19,7 +19,7 @@ LL | (tuple(),)
|
||||
| ---------- returning here with type `(impl Sized,)`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:17:15
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:16:15
|
||||
|
|
||||
LL | fn array() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -28,7 +28,7 @@ LL | [array()]
|
||||
| --------- returning here with type `[impl Sized; 1]`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:22:13
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:21:13
|
||||
|
|
||||
LL | fn ptr() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -37,7 +37,7 @@ LL | &ptr() as *const _
|
||||
| ------------------ returning here with type `*const impl Sized`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:27:16
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:26:16
|
||||
|
|
||||
LL | fn fn_ptr() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -46,7 +46,7 @@ LL | fn_ptr as fn() -> _
|
||||
| ------------------- returning here with type `fn() -> impl Sized`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:32:25
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:31:25
|
||||
|
|
||||
LL | fn closure_capture() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -55,10 +55,10 @@ LL | / move || {
|
||||
LL | | x;
|
||||
| | - closure captures itself here
|
||||
LL | | }
|
||||
| |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12}`
|
||||
| |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:34:5: 34:12}`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:40:29
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:39:29
|
||||
|
|
||||
LL | fn closure_ref_capture() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -67,28 +67,28 @@ LL | / move || {
|
||||
LL | | &x;
|
||||
| | - closure captures itself here
|
||||
LL | | }
|
||||
| |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12}`
|
||||
| |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:42:5: 42:12}`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:48:21
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:47:21
|
||||
|
|
||||
LL | fn closure_sig() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
LL |
|
||||
LL | || closure_sig()
|
||||
| ---------------- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:7}`
|
||||
| ---------------- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:49:5: 49:7}`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:53:23
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:52:23
|
||||
|
|
||||
LL | fn coroutine_sig() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
LL |
|
||||
LL | || coroutine_sig()
|
||||
| ------------------ returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:7}`
|
||||
| ------------------ returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7}`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:58:27
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:57:27
|
||||
|
|
||||
LL | fn coroutine_capture() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -98,10 +98,10 @@ LL | | yield;
|
||||
LL | | x;
|
||||
| | - coroutine captures itself here
|
||||
LL | | }
|
||||
| |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12}`
|
||||
| |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:60:5: 60:12}`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:67:35
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:66:35
|
||||
|
|
||||
LL | fn substs_change<T: 'static>() -> impl Sized {
|
||||
| ^^^^^^^^^^ recursive opaque type
|
||||
@ -109,17 +109,8 @@ LL |
|
||||
LL | (substs_change::<&T>(),)
|
||||
| ------------------------ returning here with type `(impl Sized,)`
|
||||
|
||||
error[E0733]: recursion in a coroutine requires boxing
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:73:5
|
||||
|
|
||||
LL | move || {
|
||||
| ^^^^^^^
|
||||
LL |
|
||||
LL | let x = coroutine_hold();
|
||||
| - recursive call here
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:86:26
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:76:26
|
||||
|
|
||||
LL | fn mutual_recursion() -> impl Sync {
|
||||
| ^^^^^^^^^ recursive opaque type
|
||||
@ -131,7 +122,7 @@ LL | fn mutual_recursion_b() -> impl Sized {
|
||||
| ---------- returning this opaque type `impl Sized`
|
||||
|
||||
error[E0720]: cannot resolve opaque type
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:91:28
|
||||
--> $DIR/recursive-impl-trait-type-indirect.rs:81:28
|
||||
|
|
||||
LL | fn mutual_recursion() -> impl Sync {
|
||||
| --------- returning this opaque type `impl Sync`
|
||||
@ -142,7 +133,6 @@ LL |
|
||||
LL | mutual_recursion()
|
||||
| ------------------ returning here with type `impl Sync`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0720, E0733.
|
||||
For more information about an error, try `rustc --explain E0720`.
|
||||
For more information about this error, try `rustc --explain E0720`.
|
||||
|
@ -14,7 +14,6 @@ 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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user