Skip to content

Commit fa2ff51

Browse files
Only compute layout of opaque if coroutine is the cause of an opaque cycle
1 parent 199af7c commit fa2ff51

File tree

4 files changed

+53
-12
lines changed

4 files changed

+53
-12
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_middle::middle::stability::EvalResult;
1717
use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
1818
use rustc_middle::ty::fold::BottomUpFolder;
1919
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
20-
use rustc_middle::ty::util::{Discr, IntTypeExt};
20+
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
2121
use rustc_middle::ty::GenericArgKind;
2222
use rustc_middle::ty::{
2323
AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -232,16 +232,33 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
232232
span: Span,
233233
) -> Result<(), ErrorGuaranteed> {
234234
let args = GenericArgs::identity_for_item(tcx, def_id);
235-
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
236-
let reported = opaque_type_cycle_error(tcx, def_id, span);
237-
Err(reported)
238-
} else if let Err(&LayoutError::Cycle(guar)) =
239-
tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args)))
235+
236+
// First, try to look at any opaque expansion cycles, considering coroutine fields
237+
// (even though these aren't necessarily true errors).
238+
if tcx
239+
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::Yes)
240+
.is_err()
240241
{
241-
Err(guar)
242-
} else {
243-
Ok(())
242+
// Look for true opaque expansion cycles, but ignore coroutines.
243+
// This will give us any true errors. Coroutines are only problematic
244+
// if they cause layout computation errors.
245+
if tcx
246+
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
247+
.is_err()
248+
{
249+
let reported = opaque_type_cycle_error(tcx, def_id, span);
250+
return Err(reported);
251+
}
252+
253+
// And also look for cycle errors in the layout of coroutines.
254+
if let Err(&LayoutError::Cycle(guar)) =
255+
tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args)))
256+
{
257+
return Err(guar);
258+
}
244259
}
260+
261+
Ok(())
245262
}
246263

247264
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.

compiler/rustc_middle/src/ty/util.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ impl<'tcx> TyCtxt<'tcx> {
702702
self,
703703
def_id: DefId,
704704
args: GenericArgsRef<'tcx>,
705+
inspect_coroutine_fields: InspectCoroutineFields,
705706
) -> Result<Ty<'tcx>, Ty<'tcx>> {
706707
let mut visitor = OpaqueTypeExpander {
707708
seen_opaque_tys: FxHashSet::default(),
@@ -712,6 +713,7 @@ impl<'tcx> TyCtxt<'tcx> {
712713
check_recursion: true,
713714
expand_coroutines: true,
714715
tcx: self,
716+
inspect_coroutine_fields,
715717
};
716718

717719
let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap();
@@ -885,6 +887,13 @@ struct OpaqueTypeExpander<'tcx> {
885887
/// recursion, and 'false' otherwise to avoid unnecessary work.
886888
check_recursion: bool,
887889
tcx: TyCtxt<'tcx>,
890+
inspect_coroutine_fields: InspectCoroutineFields,
891+
}
892+
893+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
894+
pub enum InspectCoroutineFields {
895+
No,
896+
Yes,
888897
}
889898

890899
impl<'tcx> OpaqueTypeExpander<'tcx> {
@@ -923,7 +932,20 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
923932
}
924933
let args = args.fold_with(self);
925934
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
926-
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
935+
let expanded_ty = match self.expanded_cache.get(&(def_id, args)) {
936+
Some(expanded_ty) => *expanded_ty,
937+
None => {
938+
if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
939+
for bty in self.tcx.coroutine_hidden_types(def_id) {
940+
let hidden_ty = bty.instantiate(self.tcx, args);
941+
self.fold_ty(hidden_ty);
942+
}
943+
}
944+
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
945+
self.expanded_cache.insert((def_id, args), expanded_ty);
946+
expanded_ty
947+
}
948+
};
927949
if self.check_recursion {
928950
self.seen_opaque_tys.remove(&def_id);
929951
}
@@ -1495,6 +1517,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
14951517
check_recursion: false,
14961518
expand_coroutines: false,
14971519
tcx,
1520+
inspect_coroutine_fields: InspectCoroutineFields::No,
14981521
};
14991522
val.fold_with(&mut visitor)
15001523
}

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

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

34
#![feature(impl_trait_in_assoc_type)]
45

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

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

0 commit comments

Comments
 (0)