Skip to content

Commit eedfece

Browse files
Eagerly detect coroutine recursion pre-mono when possible
1 parent 6dd75f0 commit eedfece

12 files changed

+37
-95
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+4-25
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_middle::span_bug;
1919
use rustc_middle::ty::error::TypeErrorToStringExt;
2020
use rustc_middle::ty::fold::{BottomUpFolder, fold_regions};
2121
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
22-
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
22+
use rustc_middle::ty::util::{Discr, IntTypeExt};
2323
use rustc_middle::ty::{
2424
AdtDef, GenericArgKind, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
2525
};
@@ -257,30 +257,9 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
257257

258258
// First, try to look at any opaque expansion cycles, considering coroutine fields
259259
// (even though these aren't necessarily true errors).
260-
if tcx
261-
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::Yes)
262-
.is_err()
263-
{
264-
// Look for true opaque expansion cycles, but ignore coroutines.
265-
// This will give us any true errors. Coroutines are only problematic
266-
// if they cause layout computation errors.
267-
if tcx
268-
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
269-
.is_err()
270-
{
271-
let reported = opaque_type_cycle_error(tcx, def_id);
272-
return Err(reported);
273-
}
274-
275-
// And also look for cycle errors in the layout of coroutines.
276-
if let Err(&LayoutError::Cycle(guar)) =
277-
tcx.layout_of(
278-
ty::TypingEnv::post_analysis(tcx, def_id.to_def_id())
279-
.as_query_input(Ty::new_opaque(tcx, def_id.to_def_id(), args)),
280-
)
281-
{
282-
return Err(guar);
283-
}
260+
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
261+
let reported = opaque_type_cycle_error(tcx, def_id);
262+
return Err(reported);
284263
}
285264

286265
Ok(())

compiler/rustc_interface/src/passes.rs

+5
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,11 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
908908
tcx.ensure().check_coroutine_obligations(
909909
tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
910910
);
911+
// Eagerly check the unsubstituted layout for cycles.
912+
tcx.ensure().layout_of(
913+
ty::TypingEnv::post_analysis(tcx, def_id.to_def_id())
914+
.as_query_input(tcx.type_of(def_id).instantiate_identity()),
915+
);
911916
}
912917
});
913918
});

compiler/rustc_middle/src/ty/util.rs

+2-56
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,6 @@ impl<'tcx> TyCtxt<'tcx> {
777777
self,
778778
def_id: DefId,
779779
args: GenericArgsRef<'tcx>,
780-
inspect_coroutine_fields: InspectCoroutineFields,
781780
) -> Result<Ty<'tcx>, Ty<'tcx>> {
782781
let mut visitor = OpaqueTypeExpander {
783782
seen_opaque_tys: FxHashSet::default(),
@@ -786,9 +785,7 @@ impl<'tcx> TyCtxt<'tcx> {
786785
found_recursion: false,
787786
found_any_recursion: false,
788787
check_recursion: true,
789-
expand_coroutines: true,
790788
tcx: self,
791-
inspect_coroutine_fields,
792789
};
793790

794791
let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap();
@@ -965,19 +962,11 @@ struct OpaqueTypeExpander<'tcx> {
965962
primary_def_id: Option<DefId>,
966963
found_recursion: bool,
967964
found_any_recursion: bool,
968-
expand_coroutines: bool,
969965
/// Whether or not to check for recursive opaque types.
970966
/// This is `true` when we're explicitly checking for opaque type
971967
/// recursion, and 'false' otherwise to avoid unnecessary work.
972968
check_recursion: bool,
973969
tcx: TyCtxt<'tcx>,
974-
inspect_coroutine_fields: InspectCoroutineFields,
975-
}
976-
977-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
978-
pub enum InspectCoroutineFields {
979-
No,
980-
Yes,
981970
}
982971

983972
impl<'tcx> OpaqueTypeExpander<'tcx> {
@@ -1009,41 +998,6 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
1009998
None
1010999
}
10111000
}
1012-
1013-
fn expand_coroutine(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) -> Option<Ty<'tcx>> {
1014-
if self.found_any_recursion {
1015-
return None;
1016-
}
1017-
let args = args.fold_with(self);
1018-
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
1019-
let expanded_ty = match self.expanded_cache.get(&(def_id, args)) {
1020-
Some(expanded_ty) => *expanded_ty,
1021-
None => {
1022-
if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
1023-
for bty in self.tcx.bound_coroutine_hidden_types(def_id) {
1024-
let hidden_ty = self.tcx.instantiate_bound_regions_with_erased(
1025-
bty.instantiate(self.tcx, args),
1026-
);
1027-
self.fold_ty(hidden_ty);
1028-
}
1029-
}
1030-
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
1031-
self.expanded_cache.insert((def_id, args), expanded_ty);
1032-
expanded_ty
1033-
}
1034-
};
1035-
if self.check_recursion {
1036-
self.seen_opaque_tys.remove(&def_id);
1037-
}
1038-
Some(expanded_ty)
1039-
} else {
1040-
// If another opaque type that we contain is recursive, then it
1041-
// will report the error, so we don't have to.
1042-
self.found_any_recursion = true;
1043-
self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap();
1044-
None
1045-
}
1046-
}
10471001
}
10481002

