Skip to content

Commit

Permalink
Use a Vec instead of a slice in DeconstructedPat
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Jan 25, 2024
1 parent acd463f commit 7d27cad
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 55 deletions.
8 changes: 4 additions & 4 deletions compiler/rustc_pattern_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pub trait TypeCx: Sized + fmt::Debug {
fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;

/// Best-effort `Debug` implementation.
fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<Self>) -> fmt::Result;

/// Raise a bug.
fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
Expand All @@ -121,9 +121,9 @@ pub trait TypeCx: Sized + fmt::Debug {
/// The default implementation does nothing.
fn lint_overlapping_range_endpoints(
&self,
_pat: &DeconstructedPat<'_, Self>,
_pat: &DeconstructedPat<Self>,
_overlaps_on: IntRange,
_overlaps_with: &[&DeconstructedPat<'_, Self>],
_overlaps_with: &[&DeconstructedPat<Self>],
) {
}
}
Expand All @@ -133,7 +133,7 @@ pub trait TypeCx: Sized + fmt::Debug {
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""))]
pub struct MatchArm<'p, Cx: TypeCx> {
pub pat: &'p DeconstructedPat<'p, Cx>,
pub pat: &'p DeconstructedPat<Cx>,
pub has_guard: bool,
pub arm_data: Cx::ArmData,
}
Expand Down
32 changes: 19 additions & 13 deletions compiler/rustc_pattern_analysis/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::fmt;
use smallvec::{smallvec, SmallVec};

use crate::constructor::{Constructor, Slice, SliceKind};
use crate::{Captures, TypeCx};
use crate::TypeCx;

use self::Constructor::*;

Expand All @@ -21,9 +21,9 @@ use self::Constructor::*;
/// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't
/// observe that it is uninhabited. In that case that field is not included in `fields`. Care must
/// be taken when converting to/from `thir::Pat`.
pub struct DeconstructedPat<'p, Cx: TypeCx> {
pub struct DeconstructedPat<Cx: TypeCx> {
ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>],
fields: Vec<DeconstructedPat<Cx>>,
ty: Cx::Ty,
/// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
/// correspond to a user-supplied pattern.
Expand All @@ -32,14 +32,20 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> {
useful: Cell<bool>,
}

impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
impl<Cx: TypeCx> DeconstructedPat<Cx> {
pub fn wildcard(ty: Cx::Ty) -> Self {
DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) }
DeconstructedPat {
ctor: Wildcard,
fields: Vec::new(),
ty,
data: None,
useful: Cell::new(false),
}
}

pub fn new(
ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>],
fields: Vec<DeconstructedPat<Cx>>,
ty: Cx::Ty,
data: Cx::PatData,
) -> Self {
Expand All @@ -62,17 +68,17 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
self.data.as_ref()
}

