Skip to content

Commit 1c176d1

Browse files
committed
Simplify field filtering
1 parent 53e03fb commit 1c176d1

File tree

2 files changed

+56
-64
lines changed

2 files changed

+56
-64
lines changed

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

+55-63
Original file line numberDiff line numberDiff line change
@@ -1058,41 +1058,30 @@ impl<'tcx> SplitWildcard<'tcx> {
10581058
}
10591059

10601060
/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
1061-
/// `Fields` struct. This struct represents such a potentially-hidden field. When a field is hidden
1062-
/// we still keep its type around.
1061+
/// `Fields` struct. This struct represents such a potentially-hidden field.
10631062
#[derive(Debug, Copy, Clone)]
10641063
pub(super) enum FilteredField<'p, 'tcx> {
10651064
Kept(&'p Pat<'tcx>),
1066-
Hidden(Ty<'tcx>),
1065+
Hidden,
10671066
}
10681067

10691068
impl<'p, 'tcx> FilteredField<'p, 'tcx> {
10701069
fn kept(self) -> Option<&'p Pat<'tcx>> {
10711070
match self {
10721071
FilteredField::Kept(p) => Some(p),
1073-
FilteredField::Hidden(_) => None,
1074-
}
1075-
}
1076-
1077-
fn to_pattern(self) -> Pat<'tcx> {
1078-
match self {
1079-
FilteredField::Kept(p) => p.clone(),
1080-
FilteredField::Hidden(ty) => Pat::wildcard_from_ty(ty),
1072+
FilteredField::Hidden => None,
10811073
}
10821074
}
10831075
}
10841076

10851077
/// A value can be decomposed into a constructor applied to some fields. This struct represents
10861078
/// those fields, generalized to allow patterns in each field. See also `Constructor`.
1079+
/// This is constructed from a constructor using [`Fields::wildcards()`].
10871080
///
10881081
/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
1089-
/// uninhabited. For that, we filter these fields out of the matrix. This is subtle because we
1090-
/// still need to have those fields back when going to/from a `Pat`. Most of this is handled
1091-
/// automatically in `Fields`, but when constructing or deconstructing `Fields` you need to be
1092-
/// careful. As a rule, when going to/from the matrix, use the filtered field list; when going
1093-
/// to/from `Pat`, use the full field list.
1094-
/// This filtering is uncommon in practice, because uninhabited fields are rarely used, so we avoid
1095-
/// it when possible to preserve performance.
1082+
/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically
1083+
/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rare used,
1084+
/// so we avoid it when possible to preserve performance.
10961085
#[derive(Debug, Clone)]
10971086
pub(super) enum Fields<'p, 'tcx> {
10981087
/// Lists of patterns that don't contain any filtered fields.
@@ -1101,21 +1090,19 @@ pub(super) enum Fields<'p, 'tcx> {
11011090
/// have not measured if it really made a difference.
11021091
Slice(&'p [Pat<'tcx>]),
11031092
Vec(SmallVec<[&'p Pat<'tcx>; 2]>),
1104-
/// Patterns where some of the fields need to be hidden. `kept_count` caches the number of
1105-
/// non-hidden fields.
1093+
/// Patterns where some of the fields need to be hidden. For all intents and purposes we only
1094+
/// care about the non-hidden fields. We need to keep the real field index for those fields;
1095+
/// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient.
1096+
/// `len` counts the number of non-hidden fields
11061097
Filtered {
11071098
fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
1108-
kept_count: usize,
1099+
len: usize,
11091100
},
11101101
}
11111102

