Introduce DotDotPos
.
This shrinks `hir::Pat` from 88 to 72 bytes.
This commit is contained in:
parent
4314615ff8
commit
e67f39f8bc
15 changed files with 85 additions and 47 deletions
|
@ -1128,8 +1128,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
// Destructure like a tuple struct.
|
||||
let tuple_struct_pat =
|
||||
hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
|
||||
let tuple_struct_pat = hir::PatKind::TupleStruct(
|
||||
qpath,
|
||||
pats,
|
||||
hir::DotDotPos::new(rest.map(|r| r.0)),
|
||||
);
|
||||
return self.pat_without_dbm(lhs.span, tuple_struct_pat);
|
||||
}
|
||||
}
|
||||
|
@ -1184,13 +1187,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::Tup(elements) => {
|
||||
let (pats, rest) =
|
||||
self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
|
||||
let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
|
||||
let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));
|
||||
return self.pat_without_dbm(lhs.span, tuple_pat);
|
||||
}
|
||||
ExprKind::Paren(e) => {
|
||||
// We special-case `(..)` for consistency with patterns.
|
||||
if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
|
||||
let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
|
||||
let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));
|
||||
return self.pat_without_dbm(lhs.span, tuple_pat);
|
||||
} else {
|
||||
return self.destructure_assign_mut(e, eq_sign_span, assignments);
|
||||
|
|
|
@ -116,7 +116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
pats: &[P<Pat>],
|
||||
ctx: &str,
|
||||
) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
|
||||
) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
|
||||
let mut elems = Vec::with_capacity(pats.len());
|
||||
let mut rest = None;
|
||||
|
||||
|
@ -160,7 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
(self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
|
||||
(self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
|
||||
}
|
||||
|
||||
/// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
|
||||
|
|
|
@ -1059,6 +1059,35 @@ impl fmt::Display for RangeEnd {
|
|||
}
|
||||
}
|
||||
|
||||
// Equivalent to `Option<usize>`. That type takes up 16 bytes on 64-bit, but
|
||||
// this type only takes up 4 bytes, at the cost of being restricted to a
|
||||
// maximum value of `u32::MAX - 1`. In practice, this is more than enough.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
pub struct DotDotPos(u32);
|
||||
|
||||
impl DotDotPos {
|
||||
// Panics if n >= u32::MAX.
|
||||
pub fn new(n: Option<usize>) -> Self {
|
||||
match n {
|
||||
Some(n) => {
|
||||
assert!(n < u32::MAX as usize);
|
||||
Self(n as u32)
|
||||
}
|
||||
None => Self(u32::MAX),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_opt_usize(&self) -> Option<usize> {
|
||||
if self.0 == u32::MAX { None } else { Some(self.0 as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DotDotPos {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.as_opt_usize().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub enum PatKind<'hir> {
|
||||
/// Represents a wildcard pattern (i.e., `_`).
|
||||
|
@ -1075,9 +1104,9 @@ pub enum PatKind<'hir> {
|
|||
Struct(QPath<'hir>, &'hir [PatField<'hir>], bool),
|
||||
|
||||
/// A tuple struct/variant pattern `Variant(x, y, .., z)`.
|
||||
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
|
||||
/// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
|
||||
/// `0 <= position <= subpats.len()`
|
||||
TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option<usize>),
|
||||
TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos),
|
||||
|
||||
/// An or-pattern `A | B | C`.
|
||||
/// Invariant: `pats.len() >= 2`.
|
||||
|
@ -1089,7 +1118,7 @@ pub enum PatKind<'hir> {
|
|||
/// A tuple pattern (e.g., `(a, b)`).
|
||||
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
|
||||
/// `0 <= position <= subpats.len()`
|
||||
Tuple(&'hir [Pat<'hir>], Option<usize>),
|
||||
Tuple(&'hir [Pat<'hir>], DotDotPos),
|
||||
|
||||
/// A `box` pattern.
|
||||
Box(&'hir Pat<'hir>),
|
||||
|
@ -3486,8 +3515,8 @@ mod size_asserts {
|
|||
static_assert_size!(ItemKind<'_>, 48);
|
||||
static_assert_size!(Local<'_>, 64);
|
||||
static_assert_size!(Param<'_>, 32);
|
||||
static_assert_size!(Pat<'_>, 88);
|
||||
static_assert_size!(PatKind<'_>, 64);
|
||||
static_assert_size!(Pat<'_>, 72);
|
||||
static_assert_size!(PatKind<'_>, 48);
|
||||
static_assert_size!(Path<'_>, 48);
|
||||
static_assert_size!(PathSegment<'_>, 56);
|
||||
static_assert_size!(QPath<'_>, 24);
|
||||
|
|
|
@ -35,7 +35,7 @@ pub trait EnumerateAndAdjustIterator {
|
|||
fn enumerate_and_adjust(
|
||||
self,
|
||||
expected_len: usize,
|
||||
gap_pos: Option<usize>,
|
||||
gap_pos: hir::DotDotPos,
|
||||
) -> EnumerateAndAdjust<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
|
@ -45,7 +45,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
|
|||
fn enumerate_and_adjust(
|
||||
self,
|
||||
expected_len: usize,
|
||||
gap_pos: Option<usize>,
|
||||
gap_pos: hir::DotDotPos,
|
||||
) -> EnumerateAndAdjust<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -53,7 +53,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
|
|||
let actual_len = self.len();
|
||||
EnumerateAndAdjust {
|
||||
enumerate: self.enumerate(),
|
||||
gap_pos: gap_pos.unwrap_or(expected_len),
|
||||
gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len),
|
||||
gap_len: expected_len - actual_len,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1761,7 +1761,8 @@ impl<'a> State<'a> {
|
|||
PatKind::TupleStruct(ref qpath, elts, ddpos) => {
|
||||
self.print_qpath(qpath, true);
|
||||
self.popen();
|
||||
if let Some(ddpos) = ddpos {
|
||||
if let Some(ddpos) = ddpos.as_opt_usize() {
|
||||
let ddpos = ddpos as usize;
|
||||
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
|
||||
if ddpos != 0 {
|
||||
self.word_space(",");
|
||||
|
@ -1804,7 +1805,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
PatKind::Tuple(elts, ddpos) => {
|
||||
self.popen();
|
||||
if let Some(ddpos) = ddpos {
|
||||
if let Some(ddpos) = ddpos.as_opt_usize() {
|
||||
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
|
||||
if ddpos != 0 {
|
||||
self.word_space(",");
|
||||
|
|
|
@ -333,7 +333,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
&mut self,
|
||||
pats: &'tcx [hir::Pat<'tcx>],
|
||||
expected_len: usize,
|
||||
gap_pos: Option<usize>,
|
||||
gap_pos: hir::DotDotPos,
|
||||
) -> Vec<FieldPat<'tcx>> {
|
||||
pats.iter()
|
||||
.enumerate_and_adjust(expected_len, gap_pos)
|
||||
|
|
|
@ -226,19 +226,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
lhs: &hir::Pat<'_>,
|
||||
res: Res,
|
||||
pats: &[hir::Pat<'_>],
|
||||
dotdot: Option<usize>,
|
||||
dotdot: hir::DotDotPos,
|
||||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
_ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
|
||||
};
|
||||
let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
|
||||
let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len());
|
||||
let first_n = pats.iter().enumerate().take(dotdot);
|
||||
let missing = variant.fields.len() - pats.len();
|
||||
let last_n = pats
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(dotdot.unwrap_or(pats.len()))
|
||||
.map(|(idx, pat)| (idx + missing, pat));
|
||||
let last_n = pats.iter().enumerate().skip(dotdot).map(|(idx, pat)| (idx + missing, pat));
|
||||
for (idx, pat) in first_n.chain(last_n) {
|
||||
if let PatKind::Wild = pat.kind {
|
||||
continue;
|
||||
|
|
|
@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pat: &'tcx Pat<'tcx>,
|
||||
qpath: &'tcx hir::QPath<'tcx>,
|
||||
subpats: &'tcx [Pat<'tcx>],
|
||||
ddpos: Option<usize>,
|
||||
ddpos: hir::DotDotPos,
|
||||
expected: Ty<'tcx>,
|
||||
def_bm: BindingMode,
|
||||
ti: TopInfo<'tcx>,
|
||||
|
@ -1066,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Type-check subpatterns.
|
||||
if subpats.len() == variant.fields.len()
|
||||
|| subpats.len() < variant.fields.len() && ddpos.is_some()
|
||||
|| subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
|
||||
{
|
||||
let ty::Adt(_, substs) = pat_ty.kind() else {
|
||||
bug!("unexpected pattern type {:?}", pat_ty);
|
||||
|
@ -1254,14 +1254,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
span: Span,
|
||||
elements: &'tcx [Pat<'tcx>],
|
||||
ddpos: Option<usize>,
|
||||
ddpos: hir::DotDotPos,
|
||||
expected: Ty<'tcx>,
|
||||
def_bm: BindingMode,
|
||||
ti: TopInfo<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let mut expected_len = elements.len();
|
||||
if ddpos.is_some() {
|
||||
if ddpos.as_opt_usize().is_some() {
|
||||
// Require known type only when `..` is present.
|
||||
if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
|
||||
expected_len = tys.len();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue