Skip to content

Commit 58b1b3c

Browse files
committed
Auto merge of #117703 - compiler-errors:recursive-async, r=<try>
Support async recursive calls (as long as they have indirection) TL;DR: This code should work ``` async fn foo() { Box::pin(foo()).await; } ``` r? `@ghost` while I write up a description, etc.
2 parents 2b603f9 + ac3c93c commit 58b1b3c

38 files changed

+282
-177
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -792,8 +792,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
792792
// debuggers and debugger extensions expect it to be called `__awaitee`. They use
793793
// this name to identify what is being awaited by a suspended async functions.
794794
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
795-
let (awaitee_pat, awaitee_pat_hid) =
796-
self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::MUT);
795+
let (awaitee_pat, awaitee_pat_hid) = self.pat_ident_binding_mode(
796+
gen_future_span,
797+
awaitee_ident,
798+
hir::BindingAnnotation::MUT,
799+
);
797800

798801
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
799802

compiler/rustc_hir/src/hir.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,15 @@ pub enum CoroutineKind {
15291529
Coroutine,
15301530
}
15311531

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

compiler/rustc_hir_analysis/src/check/check.rs

+7-18
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

+9-4
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

+2
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/query/plumbing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
5353
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
5454
pub hash_result: HashResult<C::Value>,
5555
pub value_from_cycle_error:
56-
fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value,
56+
fn(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) -> C::Value,
5757
pub format_value: fn(&C::Value) -> String,
5858
}
5959

compiler/rustc_middle/src/ty/layout.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ pub enum LayoutError<'tcx> {
215215
SizeOverflow(Ty<'tcx>),
216216
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
217217
ReferencesError(ErrorGuaranteed),
218-
Cycle,
218+
Cycle(ErrorGuaranteed),
219219
}
220220

221221
impl<'tcx> LayoutError<'tcx> {
@@ -226,7 +226,7 @@ impl<'tcx> LayoutError<'tcx> {
226226
Unknown(_) => middle_unknown_layout,
227227
SizeOverflow(_) => middle_values_too_big,
228228
NormalizationFailure(_, _) => middle_cannot_be_normalized,
229-
Cycle => middle_cycle,
229+
Cycle(_) => middle_cycle,
230230
ReferencesError(_) => middle_layout_references_error,
231231
}
232232
}
@@ -240,7 +240,7 @@ impl<'tcx> LayoutError<'tcx> {
240240
NormalizationFailure(ty, e) => {
241241
E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
242242
}
243-
Cycle => E::Cycle,
243+
Cycle(_) => E::Cycle,
244244
ReferencesError(_) => E::ReferencesError,
245245
}
246246
}
@@ -261,7 +261,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
261261
t,
262262
e.get_type_for_failure()
263263
),
264-
LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"),
264+
LayoutError::Cycle(_) => write!(f, "a cycle occurred during layout computation"),
265265
LayoutError::ReferencesError(_) => write!(f, "the type has an unknown layout"),
266266
}
267267
}
@@ -333,7 +333,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
333333
Err(err @ LayoutError::Unknown(_)) => err,
334334
// We can't extract SizeSkeleton info from other layout errors
335335
Err(
336-
e @ LayoutError::Cycle
336+
e @ LayoutError::Cycle(_)
337337
| e @ LayoutError::SizeOverflow(_)
338338
| e @ LayoutError::NormalizationFailure(..)
339339
| e @ LayoutError::ReferencesError(_),

compiler/rustc_middle/src/ty/util.rs

+11-18
Original file line numberDiff line numberDiff line change
@@ -747,9 +747,13 @@ impl<'tcx> TyCtxt<'tcx> {
747747
match def_kind {
748748
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method",
749749
DefKind::Coroutine => match self.coroutine_kind(def_id).unwrap() {
750-
rustc_hir::CoroutineKind::Async(..) => "async closure",
751-
rustc_hir::CoroutineKind::Coroutine => "coroutine",
752-
rustc_hir::CoroutineKind::Gen(..) => "gen closure",
750+
hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "async fn",
751+
hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "async block",
752+
hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "async closure",
753+
hir::CoroutineKind::Gen(hir::CoroutineSource::Fn) => "gen fn",
754+
hir::CoroutineKind::Gen(hir::CoroutineSource::Block) => "gen block",
755+
hir::CoroutineKind::Gen(hir::CoroutineSource::Closure) => "gen closure",
756+
hir::CoroutineKind::Coroutine => "coroutine",
753757
},
754758
_ => def_kind.descr(def_id),
755759
}
@@ -765,9 +769,9 @@ impl<'tcx> TyCtxt<'tcx> {
765769
match def_kind {
766770
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a",
767771
DefKind::Coroutine => match self.coroutine_kind(def_id).unwrap() {
768-
rustc_hir::CoroutineKind::Async(..) => "an",
769-
rustc_hir::CoroutineKind::Coroutine => "a",
770-
rustc_hir::CoroutineKind::Gen(..) => "a",
772+
hir::CoroutineKind::Async(..) => "an",
773+
hir::CoroutineKind::Coroutine => "a",
774+
hir::CoroutineKind::Gen(..) => "a",
771775
},
772776
_ => def_kind.article(),
773777
}
@@ -850,18 +854,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
850854
}
851855
let args = args.fold_with(self);
852856
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-
};
857+
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
865858
if self.check_recursion {
866859
self.seen_opaque_tys.remove(&def_id);
867860
}

0 commit comments

Comments
 (0)