From 82a22154815b70e5701064bef59d3334f5bc1cf7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 8 Nov 2023 06:56:06 +0000 Subject: [PATCH] Don't check for recursion in generator witness fields --- .../src/error_codes/E0733.md | 16 ++++++++- compiler/rustc_hir/src/hir.rs | 6 ++++ .../rustc_hir_analysis/src/check/check.rs | 25 ++++--------- compiler/rustc_middle/src/query/keys.rs | 13 ++++--- compiler/rustc_middle/src/query/mod.rs | 2 ++ compiler/rustc_middle/src/ty/util.rs | 13 +------ compiler/rustc_middle/src/values.rs | 36 ++++++++++++++++--- compiler/rustc_query_impl/src/plumbing.rs | 4 +-- compiler/rustc_query_system/src/query/mod.rs | 7 ++-- .../src/traits/query/normalize.rs | 13 +++---- ...utually-recursive-async-impl-trait-type.rs | 2 +- ...lly-recursive-async-impl-trait-type.stderr | 11 +----- .../recursive-coroutine.current.stderr | 12 ------- .../recursive-coroutine.next.stderr | 12 ------- tests/ui/impl-trait/recursive-coroutine.rs | 5 +-- .../recursive-impl-trait-type-indirect.rs | 2 +- .../recursive-impl-trait-type-indirect.stderr | 17 ++++----- .../indirect-recursion-issue-112047.rs | 3 +- .../indirect-recursion-issue-112047.stderr | 27 ++++---------- 19 files changed, 102 insertions(+), 124 deletions(-) delete mode 100644 tests/ui/impl-trait/recursive-coroutine.current.stderr delete mode 100644 tests/ui/impl-trait/recursive-coroutine.next.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0733.md b/compiler/rustc_error_codes/src/error_codes/E0733.md index 051b75148e5..cceb0880350 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0733.md +++ b/compiler/rustc_error_codes/src/error_codes/E0733.md @@ -13,7 +13,7 @@ async fn foo(n: usize) { To perform async recursion, the `async fn` needs to be desugared such that the `Future` is explicit in the return type: -```edition2018,compile_fail,E0720 +```edition2018,compile_fail,E0733 use std::future::Future; fn foo_desugared(n: usize) -> impl Future { async move { @@ -41,4 +41,18 @@ fn foo_recursive(n: usize) -> Pin>> { The `Box<...>` ensures that the result is of known size, and the pin is required to keep it in the same place in memory. +Alternatively, the recursive call-site can be boxed: + +```edition2018 +use std::future::Future; +use std::pin::Pin; +fn foo_recursive(n: usize) -> impl Future { + async move { + if n > 0 { + Box::pin(foo_recursive(n - 1)).await; + } + } +} +``` + [`async`]: https://doc.rust-lang.org/std/keyword.async.html diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e88b876534e..cadf54c76a3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1361,6 +1361,12 @@ impl CoroutineKind { } } +impl CoroutineKind { + pub fn is_fn_like(self) -> bool { + matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn)) + } +} + impl fmt::Display for CoroutineKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4b26a469eb5..12430b1465c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -213,13 +213,12 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - let args = GenericArgs::identity_for_item(tcx, item.owner_id); let span = tcx.def_span(item.owner_id.def_id); if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() { return; } - if check_opaque_for_cycles(tcx, item.owner_id.def_id, args, span, origin).is_err() { + if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() { return; } @@ -230,16 +229,16 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(super) fn check_opaque_for_cycles<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, - args: GenericArgsRef<'tcx>, span: Span, - origin: &hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { + let args = GenericArgs::identity_for_item(tcx, def_id); if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() { - let reported = match origin { - hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span), - _ => opaque_type_cycle_error(tcx, def_id, span), - }; + let reported = opaque_type_cycle_error(tcx, def_id, span); Err(reported) + } else if let Err(&LayoutError::Cycle(guar)) = + tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args))) + { + Err(guar) } else { Ok(()) } @@ -1300,16 +1299,6 @@ pub(super) fn check_type_params_are_used<'tcx>( } } -fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed { - struct_span_err!(tcx.dcx(), span, E0733, "recursion in an `async fn` requires boxing") - .span_label_mv(span, "recursive `async fn`") - .note_mv("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") - .note_mv( - "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion", - ) - .emit() -} - /// Emit an error for recursive opaque types. /// /// If this is a return `impl Trait`, find the item's return expressions and point at them. For diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 11376345052..945f17d5df2 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -40,7 +40,7 @@ pub trait Key: Sized { None } - fn ty_adt_id(&self) -> Option { + fn ty_def_id(&self) -> Option { None } } @@ -406,9 +406,10 @@ impl<'tcx> Key for Ty<'tcx> { DUMMY_SP } - fn ty_adt_id(&self) -> Option { - match self.kind() { + fn ty_def_id(&self) -> Option { + match *self.kind() { ty::Adt(adt, _) => Some(adt.did()), + ty::Coroutine(def_id, ..) => Some(def_id), _ => None, } } @@ -452,6 +453,10 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) } + + fn ty_def_id(&self) -> Option { + self.value.ty_def_id() + } } impl Key for Symbol { @@ -550,7 +555,7 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { DUMMY_SP } - fn ty_adt_id(&self) -> Option { + fn ty_def_id(&self) -> Option { match self.1.value.kind() { ty::Adt(adt, _) => Some(adt.did()), _ => None, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7d5abaceb20..0e3b9984423 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1387,6 +1387,8 @@ rustc_queries! { ) -> Result, &'tcx ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } + // we emit our own error during query cycle handling + cycle_delay_bug } /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b9c75bd205b..74dba41647b 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -896,18 +896,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { } let args = args.fold_with(self); if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { - let expanded_ty = match self.expanded_cache.get(&(def_id, args)) { - Some(expanded_ty) => *expanded_ty, - None => { - for bty in self.tcx.coroutine_hidden_types(def_id) { - let hidden_ty = bty.instantiate(self.tcx, args); - self.fold_ty(hidden_ty); - } - let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args); - self.expanded_cache.insert((def_id, args), expanded_ty); - expanded_ty - } - }; + let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args); if self.check_recursion { self.seen_opaque_tys.remove(&def_id); } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 4ee97dac444..0179829cc46 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::Representability; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_query_system::query::CycleError; +use rustc_query_system::query::{report_cycle, CycleError}; use rustc_query_system::Value; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span}; @@ -97,7 +97,7 @@ impl<'tcx> Value> for Representability { } for info in &cycle_error.cycle { if info.query.dep_kind == dep_kinds::representability_adt_ty - && let Some(def_id) = info.query.ty_adt_id + && let Some(def_id) = info.query.ty_def_id && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) { @@ -131,10 +131,36 @@ impl<'tcx> Value> for ty::EarlyBinder> impl<'tcx, T> Value> for Result> { fn from_cycle_error( - _tcx: TyCtxt<'tcx>, - _cycle_error: &CycleError, - guar: ErrorGuaranteed, + tcx: TyCtxt<'tcx>, + 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() + && matches!(tcx.def_kind(def_id), 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) + }; + 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( + "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion", + ) + .emit() + } else { + report_cycle(tcx.sess, cycle_error).emit() + }; + // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // tcx.arena.alloc is pretty much equal to leaking). diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f131a0f7593..7e0fbf3d76c 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -342,9 +342,9 @@ pub(crate) fn create_query_frame< hasher.finish::() }) }; - let ty_adt_id = key.ty_adt_id(); + let ty_def_id = key.ty_def_id(); - QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_adt_id, hash) + QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_def_id, hash) } pub(crate) fn encode_query_results<'a, 'tcx, Q>( diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index ce6a6d6cb1b..9ff04c4e910 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -35,7 +35,8 @@ pub struct QueryStackFrame { span: Option, pub def_id: Option, pub def_kind: Option, - pub ty_adt_id: Option, + /// A def-id that is extracted from a `Ty` in a query key + pub ty_def_id: Option, pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. @@ -51,7 +52,7 @@ impl QueryStackFrame { def_id: Option, def_kind: Option, dep_kind: DepKind, - ty_adt_id: Option, + ty_def_id: Option, _hash: impl FnOnce() -> Hash64, ) -> Self { Self { @@ -59,7 +60,7 @@ impl QueryStackFrame { span, def_id, def_kind, - ty_adt_id, + ty_def_id, dep_kind, #[cfg(parallel_compiler)] hash: _hash(), diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index e8867187a40..425c4fbe9c5 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -239,16 +239,13 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> } let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.instantiate(self.interner(), args); + let mut concrete_ty = generic_ty.instantiate(self.interner(), args); self.anon_depth += 1; if concrete_ty == ty { - bug!( - "infinite recursion generic_ty: {:#?}, args: {:#?}, \ - concrete_ty: {:#?}, ty: {:#?}", - generic_ty, - args, - concrete_ty, - ty + concrete_ty = Ty::new_error_with_message( + self.interner(), + DUMMY_SP, + "recursive opaque type", ); } let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty)); 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 bb2a61f03ce..d38ba1a569b 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 @@ -6,7 +6,7 @@ async fn rec_1() { //~ ERROR recursion in an `async fn` rec_2().await; } -async fn rec_2() { //~ ERROR recursion in an `async fn` +async fn rec_2() { rec_1().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 9442609e805..dd53075be60 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 @@ -7,15 +7,6 @@ LL | async fn rec_1() { = 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 -error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:1 - | -LL | async fn rec_2() { - | ^^^^^^^^^^^^^^^^ 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 - -error: aborting due to 2 previous errors +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.current.stderr b/tests/ui/impl-trait/recursive-coroutine.current.stderr deleted file mode 100644 index e838634ed08..00000000000 --- a/tests/ui/impl-trait/recursive-coroutine.current.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0720]: cannot resolve opaque type - --> $DIR/recursive-coroutine.rs:7:13 - | -LL | fn foo() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type -... -LL | let mut gen = Box::pin(foo()); - | ------- coroutine captures itself here - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-coroutine.next.stderr b/tests/ui/impl-trait/recursive-coroutine.next.stderr deleted file mode 100644 index e838634ed08..00000000000 --- a/tests/ui/impl-trait/recursive-coroutine.next.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0720]: cannot resolve opaque type - --> $DIR/recursive-coroutine.rs:7:13 - | -LL | fn foo() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type -... -LL | let mut gen = Box::pin(foo()); - | ------- coroutine captures itself here - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-coroutine.rs b/tests/ui/impl-trait/recursive-coroutine.rs index b82fe134a40..b9291f07e21 100644 --- a/tests/ui/impl-trait/recursive-coroutine.rs +++ b/tests/ui/impl-trait/recursive-coroutine.rs @@ -1,3 +1,4 @@ +// check-pass // revisions: current next //[next] compile-flags: -Znext-solver #![feature(coroutines, coroutine_trait)] @@ -5,12 +6,8 @@ use std::ops::{Coroutine, CoroutineState}; fn foo() -> impl Coroutine { - //~^ ERROR cannot resolve opaque type - //~| NOTE recursive opaque type - //~| NOTE in this expansion of desugaring of || { let mut gen = Box::pin(foo()); - //~^ NOTE coroutine captures itself here let mut r = gen.as_mut().resume(()); while let CoroutineState::Yielded(v) = r { yield v; 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 8331eec906e..a6bca107b1e 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -70,8 +70,8 @@ fn substs_change() -> impl Sized { } fn coroutine_hold() -> impl Sized { - //~^ ERROR move || { + //~^ ERROR let x = coroutine_hold(); yield; x; 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 8e9aa8ad0a6..0dabba26468 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[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:72:24 +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/recursive-impl-trait-type-indirect.rs:73:5 | -LL | fn coroutine_hold() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -... -LL | let x = coroutine_hold(); - | - coroutine captures itself here +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 error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 @@ -144,4 +144,5 @@ LL | mutual_recursion() error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0720`. +Some errors have detailed explanations: E0720, E0733. +For more information about an error, try `rustc --explain E0720`. 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 6a2ee761e19..3637f416c7b 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 @@ -1,5 +1,4 @@ // edition: 2021 -// build-fail #![feature(impl_trait_in_assoc_type)] @@ -20,7 +19,7 @@ impl Recur for () { fn recur(self) -> Self::Recur { async move { recur(self).await; } - //~^ ERROR cycle detected when computing layout of + //~^ ERROR recursion in an `async fn` 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 11d9cd0af08..aa352b326c6 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,27 +1,12 @@ -error[E0391]: cycle detected when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}` - --> $DIR/indirect-recursion-issue-112047.rs:22:22 +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/indirect-recursion-issue-112047.rs:21:9 | LL | async move { recur(self).await; } - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` | - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:14:31: 16:2}>`... - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop<{async fn body@$DIR/indirect-recursion-issue-112047.rs:14:31: 16:2}>`... -note: ...which requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:14:31: 16:2}`... - --> $DIR/indirect-recursion-issue-112047.rs:15:5 - | -LL | t.recur().await; - | ^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<<() as Recur>::Recur>`... - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}>`... - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop<{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}>`... - = note: ...which again requires computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}`, completing the cycle -note: cycle used when elaborating drops for `::recur` - --> $DIR/indirect-recursion-issue-112047.rs:21:5 - | -LL | fn recur(self) -> Self::Recur { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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 + = 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 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`.