Require coroutine kind type to be passed to TyCtxt::coroutine_layout
This commit is contained in:
parent
847fd88df7
commit
b7d67eace7
8 changed files with 59 additions and 17 deletions
|
@ -683,7 +683,8 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
|
||||||
_ => unreachable!(),
|
_ => 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 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);
|
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
|
||||||
|
|
|
@ -135,7 +135,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
|
||||||
unique_type_id: UniqueTypeId<'tcx>,
|
unique_type_id: UniqueTypeId<'tcx>,
|
||||||
) -> DINodeCreationResult<'ll> {
|
) -> DINodeCreationResult<'ll> {
|
||||||
let coroutine_type = unique_type_id.expect_ty();
|
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)
|
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,
|
DIFlags::FlagZero,
|
||||||
),
|
),
|
||||||
|cx, coroutine_type_di_node| {
|
|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, .. } =
|
let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } =
|
||||||
coroutine_type_and_layout.variants
|
coroutine_type_and_layout.variants
|
||||||
|
|
|
@ -101,9 +101,9 @@ impl<'tcx> MirPass<'tcx> for Validator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce that coroutine-closure layouts are identical.
|
// 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_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 layout != by_move_layout {
|
||||||
// If this turns out not to be true, please let compiler-errors know.
|
// 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
|
// args of the coroutine. Otherwise, we prefer to use this body
|
||||||
// since we may be in the process of computing this MIR in the
|
// since we may be in the process of computing this MIR in the
|
||||||
// first place.
|
// first place.
|
||||||
let gen_body = if def_id == self.caller_body.source.def_id() {
|
let layout = if def_id == self.caller_body.source.def_id() {
|
||||||
self.caller_body
|
// FIXME: This is not right for async closures.
|
||||||
|
self.caller_body.coroutine_layout_raw()
|
||||||
} else {
|
} 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(
|
self.fail(
|
||||||
location,
|
location,
|
||||||
format!("No coroutine layout for {parent_ty:?}"),
|
format!("No coroutine layout for {parent_ty:?}"),
|
||||||
|
|
|
@ -652,8 +652,9 @@ impl<'tcx> Body<'tcx> {
|
||||||
self.coroutine.as_ref().and_then(|coroutine| coroutine.resume_ty)
|
self.coroutine.as_ref().and_then(|coroutine| coroutine.resume_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prefer going through [`TyCtxt::coroutine_layout`] rather than using this directly.
|
||||||
#[inline]
|
#[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())
|
self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_layout.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ fn dump_matched_mir_node<'tcx, F>(
|
||||||
Some(promoted) => write!(file, "::{promoted:?}`")?,
|
Some(promoted) => write!(file, "::{promoted:?}`")?,
|
||||||
}
|
}
|
||||||
writeln!(file, " {disambiguator} {pass_name}")?;
|
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, "/* coroutine_layout = {layout:#?} */")?;
|
||||||
}
|
}
|
||||||
writeln!(file)?;
|
writeln!(file)?;
|
||||||
|
|
|
@ -60,6 +60,7 @@ pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
||||||
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
|
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
|
||||||
pub use vtable::*;
|
pub use vtable::*;
|
||||||
|
|
||||||
|
use std::assert_matches::assert_matches;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -1826,8 +1827,40 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
|
||||||
/// Returns layout of a coroutine. Layout might be unavailable if the
|
/// Returns layout of a coroutine. Layout might be unavailable if the
|
||||||
/// coroutine is tainted by errors.
|
/// 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.
|
/// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
|
||||||
|
|
|
@ -694,7 +694,10 @@ impl<'tcx> CoroutineArgs<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> {
|
pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> {
|
||||||
// FIXME requires optimized MIR
|
// 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
|
/// The discriminant for the given variant. Panics if the `variant_index` is
|
||||||
|
@ -754,7 +757,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
) -> impl Iterator<Item: Iterator<Item = Ty<'tcx>> + Captures<'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| {
|
layout.variant_fields.iter().map(move |variant| {
|
||||||
variant.iter().map(move |field| {
|
variant.iter().map(move |field| {
|
||||||
ty::EarlyBinder::bind(layout.field_tys[*field].ty).instantiate(tcx, self.args)
|
ty::EarlyBinder::bind(layout.field_tys[*field].ty).instantiate(tcx, self.args)
|
||||||
|
|
|
@ -745,7 +745,7 @@ fn coroutine_layout<'tcx>(
|
||||||
let tcx = cx.tcx;
|
let tcx = cx.tcx;
|
||||||
let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args);
|
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)));
|
return Err(error(cx, LayoutError::Unknown(ty)));
|
||||||
};
|
};
|
||||||
let (ineligible_locals, assignments) = coroutine_saved_local_eligibility(info);
|
let (ineligible_locals, assignments) = coroutine_saved_local_eligibility(info);
|
||||||
|
@ -1072,7 +1072,7 @@ fn variant_info_for_coroutine<'tcx>(
|
||||||
return (vec![], None);
|
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 upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
|
||||||
|
|
||||||
let mut upvars_size = Size::ZERO;
|
let mut upvars_size = Size::ZERO;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue