Skip to content

Commit e67f39f

Browse files
committed
Introduce DotDotPos.
This shrinks `hir::Pat` from 88 to 72 bytes.
1 parent 4314615 commit e67f39f

File tree

15 files changed

+85
-47
lines changed

15 files changed

+85
-47
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1128,8 +1128,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
11281128
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
11291129
);
11301130
// Destructure like a tuple struct.
1131-
let tuple_struct_pat =
1132-
hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
1131+
let tuple_struct_pat = hir::PatKind::TupleStruct(
1132+
qpath,
1133+
pats,
1134+
hir::DotDotPos::new(rest.map(|r| r.0)),
1135+
);
11331136
return self.pat_without_dbm(lhs.span, tuple_struct_pat);
11341137
}
11351138
}
@@ -1184,13 +1187,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
11841187
ExprKind::Tup(elements) => {
11851188
let (pats, rest) =
11861189
self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
1187-
let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
1190+
let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));
11881191
return self.pat_without_dbm(lhs.span, tuple_pat);
11891192
}
11901193
ExprKind::Paren(e) => {
11911194
// We special-case `(..)` for consistency with patterns.
11921195
if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
1193-
let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
1196+
let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));
11941197
return self.pat_without_dbm(lhs.span, tuple_pat);
11951198
} else {
11961199
return self.destructure_assign_mut(e, eq_sign_span, assignments);

compiler/rustc_ast_lowering/src/pat.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
116116
&mut self,
117117
pats: &[P<Pat>],
118118
ctx: &str,
119-
) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
119+
) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
120120
let mut elems = Vec::with_capacity(pats.len());
121121
let mut rest = None;
122122

@@ -160,7 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
160160
}
161161
}
162162

163-
(self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
163+
(self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
164164
}
165165

166166
/// Lower a slice pattern of form `[pat_0, ..., pat_n]` into

compiler/rustc_hir/src/hir.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,35 @@ impl fmt::Display for RangeEnd {
10591059
}
10601060
}
10611061

1062+
// Equivalent to `Option<usize>`. That type takes up 16 bytes on 64-bit, but
1063+
// this type only takes up 4 bytes, at the cost of being restricted to a
1064+
// maximum value of `u32::MAX - 1`. In practice, this is more than enough.
1065+
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)]
1066+
pub struct DotDotPos(u32);
1067+
1068+
impl DotDotPos {
1069+
// Panics if n >= u32::MAX.
1070+
pub fn new(n: Option<usize>) -> Self {
1071+
match n {
1072+
Some(n) => {
1073+
assert!(n < u32::MAX as usize);
1074+
Self(n as u32)
1075+
}
1076+
None => Self(u32::MAX),
1077+
}
1078+
}
1079+
1080+
pub fn as_opt_usize(&self) -> Option<usize> {
1081+
if self.0 == u32::MAX { None } else { Some(self.0 as usize) }
1082+
}
1083+
}
1084+
1085+
impl fmt::Debug for DotDotPos {
1086+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1087+
self.as_opt_usize().fmt(f)
1088+
}
1089+
}
1090+
10621091
#[derive(Debug, HashStable_Generic)]
10631092
pub enum PatKind<'hir> {
10641093
/// Represents a wildcard pattern (i.e., `_`).
@@ -1075,9 +1104,9 @@ pub enum PatKind<'hir> {
10751104
Struct(QPath<'hir>, &'hir [PatField<'hir>], bool),
10761105

10771106
/// A tuple struct/variant pattern `Variant(x, y, .., z)`.
1078-
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
1107+
/// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
10791108
/// `0 <= position <= subpats.len()`
1080-
TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option<usize>),
1109+
TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos),
10811110

10821111
/// An or-pattern `A | B | C`.
10831112
/// Invariant: `pats.len() >= 2`.
@@ -1089,7 +1118,7 @@ pub enum PatKind<'hir> {
10891118
/// A tuple pattern (e.g., `(a, b)`).
10901119
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
10911120
/// `0 <= position <= subpats.len()`
1092-
Tuple(&'hir [Pat<'hir>], Option<usize>),
1121+
Tuple(&'hir [Pat<'hir>], DotDotPos),
10931122

