reduce allocations
This commit is contained in:
parent
9061ffba8c
commit
dc93a28e98
@ -218,7 +218,7 @@ fn to_upvars_resolved_place_builder<'tcx>(
|
|||||||
let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder(
|
let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder(
|
||||||
cx,
|
cx,
|
||||||
upvar_resolved_local,
|
upvar_resolved_local,
|
||||||
local_projection.to_vec(),
|
local_projection.as_slice(),
|
||||||
upvar_projection,
|
upvar_projection,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ fn strip_prefix<'a, 'tcx>(
|
|||||||
mut base_ty: Ty<'tcx>,
|
mut base_ty: Ty<'tcx>,
|
||||||
projections: &'a [UpvarProjectionElem<'tcx>],
|
projections: &'a [UpvarProjectionElem<'tcx>],
|
||||||
prefix_projections: &[HirProjection<'tcx>],
|
prefix_projections: &[HirProjection<'tcx>],
|
||||||
) -> Vec<UpvarProjectionElem<'tcx>> {
|
) -> impl Iterator<Item = UpvarProjectionElem<'tcx>> + 'a {
|
||||||
let mut iter = projections
|
let mut iter = projections
|
||||||
.iter()
|
.iter()
|
||||||
// Filter out opaque casts, they are unnecessary in the prefix.
|
// Filter out opaque casts, they are unnecessary in the prefix.
|
||||||
@ -293,7 +293,7 @@ fn strip_prefix<'a, 'tcx>(
|
|||||||
base_ty = projection.ty;
|
base_ty = projection.ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter.collect::<Vec<_>>()
|
iter
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> PlaceBuilder<'tcx> {
|
impl<'tcx> PlaceBuilder<'tcx> {
|
||||||
@ -342,10 +342,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
|
|||||||
|
|
||||||
#[instrument(skip(cx), level = "debug")]
|
#[instrument(skip(cx), level = "debug")]
|
||||||
pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self {
|
pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self {
|
||||||
let field_ty = match self {
|
let field_ty = match self.clone() {
|
||||||
PlaceBuilder::Local(..) => {
|
PlaceBuilder::Local(local, projection) => {
|
||||||
let base_place = self.clone();
|
let base_place = PlaceBuilder::Local(local, projection);
|
||||||
PlaceBuilder::compute_field_ty(cx, f, base_place)
|
let PlaceTy { ty, variant_index } =
|
||||||
|
base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
|
||||||
|
let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
|
||||||
|
|
||||||
|
PlaceBuilder::compute_field_ty(cx, f, base_ty, variant_index)
|
||||||
}
|
}
|
||||||
PlaceBuilder::UpVar(..) => {
|
PlaceBuilder::UpVar(..) => {
|
||||||
let dummy_ty = cx.tcx.mk_ty_infer(ty::FreshTy(0));
|
let dummy_ty = cx.tcx.mk_ty_infer(ty::FreshTy(0));
|
||||||
@ -410,13 +414,10 @@ impl<'tcx> PlaceBuilder<'tcx> {
|
|||||||
fn compute_field_ty(
|
fn compute_field_ty(
|
||||||
cx: &Builder<'_, 'tcx>,
|
cx: &Builder<'_, 'tcx>,
|
||||||
field: Field,
|
field: Field,
|
||||||
base_place: PlaceBuilder<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
|
variant_index: Option<VariantIdx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let field_idx = field.as_usize();
|
let field_idx = field.as_usize();
|
||||||
let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
|
|
||||||
let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
|
|
||||||
debug!(?base_ty);
|
|
||||||
|
|
||||||
let field_ty = match base_ty.kind() {
|
let field_ty = match base_ty.kind() {
|
||||||
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
||||||
let variant_idx = variant_index.unwrap();
|
let variant_idx = variant_index.unwrap();
|
||||||
@ -479,41 +480,38 @@ impl<'tcx> PlaceBuilder<'tcx> {
|
|||||||
/// contains the projections of the captured upvar and `upvar_projection` the
|
/// contains the projections of the captured upvar and `upvar_projection` the
|
||||||
/// projections that are applied to the captured upvar. The main purpose of this
|
/// projections that are applied to the captured upvar. The main purpose of this
|
||||||
/// function is to figure out the `Ty`s of the field projections in `upvar_projection`.
|
/// function is to figure out the `Ty`s of the field projections in `upvar_projection`.
|
||||||
#[instrument(skip(cx, local))]
|
#[instrument(skip(cx, local, upvar_projection))]
|
||||||
fn construct_local_place_builder(
|
fn construct_local_place_builder(
|
||||||
cx: &Builder<'_, 'tcx>,
|
cx: &Builder<'_, 'tcx>,
|
||||||
local: Local,
|
local: Local,
|
||||||
mut local_projection: Vec<PlaceElem<'tcx>>,
|
local_projection: &[PlaceElem<'tcx>],
|
||||||
upvar_projection: Vec<UpvarProjectionElem<'tcx>>,
|
upvar_projection: impl Iterator<Item = UpvarProjectionElem<'tcx>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use
|
// We maintain a `Ty` to which we apply a projection in each iteration over `upvar_projection`.
|
||||||
// the ancestor projections, i.e. those projection elements that come before the field projection,
|
// This `ancestor_ty` let's us infer the field type whenever we encounter a
|
||||||
// to get the `Ty` for the field.
|
// `ProjectionElem::Field`.
|
||||||
|
let (mut ancestor_ty, mut opt_variant_idx) =
|
||||||
|
local_projections_to_ty(cx, local, local_projection);
|
||||||
|
|
||||||
for proj in upvar_projection.iter() {
|
// We add all projection elements we encounter to this `Vec`.
|
||||||
debug!("proj: {:?}, local_projection: {:?}", proj, local_projection);
|
let mut local_projection = local_projection.to_vec();
|
||||||
match *proj {
|
|
||||||
|
for (i, proj) in upvar_projection.enumerate() {
|
||||||
|
debug!("i: {:?}, proj: {:?}, local_projection: {:?}", i, proj, local_projection);
|
||||||
|
match proj {
|
||||||
ProjectionElem::Field(field, _) => {
|
ProjectionElem::Field(field, _) => {
|
||||||
let ancestor_proj = local_projection.to_vec();
|
let field_ty =
|
||||||
let base_place = PlaceBuilder::Local(local, ancestor_proj);
|
PlaceBuilder::compute_field_ty(cx, field, ancestor_ty, opt_variant_idx);
|
||||||
let field_ty = PlaceBuilder::compute_field_ty(cx, field, base_place);
|
|
||||||
debug!(?field_ty);
|
debug!(?field_ty);
|
||||||
|
|
||||||
local_projection.push(ProjectionElem::Field(field, field_ty));
|
local_projection.push(ProjectionElem::Field(field, field_ty));
|
||||||
debug!(?local_projection);
|
ancestor_ty = field_ty;
|
||||||
|
opt_variant_idx = None;
|
||||||
}
|
}
|
||||||
ProjectionElem::Deref => local_projection.push(ProjectionElem::Deref),
|
_ => {
|
||||||
ProjectionElem::Index(idx) => local_projection.push(ProjectionElem::Index(idx)),
|
let proj = upvar_proj_to_place_elem_no_field_proj(proj);
|
||||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => local_projection
|
(ancestor_ty, opt_variant_idx) = project_ty(cx.tcx, ancestor_ty, proj);
|
||||||
.push(ProjectionElem::ConstantIndex { offset, min_length, from_end }),
|
local_projection.push(proj);
|
||||||
ProjectionElem::Subslice { from, to, from_end } => {
|
|
||||||
local_projection.push(ProjectionElem::Subslice { from, to, from_end })
|
|
||||||
}
|
|
||||||
ProjectionElem::Downcast(sym, variant_idx) => {
|
|
||||||
local_projection.push(ProjectionElem::Downcast(sym, variant_idx))
|
|
||||||
}
|
|
||||||
ProjectionElem::OpaqueCast(ty) => {
|
|
||||||
local_projection.push(ProjectionElem::OpaqueCast(ty))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,6 +532,81 @@ impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn project_ty<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
elem: PlaceElem<'tcx>,
|
||||||
|
) -> (Ty<'tcx>, Option<VariantIdx>) {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Deref => {
|
||||||
|
let updated_ty = ty
|
||||||
|
.builtin_deref(true)
|
||||||
|
.unwrap_or_else(|| bug!("deref projection of non-dereferenceable ty {:?}", ty))
|
||||||
|
.ty;
|
||||||
|
|
||||||
|
(updated_ty, None)
|
||||||
|
}
|
||||||
|
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
|
||||||
|
(ty.builtin_index().unwrap(), None)
|
||||||
|
}
|
||||||
|
ProjectionElem::Subslice { from, to, from_end } => {
|
||||||
|
let ty = match ty.kind() {
|
||||||
|
ty::Slice(..) => ty,
|
||||||
|
ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
|
||||||
|
ty::Array(inner, size) if from_end => {
|
||||||
|
let size = size.eval_usize(tcx, ty::ParamEnv::empty());
|
||||||
|
let len = size - (from as u64) - (to as u64);
|
||||||
|
tcx.mk_array(*inner, len)
|
||||||
|
}
|
||||||
|
_ => bug!("cannot subslice non-array type: `{:?}`", ty),
|
||||||
|
};
|
||||||
|
|
||||||
|
(ty, None)
|
||||||
|
}
|
||||||
|
ProjectionElem::Downcast(_, variant_idx) => (ty, Some(variant_idx)),
|
||||||
|
ProjectionElem::Field(_, ty) => {
|
||||||
|
if matches!(ty.kind(), ty::Infer(..)) {
|
||||||
|
bug!("Field ty should have been resolved");
|
||||||
|
}
|
||||||
|
|
||||||
|
(ty, None)
|
||||||
|
}
|
||||||
|
ProjectionElem::OpaqueCast(..) => bug!("didn't expect OpaqueCast"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_projections_to_ty<'a, 'tcx>(
|
||||||
|
cx: &'a Builder<'a, 'tcx>,
|
||||||
|
local: Local,
|
||||||
|
projection: &'a [PlaceElem<'tcx>],
|
||||||
|
) -> (Ty<'tcx>, Option<VariantIdx>) {
|
||||||
|
let local_ty = cx.local_decls.local_decls()[local].ty;
|
||||||
|
projection.iter().fold((local_ty, None), |ty_variant_idx, elem| {
|
||||||
|
let ty = ty_variant_idx.0;
|
||||||
|
project_ty(cx.tcx, ty, *elem)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts an `UpvarProjectionElem` to `PlaceElem`, ICE'ing when being passed a
|
||||||
|
// field projection.
|
||||||
|
fn upvar_proj_to_place_elem_no_field_proj<'tcx>(
|
||||||
|
upvar_proj: UpvarProjectionElem<'tcx>,
|
||||||
|
) -> PlaceElem<'tcx> {
|
||||||
|
match upvar_proj {
|
||||||
|
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||||
|
ProjectionElem::Index(i) => ProjectionElem::Index(i),
|
||||||
|
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||||
|
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||||
|
}
|
||||||
|
ProjectionElem::Subslice { from, to, from_end } => {
|
||||||
|
ProjectionElem::Subslice { from, to, from_end }
|
||||||
|
}
|
||||||
|
ProjectionElem::Downcast(ty, variant_idx) => ProjectionElem::Downcast(ty, variant_idx),
|
||||||
|
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
|
||||||
|
ProjectionElem::Field(..) => bug!("should not be called with `ProjectionElem::Field`"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Compile `expr`, yielding a place that we can move from etc.
|
/// Compile `expr`, yielding a place that we can move from etc.
|
||||||
///
|
///
|
||||||
|
Loading…
x
Reference in New Issue
Block a user