10491003
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
@@ -1052,19 +1006,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
10521006
}
10531007

10541008
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
1055-
let mut t = if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *t.kind() {
1009+
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *t.kind() {
10561010
self.expand_opaque_ty(def_id, args).unwrap_or(t)
1057-
} else if t.has_opaque_types() || t.has_coroutines() {
1011+
} else if t.has_opaque_types() {
10581012
t.super_fold_with(self)
10591013
} else {
10601014
t
1061-
};
1062-
if self.expand_coroutines {
1063-
if let ty::CoroutineWitness(def_id, args) = *t.kind() {
1064-
t = self.expand_coroutine(def_id, args).unwrap_or(t);
1065-
}
10661015
}
1067-
t
10681016
}
10691017

10701018
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
@@ -1753,9 +1701,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
17531701
found_recursion: false,
17541702
found_any_recursion: false,
17551703
check_recursion: false,
1756-
expand_coroutines: false,
17571704
tcx,
1758-
inspect_coroutine_fields: InspectCoroutineFields::No,
17591705
};
17601706
val.fold_with(&mut visitor)
17611707
}

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

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
//@ edition: 2021
22

3-
// Test doesn't fail until monomorphization time, unfortunately.
4-
//@ build-fail
5-
63
fn main() {
74
let _ = async {
85
A.first().await.second().await;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0733]: recursion in an async fn requires boxing
2-
--> $DIR/indirect-recursion-issue-112047.rs:34:5
2+
--> $DIR/indirect-recursion-issue-112047.rs:31:5
33
|
44
LL | async fn second(self) {
55
| ^^^^^^^^^^^^^^^^^^^^^

tests/ui/force-inlining/deny-async.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
//@ check-fail
21
//@ compile-flags: --crate-type=lib
32
//@ edition: 2021
3+
44
#![allow(internal_features)]
55
#![feature(rustc_attrs)]
66

@@ -20,5 +20,7 @@ pub fn callee_justified() {
2020

2121
async fn async_caller() {
2222
callee();
23+
//~^ ERROR `callee` could not be inlined
2324
callee_justified();
25+
//~^ ERROR `callee_justified` could not be inlined
2426
}

tests/ui/force-inlining/deny-async.stderr

+18-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,22 @@ LL | pub fn callee_justified() {
2020
|
2121
= note: incompatible due to: #[rustc_no_mir_inline]
2222

23-
error: aborting due to 2 previous errors
23+
error: `callee` could not be inlined into `async_caller::{closure#0}` but is required to be inlined
24+
--> $DIR/deny-async.rs:22:5
25+
|
26+
LL | callee();
27+
| ^^^^^^^^ ...`callee` called here
28+
|
29+
= note: could not be inlined due to: #[rustc_no_mir_inline]
30+
31+
error: `callee_justified` could not be inlined into `async_caller::{closure#0}` but is required to be inlined
32+
--> $DIR/deny-async.rs:24:5
33+
|
34+
LL | callee_justified();
35+
| ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here
36+
|
37+
= note: could not be inlined due to: #[rustc_no_mir_inline]
38+
= note: `callee_justified` is required to be inlined to: the test requires it
39+
40+
error: aborting due to 4 previous errors
2441

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0733]: recursion in a coroutine requires boxing
2-
--> $DIR/recursive-coroutine-indirect.rs:11:18
2+
--> $DIR/recursive-coroutine-indirect.rs:8:18
33
|
44
LL | #[coroutine] move || {
55
| ^^^^^^^

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0733]: recursion in a coroutine requires boxing
2-
--> $DIR/recursive-coroutine-indirect.rs:11:18
2+
--> $DIR/recursive-coroutine-indirect.rs:8:18
33
|
44
LL | #[coroutine] move || {
55
| ^^^^^^^

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

-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
//@ ignore-compare-mode-next-solver (explicit revisions)
33
//@[next] compile-flags: -Znext-solver
44

5-
//@[next] build-fail
6-
// Deeply normalizing writeback results of opaques makes this into a post-mono error :(
7-
85
#![feature(coroutines)]
96
#![allow(unconditional_recursion)]
107
fn coroutine_hold() -> impl Sized {

tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@ edition: 2021
2-
//@ build-fail
32

43
#![feature(impl_trait_in_assoc_type)]
54

tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0733]: recursion in an async block requires boxing
2-
--> $DIR/indirect-recursion-issue-112047.rs:22:9
2+
--> $DIR/indirect-recursion-issue-112047.rs:21:9
33
|
44
LL | async move { recur(self).await; }
55
| ^^^^^^^^^^ ----------------- recursive call here
66
|
77
note: which leads to this async fn
8-
--> $DIR/indirect-recursion-issue-112047.rs:14:1
8+
--> $DIR/indirect-recursion-issue-112047.rs:13:1
99
|
1010
LL | async fn recur(t: impl Recur) {
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)