10941123
/// A `box` pattern.
10951124
Box(&'hir Pat<'hir>),
@@ -3486,8 +3515,8 @@ mod size_asserts {
34863515
static_assert_size!(ItemKind<'_>, 48);
34873516
static_assert_size!(Local<'_>, 64);
34883517
static_assert_size!(Param<'_>, 32);
3489-
static_assert_size!(Pat<'_>, 88);
3490-
static_assert_size!(PatKind<'_>, 64);
3518+
static_assert_size!(Pat<'_>, 72);
3519+
static_assert_size!(PatKind<'_>, 48);
34913520
static_assert_size!(Path<'_>, 48);
34923521
static_assert_size!(PathSegment<'_>, 56);
34933522
static_assert_size!(QPath<'_>, 24);

compiler/rustc_hir/src/pat_util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub trait EnumerateAndAdjustIterator {
3535
fn enumerate_and_adjust(
3636
self,
3737
expected_len: usize,
38-
gap_pos: Option<usize>,
38+
gap_pos: hir::DotDotPos,
3939
) -> EnumerateAndAdjust<Self>
4040
where
4141
Self: Sized;
@@ -45,15 +45,15 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
4545
fn enumerate_and_adjust(
4646
self,
4747
expected_len: usize,
48-
gap_pos: Option<usize>,
48+
gap_pos: hir::DotDotPos,
4949
) -> EnumerateAndAdjust<Self>
5050
where
5151
Self: Sized,
5252
{
5353
let actual_len = self.len();
5454
EnumerateAndAdjust {
5555
enumerate: self.enumerate(),
56-
gap_pos: gap_pos.unwrap_or(expected_len),
56+
gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len),
5757
gap_len: expected_len - actual_len,
5858
}
5959
}

compiler/rustc_hir_pretty/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1761,7 +1761,8 @@ impl<'a> State<'a> {
17611761
PatKind::TupleStruct(ref qpath, elts, ddpos) => {
17621762
self.print_qpath(qpath, true);
17631763
self.popen();
1764-
if let Some(ddpos) = ddpos {
1764+
if let Some(ddpos) = ddpos.as_opt_usize() {
1765+
let ddpos = ddpos as usize;
17651766
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
17661767
if ddpos != 0 {
17671768
self.word_space(",");
@@ -1804,7 +1805,7 @@ impl<'a> State<'a> {
18041805
}
18051806
PatKind::Tuple(elts, ddpos) => {
18061807
self.popen();
1807-
if let Some(ddpos) = ddpos {
1808+
if let Some(ddpos) = ddpos.as_opt_usize() {
18081809
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
18091810
if ddpos != 0 {
18101811
self.word_space(",");

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
333333
&mut self,
334334
pats: &'tcx [hir::Pat<'tcx>],
335335
expected_len: usize,
336-
gap_pos: Option<usize>,
336+
gap_pos: hir::DotDotPos,
337337
) -> Vec<FieldPat<'tcx>> {
338338
pats.iter()
339339
.enumerate_and_adjust(expected_len, gap_pos)

compiler/rustc_passes/src/dead.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
226226
lhs: &hir::Pat<'_>,
227227
res: Res,
228228
pats: &[hir::Pat<'_>],
229-
dotdot: Option<usize>,
229+
dotdot: hir::DotDotPos,
230230
) {
231231
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
232232
ty::Adt(adt, _) => adt.variant_of_res(res),
233233
_ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
234234
};
235-
let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
235+
let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len());
236+
let first_n = pats.iter().enumerate().take(dotdot);
236237
let missing = variant.fields.len() - pats.len();
237-
let last_n = pats
238-
.iter()
239-
.enumerate()
240-
.skip(dotdot.unwrap_or(pats.len()))
241-
.map(|(idx, pat)| (idx + missing, pat));
238+
let last_n = pats.iter().enumerate().skip(dotdot).map(|(idx, pat)| (idx + missing, pat));
242239
for (idx, pat) in first_n.chain(last_n) {
243240
if let PatKind::Wild = pat.kind {
244241
continue;

compiler/rustc_typeck/src/check/pat.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
981981
pat: &'tcx Pat<'tcx>,
982982
qpath: &'tcx hir::QPath<'tcx>,
983983
subpats: &'tcx [Pat<'tcx>],
984-
ddpos: Option<usize>,
984+
ddpos: hir::DotDotPos,
985985
expected: Ty<'tcx>,
986986
def_bm: BindingMode,
987987
ti: TopInfo<'tcx>,
@@ -1066,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10661066

10671067
// Type-check subpatterns.
10681068
if subpats.len() == variant.fields.len()
1069-
|| subpats.len() < variant.fields.len() && ddpos.is_some()
1069+
|| subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
10701070
{
10711071
let ty::Adt(_, substs) = pat_ty.kind() else {
10721072
bug!("unexpected pattern type {:?}", pat_ty);
@@ -1254,14 +1254,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12541254
&self,
12551255
span: Span,
12561256
elements: &'tcx [Pat<'tcx>],
1257-
ddpos: Option<usize>,
1257+
ddpos: hir::DotDotPos,
12581258
expected: Ty<'tcx>,
12591259
def_bm: BindingMode,
12601260
ti: TopInfo<'tcx>,
12611261
) -> Ty<'tcx> {
12621262
let tcx = self.tcx;
12631263
let mut expected_len = elements.len();
1264-
if ddpos.is_some() {
1264+
if ddpos.as_opt_usize().is_some() {
12651265
// Require known type only when `..` is present.
12661266
if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
12671267
expected_len = tys.len();

src/test/ui/stats/hir-stats.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,18 @@ hir-stats - Expr 32 ( 0.3%) 1
140140
hir-stats FnDecl 120 ( 1.2%) 3 40
141141
hir-stats Attribute 128 ( 1.3%) 4 32
142142
hir-stats GenericArgs 144 ( 1.5%) 3 48
143-
hir-stats Variant 160 ( 1.6%) 2 80
143+
hir-stats Variant 160 ( 1.7%) 2 80
144144
hir-stats WherePredicate 168 ( 1.7%) 3 56
145145
hir-stats - BoundPredicate 168 ( 1.7%) 3
146146
hir-stats GenericBound 192 ( 2.0%) 4 48
147147
hir-stats - Trait 192 ( 2.0%) 4
148148
hir-stats Block 288 ( 3.0%) 6 48
149+
hir-stats Pat 360 ( 3.7%) 5 72
150+
hir-stats - Wild 72 ( 0.7%) 1
151+
hir-stats - Struct 72 ( 0.7%) 1
152+
hir-stats - Binding 216 ( 2.2%) 3
149153
hir-stats GenericParam 400 ( 4.1%) 5 80
150-
hir-stats Pat 440 ( 4.5%) 5 88
151-
hir-stats - Wild 88 ( 0.9%) 1
152-
hir-stats - Struct 88 ( 0.9%) 1
153-
hir-stats - Binding 264 ( 2.7%) 3
154-
hir-stats Generics 560 ( 5.7%) 10 56
154+
hir-stats Generics 560 ( 5.8%) 10 56
155155
hir-stats Ty 720 ( 7.4%) 15 48
156156
hir-stats - Ptr 48 ( 0.5%) 1
157157
hir-stats - Rptr 48 ( 0.5%) 1
@@ -162,17 +162,17 @@ hir-stats - Struct 64 ( 0.7%) 1
162162
hir-stats - Match 64 ( 0.7%) 1
163163
hir-stats - InlineAsm 64 ( 0.7%) 1
164164
hir-stats - Lit 128 ( 1.3%) 2
165-
hir-stats - Block 384 ( 3.9%) 6
166-
hir-stats Item 960 ( 9.8%) 12 80
165+
hir-stats - Block 384 ( 4.0%) 6
166+
hir-stats Item 960 ( 9.9%) 12 80
167167
hir-stats - Trait 80 ( 0.8%) 1
168168
hir-stats - Enum 80 ( 0.8%) 1
169169
hir-stats - ExternCrate 80 ( 0.8%) 1
170170
hir-stats - ForeignMod 80 ( 0.8%) 1
171171
hir-stats - Impl 80 ( 0.8%) 1
172-
hir-stats - Fn 160 ( 1.6%) 2
172+
hir-stats - Fn 160 ( 1.7%) 2
173173
hir-stats - Use 400 ( 4.1%) 5
174-
hir-stats Path 1_536 (15.7%) 32 48
175-
hir-stats PathSegment 2_240 (23.0%) 40 56
174+
hir-stats Path 1_536 (15.9%) 32 48
175+
hir-stats PathSegment 2_240 (23.1%) 40 56
176176
hir-stats ----------------------------------------------------------------
177-
hir-stats Total 9_760
177+
hir-stats Total 9_680
178178
hir-stats

src/tools/clippy/clippy_lints/src/equatable_if_let.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
5151
false
5252
},
5353
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
54-
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a),
54+
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => {
55+
!etc.as_opt_usize().is_some() && array_rec(a)
56+
}
5557
PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
5658
PatKind::Path(_) | PatKind::Lit(_) => true,
5759
}

src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ impl<'a> NormalizedPat<'a> {
248248
} else {
249249
(None, adt.non_enum_variant())
250250
};
251-
let (front, back) = match wild_idx {
251+
let (front, back) = match wild_idx.as_opt_usize() {
252252
Some(i) => pats.split_at(i),
253253
None => (pats, [].as_slice()),
254254
};
@@ -268,7 +268,7 @@ impl<'a> NormalizedPat<'a> {
268268
ty::Tuple(subs) => subs.len(),
269269
_ => return Self::Wild,
270270
};
271-
let (front, back) = match wild_idx {
271+
let (front, back) = match wild_idx.as_opt_usize() {
272272
Some(i) => pats.split_at(i),
273273
None => (pats, [].as_slice()),
274274
};

src/tools/clippy/clippy_lints/src/matches/single_match.rs

+2
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>,
200200
// We don't actually know the position and the presence of the `..` (dotdot) operator
201201
// in the arms, so we need to evaluate the correct offsets here in order to iterate in
202202
// both arms at the same time.
203+
let left_pos = left_pos.as_opt_usize();
204+
let right_pos = right_pos.as_opt_usize();
203205
let len = max(
204206
left_in.len() + {
205207
if left_pos.is_some() { 1 } else { 0 }

src/tools/clippy/clippy_lints/src/question_mark.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
122122
if_chain! {
123123
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
124124
if !is_else_clause(cx.tcx, expr);
125-
if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
125+
if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
126+
if ddpos.as_opt_usize().is_none();
126127
if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
127128
let caller_ty = cx.typeck_results().expr_ty(let_expr);
128129
let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);

src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
1919
&& cx.typeck_results().pat_ty(local.pat).is_unit()
2020
{
2121
if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
22-
|| matches!(local.pat.kind, PatKind::Tuple([], None)))
22+
|| matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
2323
&& expr_needs_inferred_result(cx, init)
2424
{
25-
if !matches!(local.pat.kind, PatKind::Wild | PatKind::Tuple([], None)) {
25+
if !matches!(local.pat.kind, PatKind::Wild)
26+
&& !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())
27+
{
2628
span_lint_and_then(
2729
cx,
2830
LET_UNIT_VALUE,

src/tools/clippy/clippy_utils/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,8 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
15521552
pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
15531553
fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
15541554
if_chain! {
1555-
if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
1555+
if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
1556+
if ddpos.as_opt_usize().is_none();
15561557
if is_lang_ctor(cx, path, ResultOk);
15571558
if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
15581559
if path_to_local_id(arm.body, hir_id);

0 commit comments

Comments
 (0)