Allow destructuring opaque types, since the patterns constrain the opaque types
This commit is contained in:
parent
12457f814c
commit
728c7e8bda
14 changed files with 116 additions and 31 deletions
|
@ -7,6 +7,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
|||
use rustc_middle::hir::place::Projection as HirProjection;
|
||||
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::AssertKind::BoundsCheck;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::*;
|
||||
|
@ -104,8 +105,9 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
|
|||
variant = Some(*idx);
|
||||
continue;
|
||||
}
|
||||
// These do not affect anything, they just make sure we know the right type.
|
||||
ProjectionElem::OpaqueCast(_) => continue,
|
||||
ProjectionElem::Index(..)
|
||||
| ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {
|
||||
// We don't capture array-access projections.
|
||||
|
@ -297,16 +299,21 @@ fn strip_prefix<'tcx>(
|
|||
prefix_projections: &[HirProjection<'tcx>],
|
||||
) -> impl Iterator<Item = PlaceElem<'tcx>> {
|
||||
let mut iter = projections.into_iter();
|
||||
let mut next = || match iter.next()? {
|
||||
// Filter out opaque casts, they are unnecessary in the prefix.
|
||||
ProjectionElem::OpaqueCast(..) => iter.next(),
|
||||
other => Some(other),
|
||||
};
|
||||
for projection in prefix_projections {
|
||||
match projection.kind {
|
||||
HirProjectionKind::Deref => {
|
||||
assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
|
||||
assert!(matches!(next(), Some(ProjectionElem::Deref)));
|
||||
}
|
||||
HirProjectionKind::Field(..) => {
|
||||
if base_ty.is_enum() {
|
||||
assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
|
||||
assert!(matches!(next(), Some(ProjectionElem::Downcast(..))));
|
||||
}
|
||||
assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
|
||||
assert!(matches!(next(), Some(ProjectionElem::Field(..))));
|
||||
}
|
||||
HirProjectionKind::Index | HirProjectionKind::Subslice => {
|
||||
bug!("unexpected projection kind: {:?}", projection);
|
||||
|
@ -320,7 +327,23 @@ fn strip_prefix<'tcx>(
|
|||
impl<'tcx> PlaceBuilder<'tcx> {
|
||||
pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
|
||||
if let PlaceBase::Local(local) = self.base {
|
||||
Place { local, projection: cx.tcx.intern_place_elems(&self.projection) }
|
||||
let mut projections = vec![];
|
||||
let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty);
|
||||
for projection in self.projection {
|
||||
// Only preserve those opaque casts that actually go from an opaque type
|
||||
// to another type.
|
||||
if let ProjectionElem::OpaqueCast(t) = projection {
|
||||
if let ty::Opaque(..) = ty.ty.kind() {
|
||||
if t != ty.ty {
|
||||
projections.push(ProjectionElem::OpaqueCast(t));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
projections.push(projection);
|
||||
}
|
||||
ty = ty.projection_ty(cx.tcx, projection);
|
||||
}
|
||||
Place { local, projection: cx.tcx.intern_place_elems(&projections) }
|
||||
} else {
|
||||
self.expect_upvars_resolved(cx).into_place(cx)
|
||||
}
|
||||
|
|
|
@ -867,7 +867,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
|
|||
Candidate {
|
||||
span: pattern.span,
|
||||
has_guard,
|
||||
match_pairs: smallvec![MatchPair { place, pattern }],
|
||||
match_pairs: smallvec![MatchPair::new(place, pattern)],
|
||||
bindings: Vec::new(),
|
||||
ascriptions: Vec::new(),
|
||||
subcandidates: Vec::new(),
|
||||
|
|
|
@ -98,6 +98,10 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
|||
place: PlaceBuilder<'tcx>,
|
||||
pattern: &'pat Pat<'tcx>,
|
||||
) -> MatchPair<'pat, 'tcx> {
|
||||
// Force the place type to the pattern's type.
|
||||
// FIXME(oli-obk): only do this when we don't already know the place type.
|
||||
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
|
||||
let place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
|
||||
MatchPair { place, pattern }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -967,7 +967,11 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
|
||||
// In case we're matching on an opaque type in its defining scope, the patterns define the hidden type.
|
||||
// The wildcard pattern needs to have the same type, otherwise it will always be deemed useful, even if the
|
||||
// match is exhaustive for the pattern type.
|
||||
let wild_ty = arms.first().map_or(scrut_ty, |arm| arm.pat.ty());
|
||||
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(wild_ty));
|
||||
let v = PatStack::from_pattern(wild_pattern);
|
||||
let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true);
|
||||
let non_exhaustiveness_witnesses = match usefulness {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue