mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 08:53:35 +00:00
Don't check for recursion in generator witness fields
This commit is contained in:
parent
dfb9f5df2c
commit
82a2215481
@ -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<Output = ()> {
|
||||
async move {
|
||||
@ -41,4 +41,18 @@ fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
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<Output = ()> {
|
||||
async move {
|
||||
if n > 0 {
|
||||
Box::pin(foo_recursive(n - 1)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[`async`]: https://doc.rust-lang.org/std/keyword.async.html
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<TyCtxt<'tcx>> 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<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>
|
||||
|
||||
impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
|
||||
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).
|
||||
|
@ -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>(
|
||||
|
@ -35,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.
|
||||
@ -51,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 {
|
||||
@ -59,7 +60,7 @@ impl QueryStackFrame {
|
||||
span,
|
||||
def_id,
|
||||
def_kind,
|
||||
ty_adt_id,
|
||||
ty_def_id,
|
||||
dep_kind,
|
||||
#[cfg(parallel_compiler)]
|
||||
hash: _hash(),
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
@ -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`.
|
@ -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;
|
||||
|
@ -70,8 +70,8 @@ fn substs_change<T: 'static>() -> impl Sized {
|
||||
}
|
||||
|
||||
fn coroutine_hold() -> impl Sized {
|
||||
//~^ ERROR
|
||||
move || {
|
||||
//~^ ERROR
|
||||
let x = coroutine_hold();
|
||||
yield;
|
||||
x;
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 `<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
|
||||
= 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`.
|
||||
|
Loading…
Reference in New Issue
Block a user