Skip to content

Commit f1e56c6

Browse files
committed
Remove all matching on Ty from deconstruct_pat
1 parent c4f840d commit f1e56c6

File tree

2 files changed

+88
-90
lines changed

2 files changed

+88
-90
lines changed

compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

+27-69
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,10 @@ use super::usefulness::{MatchCheckCtxt, PatCtxt};
4949

5050
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
5151
use rustc_data_structures::captures::Captures;
52-
use rustc_index::vec::Idx;
5352

5453
use rustc_hir::{HirId, RangeEnd};
5554
use rustc_middle::ty::subst::GenericArg;
56-
use rustc_middle::ty::{self, Ty};
55+
use rustc_middle::ty::Ty;
5756
use rustc_span::{Span, DUMMY_SP};
5857
use rustc_target::abi::VariantIdx;
5958

@@ -93,16 +92,6 @@ impl IntRange {
9392
(*self.range.start(), *self.range.end())
9493
}
9594

96-
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
97-
#[inline]
98-
fn signed_bias(ty: Ty<'_>, ty_size: rustc_target::abi::Size) -> u128 {
99-
match *ty.kind() {
100-
ty::Int(_) => 1u128 << (ty_size.bits() as u128 - 1),
101-
ty::Char | ty::Uint(_) => 0,
102-
_ => bug!("invalid type for `IntRange`: {}", ty),
103-
}
104-
}
105-
10695
#[inline]
10796
pub(super) fn from_bits<'tcx>(
10897
ty: Ty<'tcx>,
@@ -111,7 +100,11 @@ impl IntRange {
111100
hi: u128,
112101
end: &RangeEnd,
113102
) -> IntRange {
114-
let bias = IntRange::signed_bias(ty, ty_size);
103+
let bias = if MatchCheckCtxt::is_signed_int(ty) {
104+
1u128 << (ty_size.bits() as u128 - 1)
105+
} else {
106+
0
107+
};
115108
// Perform a shift if the underlying types are signed,
116109
// which makes the interval arithmetic simpler.
117110
let (lo, hi) = (lo ^ bias, hi ^ bias);
@@ -555,7 +548,7 @@ pub(super) enum Constructor<'tcx> {
555548
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
556549
Str(&'tcx [u8]),
557550
/// Array and slice patterns.
558-
Slice(Slice),
551+
Slice(Slice, Ty<'tcx>),
559552
/// Constants that must not be matched structurally. They are treated as black
560553
/// boxes for the purposes of exhaustiveness: we must not inspect them, and they
561554
/// don't count towards making a match exhaustive.
@@ -593,36 +586,19 @@ impl<'tcx> Constructor<'tcx> {
593586

594587
fn as_slice(&self) -> Option<Slice> {
595588
match self {
596-
Slice(slice) => Some(*slice),
589+
Slice(slice, _) => Some(*slice),
597590
_ => None,
598591
}
599592
}
600593

601-
pub(super) fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
602-
match *self {
603-
Variant(idx) => idx,
604-
Single => {
605-
assert!(!adt.is_enum());
606-
VariantIdx::new(0)
607-
}
608-
_ => bug!("bad constructor {:?} for adt {:?}", self, adt),
609-
}
610-
}
611-
612594
/// The number of fields for this constructor. This must be kept in sync with
613595
/// `Fields::wildcards`.
614596
pub(super) fn arity(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> usize {
615597
match self {
616-
Single | Variant(_) => match pcx.ty.kind() {
617-
ty::Adt(adt, ..) => {
618-
let variant = &adt.variants[self.variant_index_for_adt(adt)];
619-
pcx.cx.list_variant_nonhidden_fields(pcx.ty, variant).count()
620-
}
621-
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty),
622-
},
598+
Single | Variant(_) => pcx.cx.list_variant_nonhidden_fields(pcx.ty, self).count(),
623599
Tuple(fs) => fs.len(),
624600
Ref(_) | BoxPat(_) => 1,
625-
Slice(slice) => slice.arity(),
601+
Slice(slice, _) => slice.arity(),
626602
Str(..)
627603
| Bool(..)
628604
| IntRange(..)
@@ -671,11 +647,11 @@ impl<'tcx> Constructor<'tcx> {
671647
split_range.split(int_ranges.cloned());
672648
split_range.iter().map(IntRange).collect()
673649
}
674-
&Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => {
650+
&Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }, ty) => {
675651
let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len);
676652
let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind);
677653
split_self.split(slices);
678-
split_self.iter().map(Slice).collect()
654+
split_self.iter().map(|s| Slice(s, ty)).collect()
679655
}
680656
// Any other constructor can be used unchanged.
681657
_ => smallvec![self.clone()],
@@ -724,7 +700,7 @@ impl<'tcx> Constructor<'tcx> {
724700
}
725701
}
726702
(Str(self_val), Str(other_val)) => self_val == other_val,
727-
(Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
703+
(Slice(self_slice, _), Slice(other_slice, _)) => self_slice.is_covered_by(*other_slice),
728704

729705
// We are trying to inspect an opaque constant. Thus we skip the row.
730706
(Opaque, _) | (_, Opaque) => false,
@@ -765,7 +741,7 @@ impl<'tcx> Constructor<'tcx> {
765741
.iter()
766742
.filter_map(|c| c.as_int_range())
767743
.any(|other| range.is_covered_by(other)),
768-
Slice(slice) => used_ctors
744+
Slice(slice, _) => used_ctors
769745
.iter()
770746
.filter_map(|c| c.as_slice())
771747
.any(|other| slice.is_covered_by(other)),
@@ -866,8 +842,7 @@ impl<'tcx> SplitWildcard<'tcx> {
866842
//
867843
// The exception is: if we are at the top-level, for example in an empty match, we
868844
// sometimes prefer reporting the list of constructors instead of just `_`.
869-
let report_when_all_missing = pcx.is_top_level
870-
&& !matches!(pcx.ty.kind(), ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_));
845+
let report_when_all_missing = pcx.is_top_level && !MatchCheckCtxt::is_numeric(pcx.ty);
871846
let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing {
872847
if pcx.is_non_exhaustive {
873848
Missing {
@@ -953,23 +928,16 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
953928
constructor: &Constructor<'tcx>,
954929
) -> Self {
955930
let ret = match constructor {
956-
Single | Variant(_) => match ty.kind() {
957-
ty::Adt(adt, _) => {
958-
let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
959-
let tys = cx.list_variant_nonhidden_fields(ty, variant).map(|(_, ty)| ty);
960-
Fields::wildcards_from_tys(cx, tys)
961-
}
962-
_ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
963-
},
931+
Single | Variant(_) => {
932+
let tys = cx.list_variant_nonhidden_fields(ty, constructor).map(|(_, ty)| ty);
933+
Fields::wildcards_from_tys(cx, tys)
934+
}
964935
Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter().map(|ty| ty.expect_ty())),
965936
Ref(ty) | BoxPat(ty) => Fields::wildcards_from_tys(cx, once(*ty)),
966-
Slice(slice) => match *ty.kind() {
967-
ty::Slice(ty) | ty::Array(ty, _) => {
968-
let arity = slice.arity();
969-
Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
970-
}
971-
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
972-
},
937+
Slice(slice, ty) => {
938+
let arity = slice.arity();
939+
Fields::wildcards_from_tys(cx, (0..arity).map(|_| *ty))
940+
}
973941
Str(..)
974942
| Bool(..)
975943
| IntRange(..)
@@ -1068,7 +1036,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
10681036
// We return a wildcard for each field of `other_ctor`.
10691037
Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
10701038
}
1071-
(Slice(self_slice), Slice(other_slice))
1039+
(Slice(self_slice, inner_ty), Slice(other_slice, _))
10721040
if self_slice.arity() != other_slice.arity() =>
10731041
{
10741042
// The only tricky case: two slices of different arity. Since `self_slice` covers
@@ -1079,10 +1047,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
10791047
match self_slice.kind {
10801048
FixedLen(_) => bug!("{:?} doesn't cover {:?}", self_slice, other_slice),
10811049
VarLen(prefix, suffix) => {
1082-
let inner_ty = match *self.ty.kind() {
1083-
ty::Slice(ty) | ty::Array(ty, _) => ty,
1084-
_ => bug!("bad slice pattern {:?} {:?}", self.ctor, self.ty),
1085-
};
10861050
let prefix = &self.fields.fields[..prefix];
10871051
let suffix = &self.fields.fields[self_slice.arity() - suffix..];
10881052
let wildcard: &_ =
@@ -1143,14 +1107,8 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
11431107

11441108
match &self.ctor {
11451109
Single | Variant(_) | Tuple(_) => {
1146-
let variant = match self.ty.kind() {
1147-
ty::Adt(adt, _) => Some(&adt.variants[self.ctor.variant_index_for_adt(adt)]),
1148-
ty::Tuple(_) => None,
1149-
_ => unreachable!(),
1150-
};
1151-
1152-
if let Some(variant) = variant {
1153-
write!(f, "{}", variant.ident)?;
1110+
if let Some(ident) = MatchCheckCtxt::variant_ident(self.ty(), self.ctor()) {
1111+
write!(f, "{}", ident)?;
11541112
}
11551113

11561114
// Without `cx`, we can't know which field corresponds to which, so we can't
@@ -1171,7 +1129,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
11711129
let subpattern = self.iter_fields().next().unwrap();
11721130
write!(f, "box {:?}", subpattern)
11731131
}
1174-
Slice(slice) => {
1132+
Slice(slice, _) => {
11751133
let mut subpatterns = self.fields.iter_patterns();
11761134
write!(f, "[")?;
11771135
match slice.kind {

compiler/rustc_mir_build/src/thir/pattern/mod.rs

+61-21
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ use rustc_middle::mir::interpret::{
2424
};
2525
use rustc_middle::mir::{BorrowKind, Field, Mutability};
2626
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
27-
use rustc_middle::ty::{self, ConstKind, DefIdTree, Ty, TyCtxt, VariantDef};
27+
use rustc_middle::ty::{self, ConstKind, DefIdTree, Ty, TyCtxt};
2828
use rustc_span::{Span, DUMMY_SP};
29-
use rustc_target::abi::Size;
29+
use rustc_target::abi::{Size, VariantIdx};
3030

3131
use smallvec::{smallvec, SmallVec};
3232
use std::cmp::Ordering;
33+
use std::fmt::Display;
3334

3435
#[derive(Clone, Debug)]
3536
crate enum PatternError {
@@ -734,18 +735,21 @@ fn pat_to_deconstructed<'p, 'tcx>(
734735
fields = Fields::singleton(cx, DeconstructedPat::wildcard(inner_ty));
735736
}
736737
ty::Adt(adt, _) => {
737-
ctor = match pat.kind.as_ref() {
738-
PatKind::Leaf { .. } => Constructor::Single,
738+
let variant = match *pat.kind {
739+
PatKind::Leaf { .. } => {
740+
ctor = Constructor::Single;
741+
adt.non_enum_variant()
742+
}
739743
PatKind::Variant { variant_index, .. } => {
740-
Constructor::Variant(*variant_index)
744+
ctor = Constructor::Variant(variant_index);
745+
&adt.variants[variant_index]
741746
}
742747
_ => bug!(),
743748
};
744-
let variant = &adt.variants[ctor.variant_index_for_adt(adt)];
745749
// For each field in the variant, we store the relevant index into `self.fields` if any.
746750
let mut field_id_to_id: Vec<Option<usize>> =
747751
(0..variant.fields.len()).map(|_| None).collect();
748-
let tys = cx.list_variant_nonhidden_fields(pat.ty, variant).enumerate().map(
752+
let tys = cx.list_variant_nonhidden_fields(pat.ty, &ctor).enumerate().map(
749753
|(i, (field, ty))| {
750754
field_id_to_id[field.index()] = Some(i);
751755
ty
@@ -847,17 +851,19 @@ fn pat_to_deconstructed<'p, 'tcx>(
847851
fields = Fields::empty();
848852
}
849853
PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
850-
let array_len = match pat.ty.kind() {
851-
ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env) as usize),
852-
ty::Slice(_) => None,
854+
let (ty, array_len) = match pat.ty.kind() {
855+
ty::Array(ty, length) => {
856+
(ty, Some(length.eval_usize(cx.tcx, cx.param_env) as usize))
857+
}
858+
ty::Slice(ty) => (ty, None),
853859
_ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
854860
};
855861
let kind = if slice.is_some() {
856862
SliceKind::VarLen(prefix.len(), suffix.len())
857863
} else {
858864
SliceKind::FixedLen(prefix.len() + suffix.len())
859865
};
860-
ctor = Constructor::Slice(Slice::new(array_len, kind));
866+
ctor = Constructor::Slice(Slice::new(array_len, kind), ty);
861867
fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat));
862868
}
863869
PatKind::Or { .. } => {
@@ -893,10 +899,13 @@ fn deconstructed_to_pat<'p, 'tcx>(
893899
let kind = match pat.ctor() {
894900
Single | Variant(_) => match pat.ty().kind() {
895901
ty::Adt(adt_def, substs) => {
896-
let variant_index = pat.ctor().variant_index_for_adt(adt_def);
897-
let variant = &adt_def.variants[variant_index];
902+
let variant_index = match pat.ctor() {
903+
Variant(idx) => *idx,
904+
Single => VariantIdx::new(0),
905+
_ => bug!("bad constructor {:?} for adt", pat.ctor()),
906+
};
898907
let subpatterns = cx
899-
.list_variant_nonhidden_fields(pat.ty(), variant)
908+
.list_variant_nonhidden_fields(pat.ty(), pat.ctor())
900909
.zip(subpatterns)
901910
.map(|((field, _ty), pattern)| FieldPat { field, pattern })
902911
.collect();
@@ -920,7 +929,7 @@ fn deconstructed_to_pat<'p, 'tcx>(
920929
// string literal pattern will never be reported as a non-exhaustiveness witness, so we
921930
// ignore this issue.
922931
Ref(_) | BoxPat(_) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
923-
Slice(slice) => {
932+
Slice(slice, _) => {
924933
match slice.kind {
925934
SliceKind::FixedLen(_) => {
926935
PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
@@ -977,6 +986,14 @@ fn deconstructed_to_pat<'p, 'tcx>(
977986
}
978987

979988
impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
989+
fn is_numeric(ty: Ty<'tcx>) -> bool {
990+
matches!(ty.kind(), ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_))
991+
}
992+
993+
fn is_signed_int(ty: Ty<'tcx>) -> bool {
994+
matches!(ty.kind(), ty::Int(_))
995+
}
996+
980997
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
981998
if self.tcx.features().exhaustive_patterns {
982999
self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env)
@@ -1109,22 +1126,23 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
11091126
ty::Ref(_, ty, _) => smallvec![Ref(*ty)],
11101127
ty::Tuple(fs) => smallvec![Tuple(*fs)],
11111128
ty::Array(sub_ty, len) => {
1112-
match len.try_eval_usize(cx.tcx, cx.param_env) {
1129+
let slice = match len.try_eval_usize(cx.tcx, cx.param_env) {
11131130
Some(len) => {
11141131
// The uninhabited case is already handled.
1115-
smallvec![Slice(self::Slice::new(Some(len as usize), VarLen(0, 0)))]
1132+
self::Slice::new(Some(len as usize), VarLen(0, 0))
11161133
}
11171134
None => {
11181135
// Treat arrays of a constant but unknown length like slices.
11191136
let kind =
11201137
if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
1121-
smallvec![Slice(self::Slice::new(None, kind))]
1138+
self::Slice::new(None, kind)
11221139
}
1123-
}
1140+
};
1141+
smallvec![Slice(slice, sub_ty)]
11241142
}
11251143
ty::Slice(sub_ty) => {
11261144
let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
1127-
smallvec![Slice(self::Slice::new(None, kind))]
1145+
smallvec![Slice(self::Slice::new(None, kind), sub_ty)]
11281146
}
11291147
// If `exhaustive_patterns` is disabled and our scrutinee is the never type, we don't
11301148
// expose its emptiness and return `NonExhaustive` below. The exception is if the
@@ -1137,19 +1155,41 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
11371155
}
11381156
}
11391157

1158+
/// Show the name of the variant corresponding to this constructor.
1159+
/// `ty` must be `ty::Adt`, and `ctor` must be a constructor for that type.
1160+
fn variant_ident(ty: Ty<'tcx>, ctor: &Constructor<'tcx>) -> Option<impl Display> {
1161+
match ty.kind() {
1162+
ty::Adt(adt, _) => {
1163+
let variant = match ctor {
1164+
Constructor::Variant(idx) => &adt.variants[*idx],
1165+
Constructor::Single => adt.non_enum_variant(),
1166+
_ => return None,
1167+
};
1168+
Some(variant.ident)
1169+
}
1170+
_ => None,
1171+
}
1172+
}
1173+
11401174
/// List the fields for this variant.
11411175
/// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
11421176
/// uninhabited fields in order not to reveal the uninhabitedness of the whole variant.
1177+
/// `ty` must be `ty::Adt`, and `ctor` must be a constructor for that type.
11431178
fn list_variant_nonhidden_fields<'a>(
11441179
&'a self,
11451180
ty: Ty<'tcx>,
1146-
variant: &'a VariantDef,
1181+
ctor: &Constructor<'tcx>,
11471182
) -> impl Iterator<Item = (Field, Ty<'tcx>)> + Captures<'a> + Captures<'p> {
11481183
let cx = self;
11491184
let (adt, substs) = match ty.kind() {
11501185
ty::Adt(adt, substs) => (adt, substs),
11511186
_ => bug!(),
11521187
};
1188+
let variant = match ctor {
1189+
Constructor::Variant(variant_index) => &adt.variants[*variant_index],
1190+
Constructor::Single => adt.non_enum_variant(),
1191+
_ => bug!("bad constructor {:?} for adt {:?}", ctor, ty),
1192+
};
11531193
// Whether we must not match the fields of this variant exhaustively.
11541194
let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local();
11551195

0 commit comments

Comments
 (0)