properly handle enum field projections
This commit is contained in:
parent
906c52743a
commit
f015842ed2
3 changed files with 35 additions and 49 deletions
|
@ -7,6 +7,7 @@ use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_middle::hir::place::Projection as HirProjection;
|
use rustc_middle::hir::place::Projection as HirProjection;
|
||||||
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
|
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::AssertKind::BoundsCheck;
|
use rustc_middle::mir::AssertKind::BoundsCheck;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::thir::*;
|
use rustc_middle::thir::*;
|
||||||
|
@ -324,56 +325,35 @@ impl<'tcx> PlaceBuilder<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_ty<D>(&self, local_decls: &D, cx: &Builder<'_, 'tcx>) -> Option<Ty<'tcx>>
|
pub fn try_compute_ty<D>(
|
||||||
|
&self,
|
||||||
|
local_decls: &D,
|
||||||
|
cx: &Builder<'_, 'tcx>,
|
||||||
|
) -> Option<PlaceTy<'tcx>>
|
||||||
where
|
where
|
||||||
D: HasLocalDecls<'tcx>,
|
D: HasLocalDecls<'tcx>,
|
||||||
{
|
{
|
||||||
let tcx = cx.tcx;
|
|
||||||
|
|
||||||
let project_ty = |ty: Ty<'tcx>, elem: &PlaceElem<'tcx>| -> Ty<'tcx> {
|
|
||||||
match elem {
|
|
||||||
ProjectionElem::Deref => {
|
|
||||||
ty.builtin_deref(true)
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
bug!("deref projection of non-dereferenceable ty {:?}", ty)
|
|
||||||
})
|
|
||||||
.ty
|
|
||||||
}
|
|
||||||
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
|
|
||||||
ty.builtin_index().unwrap()
|
|
||||||
}
|
|
||||||
ProjectionElem::Subslice { from, to, from_end } => 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),
|
|
||||||
},
|
|
||||||
ProjectionElem::Downcast(..) => ty,
|
|
||||||
ProjectionElem::Field(_, ty) | ProjectionElem::OpaqueCast(ty) => *ty,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match self.base {
|
match self.base {
|
||||||
PlaceBase::Local(local) => {
|
PlaceBase::Local(_) => Some(self.clone().into_place(cx).ty(local_decls, cx.tcx)),
|
||||||
let base_ty = local_decls.local_decls()[local].ty;
|
|
||||||
Some(self.projection.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)))
|
|
||||||
}
|
|
||||||
PlaceBase::Upvar { .. } => {
|
PlaceBase::Upvar { .. } => {
|
||||||
match to_upvars_resolved_place_builder(self.clone(), cx) {
|
match to_upvars_resolved_place_builder(self.clone(), cx) {
|
||||||
Ok(resolved_place_builder) => {
|
Ok(resolved_place_builder) => {
|
||||||
// `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok
|
// `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok
|
||||||
resolved_place_builder.try_ty(local_decls, cx)
|
resolved_place_builder.try_compute_ty(local_decls, cx)
|
||||||
}
|
}
|
||||||
Err(place_builder) => {
|
Err(place_builder) => {
|
||||||
match &place_builder.projection[..] {
|
match &place_builder.projection[..] {
|
||||||
&[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => Some(
|
&[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => {
|
||||||
projections.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)),
|
let place_ty = projections
|
||||||
),
|
.iter()
|
||||||
|
.fold(PlaceTy::from_ty(base_ty), |place_ty, &elem| {
|
||||||
|
place_ty.projection_ty(cx.tcx, elem)
|
||||||
|
});
|
||||||
|
|
||||||
|
debug!(?place_ty);
|
||||||
|
|
||||||
|
Some(place_ty)
|
||||||
|
}
|
||||||
_ => None, // would need a base `Ty` for these
|
_ => None, // would need a base `Ty` for these
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,9 +272,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|| !adt_def.is_variant_list_non_exhaustive());
|
|| !adt_def.is_variant_list_non_exhaustive());
|
||||||
if irrefutable {
|
if irrefutable {
|
||||||
let place_builder = match_pair.place.downcast(adt_def, variant_index);
|
let place_builder = match_pair.place.downcast(adt_def, variant_index);
|
||||||
candidate
|
let field_match_pairs =
|
||||||
.match_pairs
|
self.field_match_pairs(place_builder.clone(), subpatterns);
|
||||||
.extend(self.field_match_pairs(place_builder, subpatterns));
|
candidate.match_pairs.extend(field_match_pairs);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(match_pair)
|
Err(match_pair)
|
||||||
|
@ -294,9 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
PatKind::Leaf { ref subpatterns } => {
|
PatKind::Leaf { ref subpatterns } => {
|
||||||
// tuple struct, match subpats (if any)
|
// tuple struct, match subpats (if any)
|
||||||
candidate
|
candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
|
||||||
.match_pairs
|
|
||||||
.extend(self.field_match_pairs_tuple_struct(match_pair.place, subpatterns));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
place_builder: PlaceBuilder<'tcx>,
|
place_builder: PlaceBuilder<'tcx>,
|
||||||
subpatterns: &'pat [FieldPat<'tcx>],
|
subpatterns: &'pat [FieldPat<'tcx>],
|
||||||
) -> Vec<MatchPair<'pat, 'tcx>> {
|
) -> Vec<MatchPair<'pat, 'tcx>> {
|
||||||
let place_ty = place_builder
|
let place_ty_and_variant_idx =
|
||||||
.try_ty(&self.local_decls, self)
|
place_builder.try_compute_ty(&self.local_decls, self).map(|place_ty| {
|
||||||
.map(|ty| self.tcx.normalize_erasing_regions(self.param_env, ty));
|
(
|
||||||
debug!(?place_ty);
|
self.tcx.normalize_erasing_regions(self.param_env, place_ty.ty),
|
||||||
|
place_ty.variant_index,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
debug!(?place_ty_and_variant_idx);
|
||||||
|
|
||||||
subpatterns
|
subpatterns
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -43,9 +47,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// during borrow-checking on higher-ranked types if we use the
|
// during borrow-checking on higher-ranked types if we use the
|
||||||
// ascribed type as the field type, so we try to get the actual field
|
// ascribed type as the field type, so we try to get the actual field
|
||||||
// type from the `Place`, if possible, see issue #96514
|
// type from the `Place`, if possible, see issue #96514
|
||||||
let field_ty = if let Some(place_ty) = place_ty {
|
let field_ty = if let Some((place_ty, opt_variant_idx)) = place_ty_and_variant_idx {
|
||||||
let field_idx = fieldpat.field.as_usize();
|
let field_idx = fieldpat.field.as_usize();
|
||||||
let field_ty = match place_ty.kind() {
|
let field_ty = match place_ty.kind() {
|
||||||
|
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
||||||
|
let variant_idx = opt_variant_idx.unwrap();
|
||||||
|
adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs)
|
||||||
|
}
|
||||||
ty::Adt(adt_def, substs) => {
|
ty::Adt(adt_def, substs) => {
|
||||||
adt_def.all_fields().collect::<Vec<_>>()[field_idx].ty(self.tcx, substs)
|
adt_def.all_fields().collect::<Vec<_>>()[field_idx].ty(self.tcx, substs)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue