Auto merge of #117703 - compiler-errors:recursive-async, r=lcnr

Support async recursive calls (as long as they have indirection)

Before #101692, we stored coroutine witness types directly inside of the coroutine. That means that a coroutine could not contain itself (as a witness field) without creating a cycle in the type representation of the coroutine, which we detected with the `OpaqueTypeExpander`, which is used to detect cycles when expanding opaque types after that are inferred to contain themselves.

After `-Zdrop-tracking-mir` was stabilized, we no longer store these generator witness fields directly, but instead behind a def-id based query. That means there is no technical obstacle in the compiler preventing coroutines from containing themselves per se, other than the fact that for a coroutine to have a non-infinite layout, it must contain itself wrapped in a layer of allocation indirection (like a `Box`).

This means that it should be valid for this code to work:

```
async fn async_fibonacci(i: u32) -> u32 {
    if i == 0 || i == 1 {
        i
    } else {
        Box::pin(async_fibonacci(i - 1)).await
          + Box::pin(async_fibonacci(i - 2)).await
    }
}
```

Whereas previously, you'd need to coerce the future to `Pin<Box<dyn Future<Output = ...>>` before `await`ing it, to prevent the async's desugared coroutine from containing itself across as await point.

This PR does two things:
1. Only report an error if an opaque expansion cycle is detected *not* through coroutine witness fields.
    * Instead, if we find an opaque cycle through coroutine witness fields, we compute the layout of the coroutine. If that results in a cycle error, we report it as a recursive async fn.
4. Reworks the way we report layout errors having to do with coroutines, to make up for the diagnostic regressions introduced by (1.). We actually do even better now, pointing out the call sites of the recursion!
This commit is contained in:
bors 2024-01-09 07:20:50 +00:00
commit dc641039d2
43 changed files with 402 additions and 251 deletions

View File

@ -10,35 +10,31 @@ 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
use std::future::Future;
fn foo_desugared(n: usize) -> impl Future<Output = ()> {
async move {
if n > 0 {
foo_desugared(n - 1).await;
}
}
}
```
Finally, the future is wrapped in a pinned box:
The recursive invocation can be boxed:
```edition2018
use std::future::Future;
use std::pin::Pin;
fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
Box::pin(async move {
if n > 0 {
foo_recursive(n - 1).await;
}
})
async fn foo(n: usize) {
if n > 0 {
Box::pin(foo(n - 1)).await;
}
}
```
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 body can be boxed:
```edition2018
use std::future::Future;
use std::pin::Pin;
fn foo(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
Box::pin(async move {
if n > 0 {
foo(n - 1).await;
}
})
}
```
[`async`]: https://doc.rust-lang.org/std/keyword.async.html

View File

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

View File

@ -17,7 +17,7 @@ use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{
AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@ -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,19 +229,36 @@ 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> {
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),
};
Err(reported)
} else {
Ok(())
let args = GenericArgs::identity_for_item(tcx, def_id);
// First, try to look at any opaque expansion cycles, considering coroutine fields
// (even though these aren't necessarily true errors).
if tcx
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::Yes)
.is_err()
{
// Look for true opaque expansion cycles, but ignore coroutines.
// This will give us any true errors. Coroutines are only problematic
// if they cause layout computation errors.
if tcx
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
.is_err()
{
let reported = opaque_type_cycle_error(tcx, def_id, span);
return Err(reported);
}
// And also look for cycle errors in the layout of coroutines.
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)))
{
return Err(guar);
}
}
Ok(())
}
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
@ -1300,16 +1316,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

View File

@ -40,7 +40,7 @@ pub trait Key: Sized {
None
}
fn ty_adt_id(&self) -> Option<DefId> {
fn ty_def_id(&self) -> Option<DefId> {
None
}
}
@ -406,9 +406,10 @@ impl<'tcx> Key for Ty<'tcx> {
DUMMY_SP
}
fn ty_adt_id(&self) -> Option<DefId> {
match self.kind() {
fn ty_def_id(&self) -> Option<DefId> {
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<DefId> {
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<DefId> {
fn ty_def_id(&self) -> Option<DefId> {
match self.1.value.kind() {
ty::Adt(adt, _) => Some(adt.did()),
_ => None,

View File

@ -1387,6 +1387,8 @@ rustc_queries! {
) -> Result<ty::layout::TyAndLayout<'tcx>, &'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.

View File

@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
pub hash_result: HashResult<C::Value>,
pub value_from_cycle_error:
fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value,
fn(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) -> C::Value,
pub format_value: fn(&C::Value) -> String,
}

View File

@ -702,6 +702,7 @@ impl<'tcx> TyCtxt<'tcx> {
self,
def_id: DefId,
args: GenericArgsRef<'tcx>,
inspect_coroutine_fields: InspectCoroutineFields,
) -> Result<Ty<'tcx>, Ty<'tcx>> {
let mut visitor = OpaqueTypeExpander {
seen_opaque_tys: FxHashSet::default(),
@ -712,6 +713,7 @@ impl<'tcx> TyCtxt<'tcx> {
check_recursion: true,
expand_coroutines: true,
tcx: self,
inspect_coroutine_fields,
};
let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap();
@ -729,16 +731,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),
@ -865,6 +894,13 @@ struct OpaqueTypeExpander<'tcx> {
/// recursion, and 'false' otherwise to avoid unnecessary work.
check_recursion: bool,
tcx: TyCtxt<'tcx>,
inspect_coroutine_fields: InspectCoroutineFields,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum InspectCoroutineFields {
No,
Yes,
}
impl<'tcx> OpaqueTypeExpander<'tcx> {
@ -906,9 +942,11 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
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);
if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
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);
@ -1486,6 +1524,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
check_recursion: false,
expand_coroutines: false,
tcx,
inspect_coroutine_fields: InspectCoroutineFields::No,
};
val.fold_with(&mut visitor)
}

View File

@ -6,15 +6,17 @@ 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::QueryInfo;
use rustc_query_system::query::{report_cycle, CycleError};
use rustc_query_system::Value;
use rustc_span::def_id::LocalDefId;
use rustc_span::{ErrorGuaranteed, Span};
use std::collections::VecDeque;
use std::fmt::Write;
use std::ops::ControlFlow;
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
@ -22,13 +24,13 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
}
impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
Err(CyclePlaceholder(guar))
}
}
impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, _guar: ErrorGuaranteed) -> Self {
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe {
@ -40,10 +42,14 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
}
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle_error: &CycleError,
guar: ErrorGuaranteed,
) -> Self {
let err = Ty::new_error(tcx, guar);
let arity = if let Some(frame) = stack.get(0)
let arity = if let Some(frame) = cycle_error.cycle.get(0)
&& frame.query.dep_kind == dep_kinds::fn_sig
&& let Some(def_id) = frame.query.def_id
&& let Some(node) = tcx.hir().get_if_local(def_id)
@ -70,10 +76,14 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
}
impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle_error: &CycleError,
_guar: ErrorGuaranteed,
) -> Self {
let mut item_and_field_ids = Vec::new();
let mut representable_ids = FxHashSet::default();
for info in cycle {
for info in &cycle_error.cycle {
if info.query.dep_kind == dep_kinds::representability
&& let Some(field_id) = info.query.def_id
&& let Some(field_id) = field_id.as_local()
@ -87,9 +97,9 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
item_and_field_ids.push((item_id.expect_local(), field_id));
}
}
for info in cycle {
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)
{
@ -102,19 +112,128 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
}
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar))
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle_error: &CycleError,
guar: ErrorGuaranteed,
) -> Self {
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle_error, guar))
}
}
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar))
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle_error: &CycleError,
guar: ErrorGuaranteed,
) -> Self {
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle_error, guar))
}
}
// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`.
fn search_for_cycle_permutation<Q, T>(
cycle: &[Q],
try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow<T, ()>,
otherwise: impl FnOnce() -> T,
) -> T {
let mut cycle: VecDeque<_> = cycle.iter().collect();
for _ in 0..cycle.len() {
match try_cycle(&mut cycle) {
ControlFlow::Continue(_) => {
cycle.rotate_left(1);
}
ControlFlow::Break(t) => return t,
}
}
otherwise()
}
impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle_error: &CycleError,
_guar: ErrorGuaranteed,
) -> Self {
let diag = search_for_cycle_permutation(
&cycle_error.cycle,
|cycle| {
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(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");
}
ControlFlow::Break(diag)
} else {
ControlFlow::Continue(())
}
},
|| report_cycle(tcx.sess, cycle_error),
);
let guar = diag.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).

View File

@ -35,7 +35,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
get_query_incr, get_query_non_incr, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap,
get_query_incr, get_query_non_incr, CycleError, HashResult, QueryCache, QueryConfig, QueryMap,
QueryMode, QueryState,
};
use rustc_query_system::HandleCycleError;
@ -144,10 +144,10 @@ where
fn value_from_cycle_error(
self,
tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo],
cycle_error: &CycleError,
guar: ErrorGuaranteed,
) -> Self::Value {
(self.dynamic.value_from_cycle_error)(tcx, cycle, guar)
(self.dynamic.value_from_cycle_error)(tcx, cycle_error, guar)
}
#[inline(always)]

View File

