Skip to content

Commit f015842

Browse files
committed
properly handle enum field projections
1 parent 906c527 commit f015842

File tree

3 files changed

+35
-49
lines changed

3 files changed

+35
-49
lines changed

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

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_hir::def_id::LocalDefId;
77
use rustc_middle::hir::place::Projection as HirProjection;
88
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
99
use rustc_middle::middle::region;
10+
use rustc_middle::mir::tcx::PlaceTy;
1011
use rustc_middle::mir::AssertKind::BoundsCheck;
1112
use rustc_middle::mir::*;
1213
use rustc_middle::thir::*;
@@ -324,56 +325,35 @@ impl<'tcx> PlaceBuilder<'tcx> {
324325
}
325326
}
326327

327-
pub fn try_ty<D>(&self, local_decls: &D, cx: &Builder<'_, 'tcx>) -> Option<Ty<'tcx>>
328+
pub fn try_compute_ty<D>(
329+
&self,
330+
local_decls: &D,
331+
cx: &Builder<'_, 'tcx>,
332+
) -> Option<PlaceTy<'tcx>>
328333
where
329334
D: HasLocalDecls<'tcx>,
330335
{
331-
let tcx = cx.tcx;
332-
333-
let project_ty = |ty: Ty<'tcx>, elem: &PlaceElem<'tcx>| -> Ty<'tcx> {
334-
match elem {
335-
ProjectionElem::Deref => {
336-
ty.builtin_deref(true)
337-
.unwrap_or_else(|| {
338-
bug!("deref projection of non-dereferenceable ty {:?}", ty)
339-
})
340-
.ty
341-
}
342-
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
343-
ty.builtin_index().unwrap()
344-
}
345-
ProjectionElem::Subslice { from, to, from_end } => match ty.kind() {
346-
ty::Slice(..) => ty,
347-
ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
348-
ty::Array(inner, size) if *from_end => {
349-
let size = size.eval_usize(tcx, ty::ParamEnv::empty());
350-
let len = size - (*from as u64) - (*to as u64);
351-
tcx.mk_array(*inner, len)
352-
}
353-
_ => bug!("cannot subslice non-array type: `{:?}`", ty),
354-
},
355-
ProjectionElem::Downcast(..) => ty,
356-
ProjectionElem::Field(_, ty) | ProjectionElem::OpaqueCast(ty) => *ty,
357-
}
358-
};
359-
360336
match self.base {
361-
PlaceBase::Local(local) => {
362-
let base_ty = local_decls.local_decls()[local].ty;
363-
Some(self.projection.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)))
364-
}
337+
PlaceBase::Local(_) => Some(self.clone().into_place(cx).ty(local_decls, cx.tcx)),
365338
PlaceBase::Upvar { .. } => {
366339
match to_upvars_resolved_place_builder(self.clone(), cx) {
367340
Ok(resolved_place_builder) => {
368341
// `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok
369-
resolved_place_builder.try_ty(local_decls, cx)
342+
resolved_place_builder.try_compute_ty(local_decls, cx)
370343
}
371344
Err(place_builder) => {
372345
match &place_builder.projection[..] {
373-
&[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => Some(
374-
projections.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)),
375-
),
346+
&[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => {
347+
let place_ty = projections
348+
.iter()
349+
.fold(PlaceTy::from_ty(base_ty), |place_ty, &elem| {
350+
place_ty.projection_ty(cx.tcx, elem)
351+
});
352+
353+
debug!(?place_ty);
376354

355+
Some(place_ty)
356+
}
377357
_ => None, // would need a base `Ty` for these
378358
}
379359
}

compiler/rustc_mir_build/src/build/matches/simplify.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
272272
|| !adt_def.is_variant_list_non_exhaustive());
273273
if irrefutable {
274274
let place_builder = match_pair.place.downcast(adt_def, variant_index);
275-
candidate
276-
.match_pairs
277-
.extend(self.field_match_pairs(place_builder, subpatterns));
275+
let field_match_pairs =
276+
self.field_match_pairs(place_builder.clone(), subpatterns);
277+
candidate.match_pairs.extend(field_match_pairs);
278278
Ok(())
279279
} else {
280280
Err(match_pair)
@@ -294,9 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
294294

295295
PatKind::Leaf { ref subpatterns } => {
296296
// tuple struct, match subpats (if any)
297-
candidate
298-
.match_pairs
299-
.extend(self.field_match_pairs_tuple_struct(match_pair.place, subpatterns));
297+
candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
300298
Ok(())
301299
}
302300

compiler/rustc_mir_build/src/build/matches/util.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3131
place_builder: PlaceBuilder<'tcx>,
3232
subpatterns: &'pat [FieldPat<'tcx>],
3333
) -> Vec<MatchPair<'pat, 'tcx>> {
34-
let place_ty = place_builder
35-
.try_ty(&self.local_decls, self)
36-
.map(|ty| self.tcx.normalize_erasing_regions(self.param_env, ty));
37-
debug!(?place_ty);
34+
let place_ty_and_variant_idx =
35+
place_builder.try_compute_ty(&self.local_decls, self).map(|place_ty| {
36+
(
37+
self.tcx.normalize_erasing_regions(self.param_env, place_ty.ty),
38+
place_ty.variant_index,
39+
)
40+
});
41+
debug!(?place_ty_and_variant_idx);
3842

3943
subpatterns
4044
.iter()
@@ -43,9 +47,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4347
// during borrow-checking on higher-ranked types if we use the
4448
// ascribed type as the field type, so we try to get the actual field
4549
// type from the `Place`, if possible, see issue #96514
46-
let field_ty = if let Some(place_ty) = place_ty {
50+
let field_ty = if let Some((place_ty, opt_variant_idx)) = place_ty_and_variant_idx {
4751
let field_idx = fieldpat.field.as_usize();
4852
let field_ty = match place_ty.kind() {
53+
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
54+
let variant_idx = opt_variant_idx.unwrap();
55+
adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs)
56+
}
4957
ty::Adt(adt_def, substs) => {
5058
adt_def.all_fields().collect::<Vec<_>>()[field_idx].ty(self.tcx, substs)
5159
}

0 commit comments

Comments
 (0)