Skip to content

Commit eda8200

Browse files
Don't check for recursion in generator witness fields
1 parent ac8cb64 commit eda8200

21 files changed

+123
-116
lines changed

compiler/rustc_hir/src/hir.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,12 @@ pub enum CoroutineKind {
15291529
Coroutine,
15301530
}
15311531

1532+
impl CoroutineKind {
1533+
pub fn is_fn_like(self) -> bool {
1534+
matches!(self, CoroutineKind::Async(CoroutineSource::Fn) | CoroutineKind::Gen(CoroutineSource::Fn))
1535+
}
1536+
}
1537+
15321538
impl fmt::Display for CoroutineKind {
15331539
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15341540
match self {

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,12 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
216216
return;
217217
}
218218

219-
let args = GenericArgs::identity_for_item(tcx, item.owner_id);
220219
let span = tcx.def_span(item.owner_id.def_id);
221220

222221
if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
223222
return;
224223
}
225-
if check_opaque_for_cycles(tcx, item.owner_id.def_id, args, span, &origin).is_err() {
224+
if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() {
226225
return;
227226
}
228227

@@ -233,16 +232,16 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
233232
pub(super) fn check_opaque_for_cycles<'tcx>(
234233
tcx: TyCtxt<'tcx>,
235234
def_id: LocalDefId,
236-
args: GenericArgsRef<'tcx>,
237235
span: Span,
238-
origin: &hir::OpaqueTyOrigin,
239236
) -> Result<(), ErrorGuaranteed> {
237+
let args = GenericArgs::identity_for_item(tcx, def_id);
240238
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
241-
let reported = match origin {
242-
hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span),
243-
_ => opaque_type_cycle_error(tcx, def_id, span),
244-
};
239+
let reported = opaque_type_cycle_error(tcx, def_id, span);
245240
Err(reported)
241+
} else if let Err(&LayoutError::Cycle(guar)) =
242+
tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args)))
243+
{
244+
Err(guar)
246245
} else {
247246
Ok(())
248247
}
@@ -1324,16 +1323,6 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId
13241323
}
13251324
}
13261325

1327-
fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed {
1328-
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
1329-
.span_label(span, "recursive `async fn`")
1330-
.note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
1331-
.note(
1332-
"consider using the `async_recursion` crate: https://crates.io/crates/async_recursion",
1333-
)
1334-
.emit()
1335-
}
1336-
13371326
/// Emit an error for recursive opaque types.
13381327
///
13391328
/// If this is a return `impl Trait`, find the item's return expressions and point at them. For

compiler/rustc_middle/src/query/keys.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub trait Key: Sized {
4040
None
4141
}
4242

43-
fn ty_adt_id(&self) -> Option<DefId> {
43+
fn ty_def_id(&self) -> Option<DefId> {
4444
None
4545
}
4646
}
@@ -406,9 +406,10 @@ impl<'tcx> Key for Ty<'tcx> {
406406
DUMMY_SP
407407
}
408408

409-
fn ty_adt_id(&self) -> Option<DefId> {
410-
match self.kind() {
409+
fn ty_def_id(&self) -> Option<DefId> {
410+
match *self.kind() {
411411
ty::Adt(adt, _) => Some(adt.did()),
412+
ty::Coroutine(def_id, ..) => Some(def_id),
412413
_ => None,
413414
}
414415
}
@@ -452,6 +453,10 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
452453
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
453454
self.value.default_span(tcx)
454455
}
456+
457+
fn ty_def_id(&self) -> Option<DefId> {
458+
self.value.ty_def_id()
459+
}
455460
}
456461

457462
impl Key for Symbol {
@@ -550,7 +555,7 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
550555
DUMMY_SP
551556
}
552557

553-
fn ty_adt_id(&self) -> Option<DefId> {
558+
fn ty_def_id(&self) -> Option<DefId> {
554559
match self.1.value.kind() {
555560
ty::Adt(adt, _) => Some(adt.did()),
556561
_ => None,

compiler/rustc_middle/src/query/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,8 @@ rustc_queries! {
13901390
) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
13911391
depth_limit
13921392
desc { "computing layout of `{}`", key.value }
1393+
// we emit our own error during query cycle handling
1394+
cycle_delay_bug
13931395
}
13941396

13951397
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.

compiler/rustc_middle/src/ty/util.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -850,18 +850,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
850850
}
851851
let args = args.fold_with(self);
852852
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
853-
let expanded_ty = match self.expanded_cache.get(&(def_id, args)) {
854-
Some(expanded_ty) => *expanded_ty,
855-
None => {
856-
for bty in self.tcx.coroutine_hidden_types(def_id) {
857-
let hidden_ty = bty.instantiate(self.tcx, args);
858-
self.fold_ty(hidden_ty);
859-
}
860-
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
861-
self.expanded_cache.insert((def_id, args), expanded_ty);
862-
expanded_ty
863-
}
864-
};
853+
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
865854
if self.check_recursion {
866855
self.seen_opaque_tys.remove(&def_id);
867856
}

compiler/rustc_middle/src/values.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_hir as hir;
66
use rustc_hir::def::{DefKind, Res};
77
use rustc_middle::ty::Representability;
88
use rustc_middle::ty::{self, Ty, TyCtxt};
9-
use rustc_query_system::query::CycleError;
9+
use rustc_query_system::query::{report_cycle, CycleError};
1010
use rustc_query_system::Value;
1111
use rustc_span::def_id::LocalDefId;
1212
use rustc_span::{ErrorGuaranteed, Span};
@@ -97,7 +97,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
9797
}
9898
for info in &cycle_error.cycle {
9999
if info.query.dep_kind == dep_kinds::representability_adt_ty
100-
&& let Some(def_id) = info.query.ty_adt_id
100+
&& let Some(def_id) = info.query.ty_def_id
101101
&& let Some(def_id) = def_id.as_local()
102102
&& !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
103103
{
@@ -131,14 +131,43 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>
131131

132132
impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
133133
fn from_cycle_error(
134-
_tcx: TyCtxt<'tcx>,
135-
_cycle_error: &CycleError,
136-
guar: ErrorGuaranteed,
134+
tcx: TyCtxt<'tcx>,
135+
cycle_error: &CycleError,
136+
_guar: ErrorGuaranteed,
137137
) -> Self {
138+
let guar = if cycle_error.cycle[0].query.dep_kind == dep_kinds::layout_of
139+
&& let Some(def_id) = cycle_error.cycle[0].query.ty_def_id
140+
&& let Some(def_id) = def_id.as_local()
141+
&& matches!(tcx.def_kind(def_id), DefKind::Coroutine)
142+
{
143+
let hir = tcx.hir();
144+
let coroutine_kind = hir
145+
.body(hir.body_owned_by(def_id))
146+
.coroutine_kind
147+
.expect("expected coroutine to have a coroutine_kind");
148+
// FIXME: `def_span` for an fn-like coroutine will point to the fn's body
149+
// due to interactions between the desugaring into a closure expr and the
150+
// def_span code. I'm not motivated to fix it, because I tried and it was
151+
// not working, so just hack around it by grabbing the parent fn's span.
152+
let span = if coroutine_kind.is_fn_like() {
153+
tcx.def_span(tcx.local_parent(def_id))
154+
} else {
155+
tcx.def_span(def_id)
156+
};
157+
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
158+
.span_label(span, "recursive `async fn`")
159+
.note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
160+
.note(
161+
"consider using the `async_recursion` crate: https://crates.io/crates/async_recursion",
162+
)
163+
.emit()
164+
} else {
165+
report_cycle(tcx.sess, cycle_error).emit()
166+
};
167+
138168
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
139169
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
140170
// tcx.arena.alloc is pretty much equal to leaking).
141-
// FIXME: `Cycle` should carry the ErrorGuaranteed
142171
Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle(guar))))
143172
}
144173
}

compiler/rustc_query_impl/src/plumbing.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,9 @@ pub(crate) fn create_query_frame<
339339
hasher.finish::<Hash64>()
340340
})
341341
};
342-
let ty_adt_id = key.ty_adt_id();
342+
let ty_def_id = key.ty_def_id();
343343

344-
QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_adt_id, hash)
344+
QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_def_id, hash)
345345
}
346346

