Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a5c661c

Browse files
authoredMar 13, 2024
Unrolled build for rust-lang#121820
Rollup merge of rust-lang#121820 - Nadrieril:idxpat2, r=compiler-errors pattern analysis: Store field indices in `DeconstructedPat` to avoid virtual wildcards For a pattern like `Struct { field3: true, .. }`, in pattern analysis we represent it as `Struct { field1: _, field2: _, field3: true, field4: _ }`. This PR makes it so we store `Struct { field3: true, .. }` instead. This means we never have to create fake `_` patterns during lowering. r? ``@compiler-errors``
2 parents 5a6c1aa + d339bda commit a5c661c

File tree

6 files changed

+140
-95
lines changed

6 files changed

+140
-95
lines changed
 

‎compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
420420
{
421421
let mut redundant_subpats = redundant_subpats.clone();
422422
// Emit lints in the order in which they occur in the file.
423-
redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
423+
redundant_subpats.sort_unstable_by_key(|pat| pat.data().span);
424424
for pat in redundant_subpats {
425-
report_unreachable_pattern(cx, arm.arm_data, pat.data().unwrap().span, None)
425+
report_unreachable_pattern(cx, arm.arm_data, pat.data().span, None)
426426
}
427427
}
428428
}
@@ -905,10 +905,10 @@ fn report_arm_reachability<'p, 'tcx>(
905905
let mut catchall = None;
906906
for (arm, is_useful) in report.arm_usefulness.iter() {
907907
if matches!(is_useful, Usefulness::Redundant) {
908-
report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().unwrap().span, catchall)
908+
report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().span, catchall)
909909
}
910910
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
911-
catchall = Some(arm.pat.data().unwrap().span);
911+
catchall = Some(arm.pat.data().span);
912912
}
913913
}
914914
}
@@ -917,7 +917,9 @@ fn report_arm_reachability<'p, 'tcx>(
917917
fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
918918
match pat.ctor() {
919919
Constructor::Wildcard => true,
920-
Constructor::Struct | Constructor::Ref => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
920+
Constructor::Struct | Constructor::Ref => {
921+
pat.iter_fields().all(|ipat| pat_is_catchall(&ipat.pat))
922+
}
921923
_ => false,
922924
}
923925
}

‎compiler/rustc_pattern_analysis/src/constructor.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ pub enum SliceKind {
423423
}
424424

