diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 3e3aa821b4e..77e4ed06eaa 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -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> for Ty<'_> { @@ -135,73 +136,79 @@ impl<'tcx, T> Value> for Result> 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() }; 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 37de274565d..d085747bc4b 100644 --- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr +++ b/tests/ui/async-await/in-trait/async-recursive-generic.stderr @@ -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 diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.stderr index 6b99c516c3b..25ebc6e77c4 100644 --- a/tests/ui/async-await/in-trait/async-recursive.stderr +++ b/tests/ui/async-await/in-trait/async-recursive.stderr @@ -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 diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs index 8443cbcf4ac..4b615343a05 100644 --- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs +++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs @@ -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; } } diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr index 8e573b512ad..8126c6e1394 100644 --- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr +++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr @@ -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<<::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`. 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 3f2ee4150da..52fb41be1fb 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 @@ -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 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 cec92c54f01..5475469335f 100644 --- a/tests/ui/async-await/recursive-async-impl-trait-type.stderr +++ b/tests/ui/async-await/recursive-async-impl-trait-type.stderr @@ -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 diff --git a/tests/ui/impl-trait/recursive-coroutine.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs similarity index 100% rename from tests/ui/impl-trait/recursive-coroutine.rs rename to tests/ui/impl-trait/recursive-coroutine-boxed.rs diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr new file mode 100644 index 00000000000..11b3c4ef007 --- /dev/null +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr @@ -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`. diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr new file mode 100644 index 00000000000..11b3c4ef007 --- /dev/null +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr @@ -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`. diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.rs b/tests/ui/impl-trait/recursive-coroutine-indirect.rs new file mode 100644 index 00000000000..4f8d4d33050 --- /dev/null +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.rs @@ -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() {} diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs index a6bca107b1e..432f80a1763 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -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() -> 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() 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 16a9012958e..d5b8c531fd6 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -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() -> 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`. 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 2e75f676971..b62186103c7 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 @@ -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