347347
pub(crate) fn encode_query_results<'a, 'tcx, Q>(

compiler/rustc_query_system/src/query/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ pub struct QueryStackFrame {
3535
span: Option<Span>,
3636
pub def_id: Option<DefId>,
3737
pub def_kind: Option<DefKind>,
38-
pub ty_adt_id: Option<DefId>,
38+
/// A def-id that is extracted from a `Ty` in a query key
39+
pub ty_def_id: Option<DefId>,
3940
pub dep_kind: DepKind,
4041
/// This hash is used to deterministically pick
4142
/// a query to remove cycles in the parallel compiler.
@@ -51,15 +52,15 @@ impl QueryStackFrame {
5152
def_id: Option<DefId>,
5253
def_kind: Option<DefKind>,
5354
dep_kind: DepKind,
54-
ty_adt_id: Option<DefId>,
55+
ty_def_id: Option<DefId>,
5556
_hash: impl FnOnce() -> Hash64,
5657
) -> Self {
5758
Self {
5859
description,
5960
span,
6061
def_id,
6162
def_kind,
62-
ty_adt_id,
63+
ty_def_id,
6364
dep_kind,
6465
#[cfg(parallel_compiler)]
6566
hash: _hash(),

compiler/rustc_trait_selection/src/traits/query/normalize.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,16 +241,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
241241
}
242242

243243
let generic_ty = self.interner().type_of(data.def_id);
244-
let concrete_ty = generic_ty.instantiate(self.interner(), args);
244+
let mut concrete_ty = generic_ty.instantiate(self.interner(), args);
245245
self.anon_depth += 1;
246246
if concrete_ty == ty {
247-
bug!(
248-
"infinite recursion generic_ty: {:#?}, args: {:#?}, \
249-
concrete_ty: {:#?}, ty: {:#?}",
250-
generic_ty,
251-
args,
252-
concrete_ty,
253-
ty
247+
concrete_ty = Ty::new_error_with_message(
248+
self.interner(),
249+
DUMMY_SP,
250+
"recursive opaque type",
254251
);
255252
}
256253
let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty));

tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// edition: 2021
22
// build-fail
3-
//~^^ ERROR cycle detected when computing layout of
43

54
fn main() {
65
let _ = async {
@@ -31,6 +30,7 @@ where
3130
C: First,
3231
{
3332
async fn second(self) {
33+
//~^ ERROR recursion in an `async fn` requires boxing
3434
self.first().await.second().await;
3535
}
3636
}
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
error[E0391]: cycle detected when computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`
1+
error[E0733]: recursion in an `async fn` requires boxing
2+
--> $DIR/indirect-recursion-issue-112047.rs:32:5
23
|
3-
= note: ...which requires computing layout of `<<A as First>::Second as Second>::{opaque#0}`...
4-
= note: ...which again requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`, completing the cycle
5-
= note: cycle used when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:6:13: 8:6}`
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
4+
LL | async fn second(self) {
5+
| ^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
6+
|
7+
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
8+
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
79

810
error: aborting due to previous error
911

10-
For more information about this error, try `rustc --explain E0391`.
12+
For more information about this error, try `rustc --explain E0733`.

tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ async fn rec_1() { //~ ERROR recursion in an `async fn`
66
rec_2().await;
77
}
88

9-
async fn rec_2() { //~ ERROR recursion in an `async fn`
9+
async fn rec_2() {
1010
rec_1().await;
1111
}
1212

tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,6 @@ LL | async fn rec_1() {
77
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
88
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
99

10-
error[E0733]: recursion in an `async fn` requires boxing
11-
--> $DIR/mutually-recursive-async-impl-trait-type.rs:9:1
12-
|
13-
LL | async fn rec_2() {
14-
| ^^^^^^^^^^^^^^^^ recursive `async fn`
15-
|
16-
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
17-
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
18-
19-
error: aborting due to 2 previous errors
10+
error: aborting due to previous error
2011

2112
For more information about this error, try `rustc --explain E0733`.

tests/ui/impl-trait/recursive-coroutine.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1+
// check-pass
2+
// This works because the coroutine is boxed!
3+
14
#![feature(coroutines, coroutine_trait)]
25

36
use std::ops::{Coroutine, CoroutineState};
47

58
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
6-
//~^ ERROR cannot resolve opaque type
7-
//~| NOTE recursive opaque type
8-
//~| NOTE in this expansion of desugaring of
99
|| {
1010
let mut gen = Box::pin(foo());
11-
//~^ NOTE coroutine captures itself here
1211
let mut r = gen.as_mut().resume(());
1312
while let CoroutineState::Yielded(v) = r {
1413
yield v;

tests/ui/impl-trait/recursive-coroutine.stderr

Lines changed: 0 additions & 12 deletions
This file was deleted.

tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ fn substs_change<T: 'static>() -> impl Sized {
7070
}
7171

7272
fn coroutine_hold() -> impl Sized {
73-
//~^ ERROR
7473
move || {
74+
//~^ ERROR
7575
let x = coroutine_hold();
7676
yield;
7777
x;

tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,14 @@ LL |
109109
LL | (substs_change::<&T>(),)
110110
| ------------------------ returning here with type `(impl Sized,)`
111111

112-
error[E0720]: cannot resolve opaque type
113-
--> $DIR/recursive-impl-trait-type-indirect.rs:72:24
112+
error[E0733]: recursion in an `async fn` requires boxing
113+
--> $DIR/recursive-impl-trait-type-indirect.rs:73:5
114114
|
115-
LL | fn coroutine_hold() -> impl Sized {
116-
| ^^^^^^^^^^ recursive opaque type
117-
...
118-
LL | let x = coroutine_hold();
119-
| - coroutine captures itself here
115+
LL | move || {
116+
| ^^^^^^^ recursive `async fn`
117+
|
118+
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
119+
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
120120

121121
error[E0720]: cannot resolve opaque type
122122
--> $DIR/recursive-impl-trait-type-indirect.rs:86:26
@@ -144,4 +144,5 @@ LL | mutual_recursion()
144144

145145
error: aborting due to 14 previous errors
146146

147-
For more information about this error, try `rustc --explain E0720`.
147+
Some errors have detailed explanations: E0720, E0733.
148+
For more information about an error, try `rustc --explain E0720`.

0 commit comments

Comments
 (0)