425425
impl SliceKind {
426-
fn arity(self) -> usize {
426+
pub fn arity(self) -> usize {
427427
match self {
428428
FixedLen(length) => length,
429429
VarLen(prefix, suffix) => prefix + suffix,
@@ -462,7 +462,7 @@ impl Slice {
462462
Slice { array_len, kind }
463463
}
464464

465-
pub(crate) fn arity(self) -> usize {
465+
pub fn arity(self) -> usize {
466466
self.kind.arity()
467467
}
468468

‎compiler/rustc_pattern_analysis/src/lints.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
9898
};
9999

100100
use rustc_errors::LintDiagnostic;
101-
let mut err = rcx.tcx.dcx().struct_span_warn(arm.pat.data().unwrap().span, "");
101+
let mut err = rcx.tcx.dcx().struct_span_warn(arm.pat.data().span, "");
102102
err.primary_message(decorator.msg());
103103
decorator.decorate_lint(&mut err);
104104
err.emit();

‎compiler/rustc_pattern_analysis/src/pat.rs

+71-51
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,42 @@ impl PatId {
2020
}
2121
}
2222

23+
/// A pattern with an index denoting which field it corresponds to.
24+
pub struct IndexedPat<Cx: TypeCx> {
25+
pub idx: usize,
26+
pub pat: DeconstructedPat<Cx>,
27+
}
28+
2329
/// Values and patterns can be represented as a constructor applied to some fields. This represents
2430
/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
2531
/// exception are some `Wildcard`s introduced during pattern lowering.
2632
pub struct DeconstructedPat<Cx: TypeCx> {
2733
ctor: Constructor<Cx>,
28-
fields: Vec<DeconstructedPat<Cx>>,
34+
fields: Vec<IndexedPat<Cx>>,
35+
/// The number of fields in this pattern. E.g. if the pattern is `SomeStruct { field12: true, ..
36+
/// }` this would be the total number of fields of the struct.
37+
/// This is also the same as `self.ctor.arity(self.ty)`.
38+
arity: usize,
2939
ty: Cx::Ty,
30-
/// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
31-
/// correspond to a user-supplied pattern.
32-
data: Option<Cx::PatData>,
40+
/// Extra data to store in a pattern.
41+
data: Cx::PatData,
3342
/// Globally-unique id used to track usefulness at the level of subpatterns.
3443
pub(crate) uid: PatId,
3544
}
3645

3746
impl<Cx: TypeCx> DeconstructedPat<Cx> {
38-
pub fn wildcard(ty: Cx::Ty) -> Self {
39-
DeconstructedPat { ctor: Wildcard, fields: Vec::new(), ty, data: None, uid: PatId::new() }
40-
}
41-
4247
pub fn new(
4348
ctor: Constructor<Cx>,
44-
fields: Vec<DeconstructedPat<Cx>>,
49+
fields: Vec<IndexedPat<Cx>>,
50+
arity: usize,
4551
ty: Cx::Ty,
4652
data: Cx::PatData,
4753
) -> Self {
48-
DeconstructedPat { ctor, fields, ty, data: Some(data), uid: PatId::new() }
54+
DeconstructedPat { ctor, fields, arity, ty, data, uid: PatId::new() }
55+
}
56+
57+
pub fn at_index(self, idx: usize) -> IndexedPat<Cx> {
58+
IndexedPat { idx, pat: self }
4959
}
5060

5161
pub(crate) fn is_or_pat(&self) -> bool {
@@ -58,13 +68,15 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
5868
pub fn ty(&self) -> &Cx::Ty {
5969
&self.ty
6070
}
61-
/// Returns the extra data stored in a pattern. Returns `None` if the pattern is a wildcard that
62-
/// does not correspond to a user-supplied pattern.
63-
pub fn data(&self) -> Option<&Cx::PatData> {
64-
self.data.as_ref()
71+
/// Returns the extra data stored in a pattern.
72+
pub fn data(&self) -> &Cx::PatData {
73+
&self.data
74+
}
75+
pub fn arity(&self) -> usize {
76+
self.arity
6577
}
6678

67-
pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a DeconstructedPat<Cx>> {
79+
pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a IndexedPat<Cx>> {
6880
self.fields.iter()
6981
}
7082

@@ -73,36 +85,40 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
7385
pub(crate) fn specialize<'a>(
7486
&'a self,
7587
other_ctor: &Constructor<Cx>,
76-
ctor_arity: usize,
88+
other_ctor_arity: usize,
7789
) -> SmallVec<[PatOrWild<'a, Cx>; 2]> {
78-
let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect();
79-
match (&self.ctor, other_ctor) {
80-
// Return a wildcard for each field of `other_ctor`.
81-
(Wildcard, _) => wildcard_sub_tys(),
90+
if matches!(other_ctor, PrivateUninhabited) {
8291
// Skip this column.
83-
(_, PrivateUninhabited) => smallvec![],
84-
// The only non-trivial case: two slices of different arity. `other_slice` is
85-
// guaranteed to have a larger arity, so we fill the middle part with enough
86-
// wildcards to reach the length of the new, larger slice.
87-
(
88-
&Slice(self_slice @ Slice { kind: SliceKind::VarLen(prefix, suffix), .. }),
89-
&Slice(other_slice),
90-
) if self_slice.arity() != other_slice.arity() => {
91-
// Start with a slice of wildcards of the appropriate length.
92-
let mut fields: SmallVec<[_; 2]> = wildcard_sub_tys();
93-
// Fill in the fields from both ends.
94-
let new_arity = fields.len();
95-
for i in 0..prefix {
96-
fields[i] = PatOrWild::Pat(&self.fields[i]);
92+
return smallvec![];
93+
}
94+
95+
// Start with a slice of wildcards of the appropriate length.
96+
let mut fields: SmallVec<[_; 2]> = (0..other_ctor_arity).map(|_| PatOrWild::Wild).collect();
97+
// Fill `fields` with our fields. The arities are known to be compatible.
98+
match self.ctor {
99+
// The only non-trivial case: two slices of different arity. `other_ctor` is guaranteed
100+
// to have a larger arity, so we adjust the indices of the patterns in the suffix so
101+
// that they are correctly positioned in the larger slice.
102+
Slice(Slice { kind: SliceKind::VarLen(prefix, _), .. })
103+
if self.arity != other_ctor_arity =>
104+
{
105+
for ipat in &self.fields {
106+
let new_idx = if ipat.idx < prefix {
107+
ipat.idx
108+
} else {
109+
// Adjust the indices in the suffix.
110+
ipat.idx + other_ctor_arity - self.arity
111+
};
112+
fields[new_idx] = PatOrWild::Pat(&ipat.pat);
97113
}
98-
for i in 0..suffix {
99-
fields[new_arity - 1 - i] =
100-
PatOrWild::Pat(&self.fields[self.fields.len() - 1 - i]);
114+
}
115+
_ => {
116+
for ipat in &self.fields {
117+
fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
101118
}
102-
fields
103119
}
104-
_ => self.fields.iter().map(PatOrWild::Pat).collect(),
105120
}
121+
fields
106122
}
107123

108124
/// Walk top-down and call `it` in each place where a pattern occurs
@@ -114,7 +130,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
114130
}
115131

116132
for p in self.iter_fields() {
117-
p.walk(it)
133+
p.pat.walk(it)
118134
}
119135
}
120136
}
@@ -134,14 +150,19 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
134150
};
135151
let mut start_or_comma = || start_or_continue(", ");
136152

153+
let mut fields: Vec<_> = (0..self.arity).map(|_| PatOrWild::Wild).collect();
154+
for ipat in self.iter_fields() {
155+
fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
156+
}
157+
137158
match pat.ctor() {
138159
Struct | Variant(_) | UnionField => {
139160
Cx::write_variant_name(f, pat)?;
140161
// Without `cx`, we can't know which field corresponds to which, so we can't
141162
// get the names of the fields. Instead we just display everything as a tuple
142163
// struct, which should be good enough.
143164
write!(f, "(")?;
144-
for p in pat.iter_fields() {
165+
for p in fields {
145166
write!(f, "{}", start_or_comma())?;
146167
write!(f, "{p:?}")?;
147168
}
@@ -151,25 +172,23 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
151172
// be careful to detect strings here. However a string literal pattern will never
152173
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
153174
Ref => {
154-
let subpattern = pat.iter_fields().next().unwrap();
155-
write!(f, "&{:?}", subpattern)
175+
write!(f, "&{:?}", &fields[0])
156176
}
157177
Slice(slice) => {
158-
let mut subpatterns = pat.iter_fields();
159178
write!(f, "[")?;
160179
match slice.kind {
161180
SliceKind::FixedLen(_) => {
162-
for p in subpatterns {
181+
for p in fields {
163182
write!(f, "{}{:?}", start_or_comma(), p)?;
164183
}
165184
}
166185
SliceKind::VarLen(prefix_len, _) => {
167-
for p in subpatterns.by_ref().take(prefix_len) {
186+
for p in &fields[..prefix_len] {
168187
write!(f, "{}{:?}", start_or_comma(), p)?;
169188
}
170189
write!(f, "{}", start_or_comma())?;
171190
write!(f, "..")?;
172-
for p in subpatterns {
191+
for p in &fields[prefix_len..] {
173192
write!(f, "{}{:?}", start_or_comma(), p)?;
174193
}
175194
}
@@ -184,7 +203,7 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
184203
Str(value) => write!(f, "{value:?}"),
185204
Opaque(..) => write!(f, "<constant pattern>"),
186205
Or => {
187-
for pat in pat.iter_fields() {
206+
for pat in fields {
188207
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
189208
}
190209
Ok(())
@@ -242,9 +261,10 @@ impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
242261
/// Expand this (possibly-nested) or-pattern into its alternatives.
243262
pub(crate) fn flatten_or_pat(self) -> SmallVec<[Self; 1]> {
244263
match self {
245-
PatOrWild::Pat(pat) if pat.is_or_pat() => {
246-
pat.iter_fields().flat_map(|p| PatOrWild::Pat(p).flatten_or_pat()).collect()
247-
}
264+
PatOrWild::Pat(pat) if pat.is_or_pat() => pat
265+
.iter_fields()
266+
.flat_map(|ipat| PatOrWild::Pat(&ipat.pat).flatten_or_pat())
267+
.collect(),
248268
_ => smallvec![self],
249269
}
250270
}
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.