pub fn iter_fields(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> {
pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a DeconstructedPat<Cx>> {
self.fields.iter()
}

/// Specialize this pattern with a constructor.
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
pub(crate) fn specialize(
&self,
pub(crate) fn specialize<'a>(
&'a self,
other_ctor: &Constructor<Cx>,
ctor_arity: usize,
) -> SmallVec<[PatOrWild<'p, Cx>; 2]> {
) -> SmallVec<[PatOrWild<'a, Cx>; 2]> {
let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect();
match (&self.ctor, other_ctor) {
// Return a wildcard for each field of `other_ctor`.
Expand Down Expand Up @@ -139,7 +145,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
}

/// This is best effort and not good enough for a `Display` impl.
impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Cx::debug_pat(f, self)
}
Expand All @@ -155,11 +161,11 @@ pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
/// A non-user-provided wildcard, created during specialization.
Wild,
/// A user-provided pattern.
Pat(&'p DeconstructedPat<'p, Cx>),
Pat(&'p DeconstructedPat<Cx>),
}

impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> {
pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<Cx>> {
match self {
PatOrWild::Wild => None,
PatOrWild::Pat(pat) => Some(pat),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_pattern_analysis/src/pat_column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{Captures, MatchArm, TypeCx};
#[derive(Debug)]
pub struct PatternColumn<'p, Cx: TypeCx> {
/// This must not contain an or-pattern. `expand_and_push` takes care to expand them.
patterns: Vec<&'p DeconstructedPat<'p, Cx>>,
patterns: Vec<&'p DeconstructedPat<Cx>>,
}

impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
Expand Down Expand Up @@ -41,7 +41,7 @@ impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
pub fn head_ty(&self) -> Option<&Cx::Ty> {
self.patterns.first().map(|pat| pat.ty())
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'a> {
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<Cx>> + Captures<'a> {
self.patterns.iter().copied()
}

Expand Down
59 changes: 25 additions & 34 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use smallvec::SmallVec;
use std::fmt;
use std::iter::once;

Expand Down Expand Up @@ -28,8 +27,7 @@ use crate::constructor::Constructor::*;
pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcMatchCheckCtxt<'p, 'tcx>>;
pub type ConstructorSet<'p, 'tcx> =
crate::constructor::ConstructorSet<RustcMatchCheckCtxt<'p, 'tcx>>;
pub type DeconstructedPat<'p, 'tcx> =
crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat<RustcMatchCheckCtxt<'p, 'tcx>>;
pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
pub type UsefulnessReport<'p, 'tcx> =
Expand Down Expand Up @@ -452,21 +450,20 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
/// Note: the input patterns must have been lowered through
/// `rustc_mir_build::thir::pattern::check_match::MatchVisitor::lower_pattern`.
pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat));
let cx = self;
let ty = cx.reveal_opaque_ty(pat.ty);
let ctor;
let fields: &[_];
let mut fields: Vec<_>;
match &pat.kind {
PatKind::AscribeUserType { subpattern, .. }
| PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
ctor = Wildcard;
fields = &[];
fields = vec![];
}
PatKind::Deref { subpattern } => {
fields = singleton(self.lower_pat(subpattern));
fields = vec![self.lower_pat(subpattern)];
ctor = match ty.kind() {
// This is a box pattern.
ty::Adt(adt, ..) if adt.is_box() => Struct,
Expand All @@ -478,15 +475,14 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
match ty.kind() {
ty::Tuple(fs) => {
ctor = Struct;
let mut wilds: SmallVec<[_; 2]> = fs
fields = fs
.iter()
.map(|ty| cx.reveal_opaque_ty(ty))
.map(|ty| DeconstructedPat::wildcard(ty))
.collect();
for pat in subpatterns {
wilds[pat.field.index()] = self.lower_pat(&pat.pattern);
fields[pat.field.index()] = self.lower_pat(&pat.pattern);
}
fields = cx.pattern_arena.alloc_from_iter(wilds);
}
ty::Adt(adt, args) if adt.is_box() => {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
Expand All @@ -508,7 +504,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
DeconstructedPat::wildcard(self.reveal_opaque_ty(args.type_at(0)))
};
ctor = Struct;
fields = singleton(pat);
fields = vec![pat];
}
ty::Adt(adt, _) => {
ctor = match pat.kind {
Expand All @@ -528,14 +524,12 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
ty
},
);
let mut wilds: SmallVec<[_; 2]> =
tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
fields = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
for pat in subpatterns {
if let Some(i) = field_id_to_id[pat.field.index()] {
wilds[i] = self.lower_pat(&pat.pattern);
fields[i] = self.lower_pat(&pat.pattern);
}
}
fields = cx.pattern_arena.alloc_from_iter(wilds);
}
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
}
Expand All @@ -547,7 +541,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
Some(b) => Bool(b),
None => Opaque(OpaqueId::new()),
};
fields = &[];
fields = vec![];
}
ty::Char | ty::Int(_) | ty::Uint(_) => {
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
Expand All @@ -563,7 +557,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
}
None => Opaque(OpaqueId::new()),
};
fields = &[];
fields = vec![];
}
ty::Float(ty::FloatTy::F32) => {
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
Expand All @@ -574,7 +568,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
}
None => Opaque(OpaqueId::new()),
};
fields = &[];
fields = vec![];
}
ty::Float(ty::FloatTy::F64) => {
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
Expand All @@ -585,7 +579,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
}
None => Opaque(OpaqueId::new()),
};
fields = &[];
fields = vec![];
}
ty::Ref(_, t, _) if t.is_str() => {
// We want a `&str` constant to behave like a `Deref` pattern, to be compatible
Expand All @@ -596,16 +590,16 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
// subfields.
// Note: `t` is `str`, not `&str`.
let ty = self.reveal_opaque_ty(*t);
let subpattern = DeconstructedPat::new(Str(*value), &[], ty, pat);
let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), ty, pat);
ctor = Ref;
fields = singleton(subpattern)
fields = vec![subpattern]
}
// All constants that can be structurally matched have already been expanded
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
// opaque.
_ => {
ctor = Opaque(OpaqueId::new());
fields = &[];
fields = vec![];
}
}
}
Expand Down Expand Up @@ -642,7 +636,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
}
_ => bug!("invalid type for range pattern: {}", ty.inner()),
};
fields = &[];
fields = vec![];
}
PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
let array_len = match ty.kind() {
Expand All @@ -658,25 +652,22 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
SliceKind::FixedLen(prefix.len() + suffix.len())
};
ctor = Slice(Slice::new(array_len, kind));
fields = cx.pattern_arena.alloc_from_iter(
prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)),
)
fields = prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)).collect();
}
PatKind::Or { .. } => {
ctor = Or;
let pats = expand_or_pat(pat);
fields =
cx.pattern_arena.alloc_from_iter(pats.into_iter().map(|p| self.lower_pat(p)))
fields = pats.into_iter().map(|p| self.lower_pat(p)).collect();
}
PatKind::Never => {
// FIXME(never_patterns): handle `!` in exhaustiveness. This is a sane default
// in the meantime.
ctor = Wildcard;
fields = &[];
fields = vec![];
}
PatKind::Error(_) => {
ctor = Opaque(OpaqueId::new());
fields = &[];
fields = vec![];
}
}
DeconstructedPat::new(ctor, fields, ty, pat)
Expand Down Expand Up @@ -849,7 +840,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
/// Best-effort `Debug` implementation.
pub(crate) fn debug_pat(
f: &mut fmt::Formatter<'_>,
pat: &crate::pat::DeconstructedPat<'_, Self>,
pat: &crate::pat::DeconstructedPat<Self>,
) -> fmt::Result {
let mut first = true;
let mut start_or_continue = |s| {
Expand Down Expand Up @@ -975,7 +966,7 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {

fn debug_pat(
f: &mut fmt::Formatter<'_>,
pat: &crate::pat::DeconstructedPat<'_, Self>,
pat: &crate::pat::DeconstructedPat<Self>,
) -> fmt::Result {
Self::debug_pat(f, pat)
}
Expand All @@ -985,9 +976,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {

fn lint_overlapping_range_endpoints(
&self,
pat: &crate::pat::DeconstructedPat<'_, Self>,
pat: &crate::pat::DeconstructedPat<Self>,
overlaps_on: IntRange,
overlaps_with: &[&crate::pat::DeconstructedPat<'_, Self>],
overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
) {
let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty());
let overlaps: Vec<_> = overlaps_with
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ struct PatStack<'p, Cx: TypeCx> {
}

impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self {
fn from_pattern(pat: &'p DeconstructedPat<Cx>) -> Self {
PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
}

Expand Down Expand Up @@ -1537,7 +1537,7 @@ pub enum Usefulness<'p, Cx: TypeCx> {
/// The arm is useful. This additionally carries a set of or-pattern branches that have been
/// found to be redundant despite the overall arm being useful. Used only in the presence of
/// or-patterns, otherwise it stays empty.
Useful(Vec<&'p DeconstructedPat<'p, Cx>>),
Useful(Vec<&'p DeconstructedPat<Cx>>),
/// The arm is redundant and can be removed without changing the behavior of the match
/// expression.
Redundant,
Expand Down

0 comments on commit 7d27cad

Please sign in to comment.