1
Fork 0

Only compute layout of opaque if coroutine is the cause of an opaque cycle

This commit is contained in:
Michael Goulet 2023-11-13 02:08:14 +00:00
parent 199af7cef0
commit fa2ff51ace
4 changed files with 53 additions and 12 deletions

View file

@ -17,7 +17,7 @@ use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{ use rustc_middle::ty::{
AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@ -232,16 +232,33 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
span: Span, span: Span,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let args = GenericArgs::identity_for_item(tcx, def_id); let args = GenericArgs::identity_for_item(tcx, def_id);
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
// First, try to look at any opaque expansion cycles, considering coroutine fields
// (even though these aren't necessarily true errors).
if tcx
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::Yes)
.is_err()
{
// Look for true opaque expansion cycles, but ignore coroutines.
// This will give us any true errors. Coroutines are only problematic
// if they cause layout computation errors.
if tcx
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
.is_err()
{
let reported = opaque_type_cycle_error(tcx, def_id, span); let reported = opaque_type_cycle_error(tcx, def_id, span);
Err(reported) return Err(reported);
} else if let Err(&LayoutError::Cycle(guar)) = }
// And also look for cycle errors in the layout of coroutines.
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))) tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args)))
{ {
Err(guar) return Err(guar);
} else {
Ok(())
} }
}
Ok(())
} }
/// Check that the concrete type behind `impl Trait` actually implements `Trait`. /// Check that the concrete type behind `impl Trait` actually implements `Trait`.

View file

@ -702,6 +702,7 @@ impl<'tcx> TyCtxt<'tcx> {
self, self,
def_id: DefId, def_id: DefId,
args: GenericArgsRef<'tcx>, args: GenericArgsRef<'tcx>,
inspect_coroutine_fields: InspectCoroutineFields,
) -> Result<Ty<'tcx>, Ty<'tcx>> { ) -> Result<Ty<'tcx>, Ty<'tcx>> {
let mut visitor = OpaqueTypeExpander { let mut visitor = OpaqueTypeExpander {
seen_opaque_tys: FxHashSet::default(), seen_opaque_tys: FxHashSet::default(),
@ -712,6 +713,7 @@ impl<'tcx> TyCtxt<'tcx> {
check_recursion: true, check_recursion: true,
expand_coroutines: true, expand_coroutines: true,
tcx: self, tcx: self,
inspect_coroutine_fields,
}; };
let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap(); let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap();
@ -885,6 +887,13 @@ struct OpaqueTypeExpander<'tcx> {
/// recursion, and 'false' otherwise to avoid unnecessary work. /// recursion, and 'false' otherwise to avoid unnecessary work.
check_recursion: bool, check_recursion: bool,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
inspect_coroutine_fields: InspectCoroutineFields,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum InspectCoroutineFields {
No,
Yes,
} }
impl<'tcx> OpaqueTypeExpander<'tcx> { impl<'tcx> OpaqueTypeExpander<'tcx> {
@ -923,7 +932,20 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
} }
let args = args.fold_with(self); let args = args.fold_with(self);
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { 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 => {
if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
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); let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
self.expanded_cache.insert((def_id, args), expanded_ty);
expanded_ty
}
};
if self.check_recursion { if self.check_recursion {
self.seen_opaque_tys.remove(&def_id); self.seen_opaque_tys.remove(&def_id);
} }
@ -1495,6 +1517,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
check_recursion: false, check_recursion: false,
expand_coroutines: false, expand_coroutines: false,
tcx, tcx,
inspect_coroutine_fields: InspectCoroutineFields::No,
}; };
val.fold_with(&mut visitor) val.fold_with(&mut visitor)
} }

View file

@ -1,4 +1,5 @@
// edition: 2021 // edition: 2021
// build-fail
#![feature(impl_trait_in_assoc_type)] #![feature(impl_trait_in_assoc_type)]

View file

@ -1,5 +1,5 @@
error[E0733]: recursion in an async block requires boxing error[E0733]: recursion in an async block requires boxing
--> $DIR/indirect-recursion-issue-112047.rs:21:9 --> $DIR/indirect-recursion-issue-112047.rs:22:9
| |
LL | async move { recur(self).await; } LL | async move { recur(self).await; }
| ^^^^^^^^^^^^^-----------------^^^ | ^^^^^^^^^^^^^-----------------^^^
@ -7,7 +7,7 @@ LL | async move { recur(self).await; }
| recursive call here | recursive call here
| |
note: which leads to this async fn note: which leads to this async fn
--> $DIR/indirect-recursion-issue-112047.rs:13:1 --> $DIR/indirect-recursion-issue-112047.rs:14:1
| |
LL | async fn recur(t: impl Recur) { LL | async fn recur(t: impl Recur) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^