1
Fork 0

Require coroutine kind type to be passed to TyCtxt::coroutine_layout

This commit is contained in:
Michael Goulet 2024-03-24 21:12:49 -04:00
parent 847fd88df7
commit b7d67eace7
8 changed files with 59 additions and 17 deletions

View file

@ -683,7 +683,8 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
_ => unreachable!(),
};
let coroutine_layout = cx.tcx.coroutine_layout(coroutine_def_id).unwrap();
let coroutine_layout =
cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args.kind_ty()).unwrap();
let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);

View file

@ -135,7 +135,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
unique_type_id: UniqueTypeId<'tcx>,
) -> DINodeCreationResult<'ll> {
let coroutine_type = unique_type_id.expect_ty();
let &ty::Coroutine(coroutine_def_id, _) = coroutine_type.kind() else {
let &ty::Coroutine(coroutine_def_id, coroutine_args) = coroutine_type.kind() else {
bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
};
@ -158,7 +158,10 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
DIFlags::FlagZero,
),
|cx, coroutine_type_di_node| {
let coroutine_layout = cx.tcx.coroutine_layout(coroutine_def_id).unwrap();
let coroutine_layout = cx
.tcx
.coroutine_layout(coroutine_def_id, coroutine_args.as_coroutine().kind_ty())
.unwrap();
let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } =
coroutine_type_and_layout.variants

View file

@ -101,9 +101,9 @@ impl<'tcx> MirPass<'tcx> for Validator {
}
// Enforce that coroutine-closure layouts are identical.
if let Some(layout) = body.coroutine_layout()
if let Some(layout) = body.coroutine_layout_raw()
&& let Some(by_move_body) = body.coroutine_by_move_body()
&& let Some(by_move_layout) = by_move_body.coroutine_layout()
&& let Some(by_move_layout) = by_move_body.coroutine_layout_raw()
{
if layout != by_move_layout {
// If this turns out not to be true, please let compiler-errors know.
@ -715,13 +715,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// args of the coroutine. Otherwise, we prefer to use this body
// since we may be in the process of computing this MIR in the
// first place.
let gen_body = if def_id == self.caller_body.source.def_id() {
self.caller_body
let layout = if def_id == self.caller_body.source.def_id() {
// FIXME: This is not right for async closures.
self.caller_body.coroutine_layout_raw()
} else {
self.tcx.optimized_mir(def_id)
self.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty())
};
let Some(layout) = gen_body.coroutine_layout() else {
let Some(layout) = layout else {
self.fail(
location,
format!("No coroutine layout for {parent_ty:?}"),

View file

@ -652,8 +652,9 @@ impl<'tcx> Body<'tcx> {
self.coroutine.as_ref().and_then(|coroutine| coroutine.resume_ty)
}
/// Prefer going through [`TyCtxt::coroutine_layout`] rather than using this directly.
#[inline]
pub fn coroutine_layout(&self) -> Option<&CoroutineLayout<'tcx>> {
pub fn coroutine_layout_raw(&self) -> Option<&CoroutineLayout<'tcx>> {
self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_layout.as_ref())
}

View file

@ -126,7 +126,7 @@ fn dump_matched_mir_node<'tcx, F>(
Some(promoted) => write!(file, "::{promoted:?}`")?,
}
writeln!(file, " {disambiguator} {pass_name}")?;
if let Some(ref layout) = body.coroutine_layout() {
if let Some(ref layout) = body.coroutine_layout_raw() {
writeln!(file, "/* coroutine_layout = {layout:#?} */")?;
}
writeln!(file)?;

View file

@ -60,6 +60,7 @@ pub use rustc_target::abi::{ReprFlags, ReprOptions};
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
pub use vtable::*;
use std::assert_matches::assert_matches;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
@ -1826,8 +1827,40 @@ impl<'tcx> TyCtxt<'tcx> {
/// Returns layout of a coroutine. Layout might be unavailable if the
/// coroutine is tainted by errors.
pub fn coroutine_layout(self, def_id: DefId) -> Option<&'tcx CoroutineLayout<'tcx>> {
self.optimized_mir(def_id).coroutine_layout()
///
/// Takes `coroutine_kind` which can be acquired from the `CoroutineArgs::kind_ty`,
/// e.g. `args.as_coroutine().kind_ty()`.
pub fn coroutine_layout(
self,
def_id: DefId,
coroutine_kind_ty: Ty<'tcx>,
) -> Option<&'tcx CoroutineLayout<'tcx>> {
let mir = self.optimized_mir(def_id);
// Regular coroutine
if coroutine_kind_ty.is_unit() {
mir.coroutine_layout_raw()
} else {
// If we have a `Coroutine` that comes from an coroutine-closure,
// then it may be a by-move or by-ref body.
let ty::Coroutine(_, identity_args) =
*self.type_of(def_id).instantiate_identity().kind()
else {
unreachable!();
};
let identity_kind_ty = identity_args.as_coroutine().kind_ty();
// If the types differ, then we must be getting the by-move body of
// a by-ref coroutine.
if identity_kind_ty == coroutine_kind_ty {
mir.coroutine_layout_raw()
} else {
assert_matches!(coroutine_kind_ty.to_opt_closure_kind(), Some(ClosureKind::FnOnce));
assert_matches!(
identity_kind_ty.to_opt_closure_kind(),
Some(ClosureKind::Fn | ClosureKind::FnMut)
);
mir.coroutine_by_move_body().unwrap().coroutine_layout_raw()
}
}
}
/// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.

View file

@ -694,7 +694,10 @@ impl<'tcx> CoroutineArgs<'tcx> {
#[inline]
pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> {
// FIXME requires optimized MIR
FIRST_VARIANT..tcx.coroutine_layout(def_id).unwrap().variant_fields.next_index()
// FIXME(async_closures): We should assert all coroutine layouts have
// the same number of variants.
FIRST_VARIANT
..tcx.coroutine_layout(def_id, tcx.types.unit).unwrap().variant_fields.next_index()
}
/// The discriminant for the given variant. Panics if the `variant_index` is
@ -754,7 +757,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
def_id: DefId,
tcx: TyCtxt<'tcx>,
) -> impl Iterator<Item: Iterator<Item = Ty<'tcx>> + Captures<'tcx>> {
let layout = tcx.coroutine_layout(def_id).unwrap();
let layout = tcx.coroutine_layout(def_id, self.kind_ty()).unwrap();
layout.variant_fields.iter().map(move |variant| {
variant.iter().map(move |field| {
ty::EarlyBinder::bind(layout.field_tys[*field].ty).instantiate(tcx, self.args)

View file

@ -745,7 +745,7 @@ fn coroutine_layout<'tcx>(
let tcx = cx.tcx;
let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args);
let Some(info) = tcx.coroutine_layout(def_id) else {
let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else {
return Err(error(cx, LayoutError::Unknown(ty)));
};
let (ineligible_locals, assignments) = coroutine_saved_local_eligibility(info);
@ -1072,7 +1072,7 @@ fn variant_info_for_coroutine<'tcx>(
return (vec![], None);
};
let coroutine = cx.tcx.coroutine_layout(def_id).unwrap();
let coroutine = cx.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()).unwrap();
let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
let mut upvars_size = Size::ZERO;