Skip to content

Commit dc93a28

Browse files
committed
reduce allocations
1 parent 9061ffb commit dc93a28

File tree

1 file changed

+111
-38
lines changed

1 file changed

+111
-38
lines changed

compiler/rustc_mir_build/src/build/expr/as_place.rs

+111-38
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ fn to_upvars_resolved_place_builder<'tcx>(
218218
let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder(
219219
cx,
220220
upvar_resolved_local,
221-
local_projection.to_vec(),
221+
local_projection.as_slice(),
222222
upvar_projection,
223223
);
224224

@@ -266,7 +266,7 @@ fn strip_prefix<'a, 'tcx>(
266266
mut base_ty: Ty<'tcx>,
267267
projections: &'a [UpvarProjectionElem<'tcx>],
268268
prefix_projections: &[HirProjection<'tcx>],
269-
) -> Vec<UpvarProjectionElem<'tcx>> {
269+
) -> impl Iterator<Item = UpvarProjectionElem<'tcx>> + 'a {
270270
let mut iter = projections
271271
.iter()
272272
// Filter out opaque casts, they are unnecessary in the prefix.
@@ -293,7 +293,7 @@ fn strip_prefix<'a, 'tcx>(
293293
base_ty = projection.ty;
294294
}
295295

296-
iter.collect::<Vec<_>>()
296+
iter
297297
}
298298

299299
impl<'tcx> PlaceBuilder<'tcx> {
@@ -342,10 +342,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
342342

343343
#[instrument(skip(cx), level = "debug")]
344344
pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self {
345-
let field_ty = match self {
346-
PlaceBuilder::Local(..) => {
347-
let base_place = self.clone();
348-
PlaceBuilder::compute_field_ty(cx, f, base_place)
345+
let field_ty = match self.clone() {
346+
PlaceBuilder::Local(local, projection) => {
347+
let base_place = PlaceBuilder::Local(local, projection);
348+
let PlaceTy { ty, variant_index } =
349+
base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
350+
let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
351+
352+
PlaceBuilder::compute_field_ty(cx, f, base_ty, variant_index)
349353
}
350354
PlaceBuilder::UpVar(..) => {
351355
let dummy_ty = cx.tcx.mk_ty_infer(ty::FreshTy(0));
@@ -410,13 +414,10 @@ impl<'tcx> PlaceBuilder<'tcx> {
410414
fn compute_field_ty(
411415
cx: &Builder<'_, 'tcx>,
412416
field: Field,
413-
base_place: PlaceBuilder<'tcx>,
417+
base_ty: Ty<'tcx>,
418+
variant_index: Option<VariantIdx>,
414419
) -> Ty<'tcx> {
415420
let field_idx = field.as_usize();
416-
let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
417-
let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
418-
debug!(?base_ty);
419-
420421
let field_ty = match base_ty.kind() {
421422
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
422423
let variant_idx = variant_index.unwrap();
@@ -479,41 +480,38 @@ impl<'tcx> PlaceBuilder<'tcx> {
479480
/// contains the projections of the captured upvar and `upvar_projection` the
480481
/// projections that are applied to the captured upvar. The main purpose of this
481482
/// function is to figure out the `Ty`s of the field projections in `upvar_projection`.
482-
#[instrument(skip(cx, local))]
483+
#[instrument(skip(cx, local, upvar_projection))]
483484
fn construct_local_place_builder(
484485
cx: &Builder<'_, 'tcx>,
485486
local: Local,
486-
mut local_projection: Vec<PlaceElem<'tcx>>,
487-
upvar_projection: Vec<UpvarProjectionElem<'tcx>>,
487+
local_projection: &[PlaceElem<'tcx>],
488+
upvar_projection: impl Iterator<Item = UpvarProjectionElem<'tcx>>,
488489
) -> Self {
489-
// We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use
490-
// the ancestor projections, i.e. those projection elements that come before the field projection,
491-
// to get the `Ty` for the field.
492-
493-
for proj in upvar_projection.iter() {
494-
debug!("proj: {:?}, local_projection: {:?}", proj, local_projection);
495-
match *proj {
490+
// We maintain a `Ty` to which we apply a projection in each iteration over `upvar_projection`.
491+
// This `ancestor_ty` let's us infer the field type whenever we encounter a
492+
// `ProjectionElem::Field`.
493+
let (mut ancestor_ty, mut opt_variant_idx) =
494+
local_projections_to_ty(cx, local, local_projection);
495+
496+
// We add all projection elements we encounter to this `Vec`.
497+
let mut local_projection = local_projection.to_vec();
498+
499+
for (i, proj) in upvar_projection.enumerate() {
500+
debug!("i: {:?}, proj: {:?}, local_projection: {:?}", i, proj, local_projection);
501+
match proj {
496502
ProjectionElem::Field(field, _) => {
497-
let ancestor_proj = local_projection.to_vec();
498-
let base_place = PlaceBuilder::Local(local, ancestor_proj);
499-
let field_ty = PlaceBuilder::compute_field_ty(cx, field, base_place);
503+
let field_ty =
504+
PlaceBuilder::compute_field_ty(cx, field, ancestor_ty, opt_variant_idx);
500505
debug!(?field_ty);
501506

502507
local_projection.push(ProjectionElem::Field(field, field_ty));
503-
debug!(?local_projection);
504-
}
505-
ProjectionElem::Deref => local_projection.push(ProjectionElem::Deref),
506-
ProjectionElem::Index(idx) => local_projection.push(ProjectionElem::Index(idx)),
507-
ProjectionElem::ConstantIndex { offset, min_length, from_end } => local_projection
508-
.push(ProjectionElem::ConstantIndex { offset, min_length, from_end }),
509-
ProjectionElem::Subslice { from, to, from_end } => {
510-
local_projection.push(ProjectionElem::Subslice { from, to, from_end })
508+
ancestor_ty = field_ty;
509+
opt_variant_idx = None;
511510
}
512-
ProjectionElem::Downcast(sym, variant_idx) => {
513-
local_projection.push(ProjectionElem::Downcast(sym, variant_idx))
514-
}
515-
ProjectionElem::OpaqueCast(ty) => {
516-
local_projection.push(ProjectionElem::OpaqueCast(ty))
511+
_ => {
512+
let proj = upvar_proj_to_place_elem_no_field_proj(proj);
513+
(ancestor_ty, opt_variant_idx) = project_ty(cx.tcx, ancestor_ty, proj);
514+
local_projection.push(proj);
517515
}
518516
}
519517
}
@@ -534,6 +532,81 @@ impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
534532
}
535533
}
536534

535+
fn project_ty<'tcx>(
536+
tcx: TyCtxt<'tcx>,
537+
ty: Ty<'tcx>,
538+
elem: PlaceElem<'tcx>,
539+
) -> (Ty<'tcx>, Option<VariantIdx>) {
540+
match elem {
541+
ProjectionElem::Deref => {
542+
let updated_ty = ty
543+
.builtin_deref(true)
544+
.unwrap_or_else(|| bug!("deref projection of non-dereferenceable ty {:?}", ty))
545+
.ty;
546+
547+
(updated_ty, None)
548+
}
549+
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
550+
(ty.builtin_index().unwrap(), None)
551+
}
552+
ProjectionElem::Subslice { from, to, from_end } => {
553+
let ty = match ty.kind() {
554+
ty::Slice(..) => ty,
555+
ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
556+
ty::Array(inner, size) if from_end => {
557+
let size = size.eval_usize(tcx, ty::ParamEnv::empty());
558+
let len = size - (from as u64) - (to as u64);
559+
tcx.mk_array(*inner, len)
560+
}
561+
_ => bug!("cannot subslice non-array type: `{:?}`", ty),
562+
};
563+
564+
(ty, None)
565+
}
566+
ProjectionElem::Downcast(_, variant_idx) => (ty, Some(variant_idx)),
567+
ProjectionElem::Field(_, ty) => {
568+
if matches!(ty.kind(), ty::Infer(..)) {
569+
bug!("Field ty should have been resolved");
570+
}
571+
572+
(ty, None)
573+
}
574+
ProjectionElem::OpaqueCast(..) => bug!("didn't expect OpaqueCast"),
575+
}
576+
}
577+
578+
fn local_projections_to_ty<'a, 'tcx>(
579+
cx: &'a Builder<'a, 'tcx>,
580+
local: Local,
581+
projection: &'a [PlaceElem<'tcx>],
582+
) -> (Ty<'tcx>, Option<VariantIdx>) {
583+
let local_ty = cx.local_decls.local_decls()[local].ty;
584+
projection.iter().fold((local_ty, None), |ty_variant_idx, elem| {
585+
let ty = ty_variant_idx.0;
586+
project_ty(cx.tcx, ty, *elem)
587+
})
588+
}
589+
590+
// Converts an `UpvarProjectionElem` to `PlaceElem`, ICE'ing when being passed a
591+
// field projection.
592+
fn upvar_proj_to_place_elem_no_field_proj<'tcx>(
593+
upvar_proj: UpvarProjectionElem<'tcx>,
594+
) -> PlaceElem<'tcx> {
595+
match upvar_proj {
596+
ProjectionElem::Deref => ProjectionElem::Deref,
597+
ProjectionElem::Index(i) => ProjectionElem::Index(i),
598+
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
599+
ProjectionElem::ConstantIndex { offset, min_length, from_end }
600+
}
601+
ProjectionElem::Subslice { from, to, from_end } => {
602+
ProjectionElem::Subslice { from, to, from_end }
603+
}
604+
ProjectionElem::Downcast(ty, variant_idx) => ProjectionElem::Downcast(ty, variant_idx),
605+
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
606+
ProjectionElem::Field(..) => bug!("should not be called with `ProjectionElem::Field`"),
607+
}
608+
}
609+
537610
impl<'a, 'tcx> Builder<'a, 'tcx> {
538611
/// Compile `expr`, yielding a place that we can move from etc.
539612
///

0 commit comments

Comments
 (0)