11121103
impl<'p, 'tcx> Fields<'p, 'tcx> {
1113-
fn empty() -> Self {
1114-
Fields::Slice(&[])
1115-
}
1116-
1117-
/// Construct a new `Fields` from the given pattern. Must not be used if the pattern is a field
1118-
/// of a struct/tuple/variant.
1104+
/// Internal use. Use `Fields::wildcards()` instead.
1105+
/// Must not be used if the pattern is a field of a struct/tuple/variant.
11191106
fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
11201107
Fields::Slice(std::slice::from_ref(pat))
11211108
}
@@ -1160,7 +1147,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
11601147
if has_no_hidden_fields {
11611148
Fields::wildcards_from_tys(cx, field_tys)
11621149
} else {
1163-
let mut kept_count = 0;
1150+
let mut len = 0;
11641151
let fields = variant
11651152
.fields
11661153
.iter()
@@ -1175,14 +1162,14 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
11751162
// order not to reveal the uninhabitedness of the whole
11761163
// variant.
11771164
if is_uninhabited && (!is_visible || is_non_exhaustive) {
1178-
FilteredField::Hidden(ty)
1165+
FilteredField::Hidden
11791166
} else {
1180-
kept_count += 1;
1167+
len += 1;
11811168
FilteredField::Kept(wildcard_from_ty(ty))
11821169
}
11831170
})
11841171
.collect();
1185-
Fields::Filtered { fields, kept_count }
1172+
Fields::Filtered { fields, len }
11861173
}
11871174
}
11881175
}
@@ -1196,7 +1183,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
11961183
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
11971184
},
11981185
Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing
1199-
| Wildcard => Fields::empty(),
1186+
| Wildcard => Fields::Slice(&[]),
12001187
};
12011188
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
12021189
ret
@@ -1218,14 +1205,16 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12181205
/// `self`: `[false]`
12191206
/// returns `Some(false)`
12201207
pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> {
1221-
let mut subpatterns = self.all_patterns();
1208+
let subpatterns_and_indices = self.patterns_and_indices();
1209+
let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned();
12221210

12231211
let pat = match ctor {
12241212
Single | Variant(_) => match pcx.ty.kind() {
12251213
ty::Adt(..) | ty::Tuple(..) => {
1226-
let subpatterns = subpatterns
1227-
.enumerate()
1228-
.map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
1214+
// We want the real indices here.
1215+
let subpatterns = subpatterns_and_indices
1216+
.iter()
1217+
.map(|&(field, p)| FieldPat { field, pattern: p.clone() })
12291218
.collect();
12301219

12311220
if let ty::Adt(adt, substs) = pcx.ty.kind() {
@@ -1290,39 +1279,42 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12901279
Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
12911280
}
12921281

1293-
/// Returns the number of patterns from the viewpoint of match-checking, i.e. excluding hidden
1294-
/// fields. This is what we want in most cases in this file, the only exception being
1295-
/// conversion to/from `Pat`.
1282+
/// Returns the number of patterns. This is the same as the arity of the constructor used to
1283+
/// construct `self`.
12961284
pub(super) fn len(&self) -> usize {
12971285
match self {
12981286
Fields::Slice(pats) => pats.len(),
12991287
Fields::Vec(pats) => pats.len(),
1300-
Fields::Filtered { kept_count, .. } => *kept_count,
1288+
Fields::Filtered { len, .. } => *len,
13011289
}
13021290
}
13031291

1304-
/// Returns the complete list of patterns, including hidden fields.
1305-
fn all_patterns(self) -> impl Iterator<Item = Pat<'tcx>> {
1306-
let pats: SmallVec<[_; 2]> = match self {
1307-
Fields::Slice(pats) => pats.iter().cloned().collect(),
1308-
Fields::Vec(pats) => pats.into_iter().cloned().collect(),
1292+
/// Returns the list of patterns along with the corresponding field indices.
1293+
fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> {
1294+
match self {
1295+
Fields::Slice(pats) => {
1296+
pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
1297+
}
1298+
Fields::Vec(pats) => {
1299+
pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
1300+
}
13091301
Fields::Filtered { fields, .. } => {
1310-
// We don't skip any fields here.
1311-
fields.into_iter().map(|p| p.to_pattern()).collect()
1302+
// Indices must be relative to the full list of patterns
1303+
fields
1304+
.iter()
1305+
.enumerate()
1306+
.filter_map(|(i, p)| Some((Field::new(i), p.kept()?)))
1307+
.collect()
13121308
}
1313-
};
1314-
pats.into_iter()
1309+
}
13151310
}
13161311

1317-
/// Returns the filtered list of patterns, not including hidden fields.
1318-
pub(super) fn filtered_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
1312+
/// Returns the list of patterns.
1313+
pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
13191314
match self {
13201315
Fields::Slice(pats) => pats.iter().collect(),
13211316
Fields::Vec(pats) => pats,
1322-
Fields::Filtered { fields, .. } => {
1323-
// We skip hidden fields here
1324-
fields.into_iter().filter_map(|p| p.kept()).collect()
1325-
}
1317+
Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(),
13261318
}
13271319
}
13281320

@@ -1338,10 +1330,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
13381330
}
13391331

13401332
/// Overrides some of the fields with the provided patterns. This is used when a pattern
1341-
/// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start with a
1342-
/// `Fields` that is just one wildcard per field of the `Foo` struct, and override the entry
1343-
/// corresponding to `field1` with the pattern `Some(_)`. This is also used for slice patterns
1344-
/// for the same reason.
1333+
/// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start
1334+
/// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the
1335+
/// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice
1336+
/// patterns for the same reason.
13451337
fn replace_fields_indexed(
13461338
&self,
13471339
new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
@@ -1369,8 +1361,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
13691361
fields
13701362
}
13711363

1372-
/// Replaces contained fields with the given filtered list of patterns, e.g. taken from the
1373-
/// matrix. There must be `len()` patterns in `pats`.
1364+
/// Replaces contained fields with the given list of patterns. There must be `len()` patterns
1365+
/// in `pats`.
13741366
pub(super) fn replace_fields(
13751367
&self,
13761368
cx: &MatchCheckCtxt<'p, 'tcx>,
@@ -1379,7 +1371,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
13791371
let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
13801372

13811373
match self {
1382-
Fields::Filtered { fields, kept_count } => {
1374+
Fields::Filtered { fields, len } => {
13831375
let mut pats = pats.iter();
13841376
let mut fields = fields.clone();
13851377
for f in &mut fields {
@@ -1388,7 +1380,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
13881380
*p = pats.next().unwrap();
13891381
}
13901382
}
1391-
Fields::Filtered { fields, kept_count: *kept_count }
1383+
Fields::Filtered { fields, len: *len }
13921384
}
13931385
_ => Fields::Slice(pats),
13941386
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
447447
// We pop the head pattern and push the new fields extracted from the arguments of
448448
// `self.head()`.
449449
let mut new_fields =
450-
ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).filtered_patterns();
450+
ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns();
451451
new_fields.extend_from_slice(&self.pats[1..]);
452452
PatStack::from_vec(new_fields)
453453
}

0 commit comments

Comments
 (0)