@ -342,9 +342,9 @@ pub(crate) fn create_query_frame<
hasher.finish::<Hash64>()
})
};
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>(

View File

@ -5,7 +5,7 @@ use crate::error::HandleCycleError;
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
use crate::query::DepNodeIndex;
use crate::query::{QueryContext, QueryInfo, QueryState};
use crate::query::{CycleError, QueryContext, QueryState};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_span::ErrorGuaranteed;
@ -57,7 +57,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
fn value_from_cycle_error(
self,
tcx: Qcx::DepContext,
cycle: &[QueryInfo],
cycle_error: &CycleError,
guar: ErrorGuaranteed,
) -> Self::Value;

View File

@ -556,7 +556,7 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
#[inline(never)]
#[cold]
pub(crate) fn report_cycle<'a>(
pub fn report_cycle<'a>(
sess: &'a Session,
CycleError { usage, cycle: stack }: &CycleError,
) -> DiagnosticBuilder<'a> {

View File

@ -4,7 +4,9 @@ pub use self::plumbing::*;
mod job;
#[cfg(parallel_compiler)]
pub use self::job::deadlock;
pub use self::job::{print_query_stack, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap};
pub use self::job::{
print_query_stack, report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap,
};
mod caches;
pub use self::caches::{
@ -33,7 +35,8 @@ pub struct QueryStackFrame {
span: Option<Span>,
pub def_id: Option<DefId>,
pub def_kind: Option<DefKind>,
pub ty_adt_id: Option<DefId>,
/// A def-id that is extracted from a `Ty` in a query key
pub ty_def_id: Option<DefId>,
pub dep_kind: DepKind,
/// This hash is used to deterministically pick
/// a query to remove cycles in the parallel compiler.
@ -49,7 +52,7 @@ impl QueryStackFrame {
def_id: Option<DefId>,
def_kind: Option<DefKind>,
dep_kind: DepKind,
ty_adt_id: Option<DefId>,
ty_def_id: Option<DefId>,
_hash: impl FnOnce() -> Hash64,
) -> Self {
Self {
@ -57,7 +60,7 @@ impl QueryStackFrame {
span,
def_id,
def_kind,
ty_adt_id,
ty_def_id,
dep_kind,
#[cfg(parallel_compiler)]
hash: _hash(),

View File

@ -134,7 +134,7 @@ where
match query.handle_cycle_error() {
Error => {
let guar = error.emit();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar)
}
Fatal => {
error.emit();
@ -143,7 +143,7 @@ where
}
DelayBug => {
let guar = error.delay_as_bug();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar)
}
Stash => {
let guar = if let Some(root) = cycle_error.cycle.first()
@ -154,7 +154,7 @@ where
} else {
error.emit()
};
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar)
}
}
}
@ -211,7 +211,7 @@ where
}
#[derive(Clone, Debug)]
pub(crate) struct CycleError {
pub struct CycleError {
/// The query and related span that uses the cycle.
pub usage: Option<(Span, QueryStackFrame)>,
pub cycle: Vec<QueryInfo>,

View File

@ -1,20 +1,21 @@
use rustc_span::ErrorGuaranteed;
use crate::dep_graph::DepContext;
use crate::query::QueryInfo;
use crate::query::CycleError;
pub trait Value<Tcx: DepContext>: Sized {
fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self;
fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, guar: ErrorGuaranteed) -> Self;
}
impl<Tcx: DepContext, T> Value<Tcx> for T {
default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> T {
default fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed) -> T {
tcx.sess().dcx().abort_if_errors();
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
// non-trivial to define it earlier.
panic!(
"<{} as Value>::from_cycle_error called without errors: {cycle:#?}",
std::any::type_name::<T>()
"<{} as Value>::from_cycle_error called without errors: {:#?}",
std::any::type_name::<T>(),
cycle_error.cycle,
);
}
}

View File

@ -239,16 +239,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> 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));

View File

@ -4,7 +4,6 @@ use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::DefId;
use rustc_index::IndexVec;
use rustc_middle::query::Key;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
@ -1259,7 +1258,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c
clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => {
let variants_iter = || variants.iter().filter(|i| !i.is_stripped());
let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
let enum_def_id = ty.ty_adt_id().unwrap();
let enum_def_id = ty.ty_adt_def().unwrap().did();
wrap_item(w, |w| {
let variants_len = variants.len();

View File

@ -12,7 +12,6 @@ use rustc_errors::Applicability;
use rustc_hir::def_id::DefIdSet;
use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::query::Key;
use rustc_session::impl_lint_pass;
use rustc_span::hygiene::walk_chain;
use rustc_span::source_map::SourceMap;
@ -574,7 +573,7 @@ fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignore
let caller_ty = cx.typeck_results().expr_ty(caller_expr);
// Check if given type has inner mutability and was not set to ignored by the configuration
let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty)
&& !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id));
&& !matches!(caller_ty.ty_adt_def(), Some(adt) if ignored_ty_ids.contains(&adt.did()));
is_inner_mut_ty
|| caller_ty.is_mutable_ptr()

View File

@ -6,7 +6,6 @@ use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::query::Key;
use rustc_middle::ty;
use rustc_middle::ty::Ty;
use rustc_span::{sym, Symbol};
@ -18,10 +17,10 @@ use rustc_span::{sym, Symbol};
/// `vec![1,2].drain(..).collect::<HashSet<_>>()`
/// ^^^^^^^^^ ^^^^^^^^^^ false
fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool {
if let Some(expr_adt_did) = expr.ty_adt_id()
&& let Some(recv_adt_did) = recv.ty_adt_id()
if let Some(expr_adt) = expr.ty_adt_def()
&& let Some(recv_adt) = recv.ty_adt_def()
{
cx.tcx.is_diagnostic_item(sym, expr_adt_did) && cx.tcx.is_diagnostic_item(sym, recv_adt_did)
cx.tcx.is_diagnostic_item(sym, expr_adt.did()) && cx.tcx.is_diagnostic_item(sym, recv_adt.did())
} else {
false
}

View File

@ -4,7 +4,6 @@ use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::query::Key;
use rustc_span::Span;
pub(super) fn check(
@ -14,11 +13,7 @@ pub(super) fn check(
as_str_span: Span,
other_method_span: Span,
) {
if cx
.tcx
.lang_items()
.string()
.is_some_and(|id| Some(id) == cx.typeck_results().expr_ty(recv).ty_adt_id())
if cx.typeck_results().expr_ty(recv).ty_adt_def().is_some_and(|adt| Some(adt.did()) == cx.tcx.lang_items().string())
{
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(

View File

@ -4,7 +4,6 @@ use clippy_utils::{def_path_def_ids, trait_ref_of_method};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::query::Key;
use rustc_middle::ty::{Adt, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
@ -166,7 +165,7 @@ impl MutableKeyType {
// Determines if a type contains interior mutability which would affect its implementation of
// [`Hash`] or [`Ord`].
if is_interior_mut_ty(cx, subst_ty)
&& !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
&& !matches!(subst_ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did()))
{
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
}

View File

@ -15,7 +15,6 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
use rustc_middle::query::Key;
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::impl_lint_pass;
@ -188,7 +187,7 @@ impl NonCopyConst {
}
fn is_ty_ignored(&self, ty: Ty<'_>) -> bool {
matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
matches!(ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did()))
}
fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {

View File

@ -4,7 +4,6 @@ use clippy_utils::sugg;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::query::Key;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::sym;
@ -17,10 +16,10 @@ pub(super) fn check<'tcx>(
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
) -> bool {
let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else {
let (ty::Int(_) | ty::Uint(_), Some(to_ty_adt)) = (&from_ty.kind(), to_ty.ty_adt_def()) else {
return false;
};
let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else {
let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_adt.did()) else {
return false;
};

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,11 +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: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
= 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

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,11 +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: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
= 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

View File

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

View File

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

View File

@ -2,11 +2,11 @@
// 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;
}
async fn rec_2() { //~ ERROR recursion in an `async fn`
async fn rec_2() {
rec_1().await;
}

View File

@ -1,21 +1,20 @@
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: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
error[E0733]: recursion in an `async fn` requires boxing
note: which leads to this async fn
--> $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
| ^^^^^^^^^^^^^^^^
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
error: aborting due to 2 previous errors
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0733`.

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,11 +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: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
= 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

View File

@ -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<Yield = (), Return = ()> {
//~^ 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;

View 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`.

View 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`.

View 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() {}

View File

@ -1,12 +0,0 @@
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-coroutine.rs:7:13
|
LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.

View File

@ -1,12 +0,0 @@
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-coroutine.rs:7:13
|
LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.

View File

@ -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 {
//~^ ERROR
move || {
let x = coroutine_hold();
yield;
x;
}
}
fn use_fn_ptr() -> impl Sized {
// OK, error already reported
fn_ptr()

View File

@ -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
@ -110,16 +110,7 @@ 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
|
LL | fn coroutine_hold() -> impl Sized {
| ^^^^^^^^^^ recursive opaque type
...
LL | let x = coroutine_hold();
| - coroutine captures itself 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,6 +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
For more information about this error, try `rustc --explain E0720`.

View File

@ -20,7 +20,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 block requires boxing
}
}

View File

@ -1,27 +1,20 @@
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 block requires boxing
--> $DIR/indirect-recursion-issue-112047.rs:22:9
|
LL | async move { recur(self).await; }
| ^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^-----------------^^^
| |
| recursive call here
|
= 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
note: which leads to this async fn
--> $DIR/indirect-recursion-issue-112047.rs:14:1
|
LL | async fn recur(t: impl Recur) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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 `<impl at $DIR/indirect-recursion-issue-112047.rs:18:1: 18:18>::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
| --------------- ...leading to this recursive call
= 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`.