use rustc::lint;
use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
use rustc::mir::Field;
+use rustc::util::captures::Captures;
use rustc::util::common::ErrorReported;
use syntax::attr::{SignedInt, UnsignedInt};
}
}
-/// A 2D matrix. Nx1 matrices are very common, which is why `SmallVec[_; 2]`
-/// works well for each row.
-pub struct Matrix<'p, 'tcx>(Vec<SmallVec<[&'p Pat<'tcx>; 2]>>);
+/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
+/// works well.
+#[derive(Debug, Clone)]
+pub struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>);
+
+impl<'p, 'tcx> PatStack<'p, 'tcx> {
+ pub fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
+ PatStack(smallvec![pat])
+ }
+
+ fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
+ PatStack(vec)
+ }
+
+ fn from_slice(s: &[&'p Pat<'tcx>]) -> Self {
+ PatStack(SmallVec::from_slice(s))
+ }
+
+ fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ fn head(&self) -> &'p Pat<'tcx> {
+ self.0[0]
+ }
+
+ fn to_tail(&self) -> Self {
+ PatStack::from_slice(&self.0[1..])
+ }
+
+ fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
+ self.0.iter().map(|p| *p)
+ }
+
+ /// This computes `D(self)`. See top of the file for explanations.
+ fn specialize_wildcard(&self) -> Option<Self> {
+ if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
+ }
+
+ /// This computes `S(constructor, self)`. See top of the file for explanations.
+ fn specialize_constructor<'a, 'q>(
+ &self,
+ cx: &mut MatchCheckCtxt<'a, 'tcx>,
+ constructor: &Constructor<'tcx>,
+ wild_patterns: &[&'q Pat<'tcx>],
+ ) -> Option<PatStack<'q, 'tcx>>
+ where
+ 'a: 'q,
+ 'p: 'q,
+ {
+ specialize(cx, self, constructor, wild_patterns)
+ }
+}
+
+impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
+ fn default() -> Self {
+ PatStack(smallvec![])
+ }
+}
+
+impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = &'p Pat<'tcx>>,
+ {
+ PatStack(iter.into_iter().collect())
+ }
+}
+
+/// A 2D matrix.
+pub struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
impl<'p, 'tcx> Matrix<'p, 'tcx> {
pub fn empty() -> Self {
Matrix(vec![])
}
- pub fn push(&mut self, row: SmallVec<[&'p Pat<'tcx>; 2]>) {
+ pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
self.0.push(row)
}
+
+ /// Iterate over the first component of each row
+ fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
+ self.0.iter().map(|r| r.head())
+ }
+
+ /// This computes `D(self)`. See top of the file for explanations.
+ fn specialize_wildcard(&self) -> Self {
+ self.0.iter().filter_map(|r| r.specialize_wildcard()).collect()
+ }
+
+ /// This computes `S(constructor, self)`. See top of the file for explanations.
+ fn specialize_constructor<'a, 'q>(
+ &self,
+ cx: &mut MatchCheckCtxt<'a, 'tcx>,
+ constructor: &Constructor<'tcx>,
+ wild_patterns: &[&'q Pat<'tcx>],
+ ) -> Matrix<'q, 'tcx>
+ where
+ 'a: 'q,
+ 'p: 'q,
+ {
+ Matrix(
+ self.0
+ .iter()
+ .filter_map(|r| r.specialize_constructor(cx, constructor, wild_patterns))
+ .collect(),
+ )
+ }
}
/// Pretty-printer for matrices of patterns, example:
}
}
-impl<'p, 'tcx> FromIterator<SmallVec<[&'p Pat<'tcx>; 2]>> for Matrix<'p, 'tcx> {
+impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
fn from_iter<T>(iter: T) -> Self
where
- T: IntoIterator<Item = SmallVec<[&'p Pat<'tcx>; 2]>>,
+ T: IntoIterator<Item = PatStack<'p, 'tcx>>,
{
Matrix(iter.into_iter().collect())
}
_ => bug!("bad constructor being displayed: `{:?}", self),
}
}
+
+ fn wildcard_subpatterns<'a>(
+ &self,
+ cx: &MatchCheckCtxt<'a, 'tcx>,
+ ty: Ty<'tcx>,
+ ) -> Vec<Pat<'tcx>> {
+ constructor_sub_pattern_tys(cx, self, ty)
+ .into_iter()
+ .map(|ty| Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild })
+ .collect()
+ }
+
+ /// This computes the arity of a constructor. The arity of a constructor
+ /// is how many subpattern patterns of that constructor should be expanded to.
+ ///
+ /// For instance, a tuple pattern `(_, 42, Some([]))` has the arity of 3.
+ /// A struct pattern's arity is the number of fields it contains, etc.
+ fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 {
+ debug!("Constructor::arity({:#?}, {:?})", self, ty);
+ match ty.kind {
+ ty::Tuple(ref fs) => fs.len() as u64,
+ ty::Slice(..) | ty::Array(..) => match *self {
+ Slice(length) => length,
+ ConstantValue(..) => 0,
+ _ => bug!("bad slice pattern {:?} {:?}", self, ty),
+ },
+ ty::Ref(..) => 1,
+ ty::Adt(adt, _) => {
+ adt.variants[self.variant_index_for_adt(cx, adt)].fields.len() as u64
+ }
+ _ => 0,
+ }
+ }
+
+ /// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
+ /// must have as many elements as this constructor's arity.
+ ///
+ /// Examples:
+ /// self: Single
+ /// ty: tuple of 3 elements
+ /// pats: [10, 20, _] => (10, 20, _)
+ ///
+ /// self: Option::Some
+ /// ty: Option<bool>
+ /// pats: [false] => Some(false)
+ fn apply<'a>(
+ &self,
+ cx: &MatchCheckCtxt<'a, 'tcx>,
+ ty: Ty<'tcx>,
+ pats: impl IntoIterator<Item = Pat<'tcx>>,
+ ) -> Pat<'tcx> {
+ let mut pats = pats.into_iter();
+ let pat = match ty.kind {
+ ty::Adt(..) | ty::Tuple(..) => {
+ let pats = pats
+ .enumerate()
+ .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+ .collect();
+
+ if let ty::Adt(adt, substs) = ty.kind {
+ if adt.is_enum() {
+ PatKind::Variant {
+ adt_def: adt,
+ substs,
+ variant_index: self.variant_index_for_adt(cx, adt),
+ subpatterns: pats,
+ }
+ } else {
+ PatKind::Leaf { subpatterns: pats }
+ }
+ } else {
+ PatKind::Leaf { subpatterns: pats }
+ }
+ }
+
+ ty::Ref(..) => PatKind::Deref { subpattern: pats.nth(0).unwrap() },
+
+ ty::Slice(_) | ty::Array(..) => {
+ PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] }
+ }
+
+ _ => match *self {
+ ConstantValue(value, _) => PatKind::Constant { value },
+ ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange {
+ lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
+ hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
+ end,
+ }),
+ _ => PatKind::Wild,
+ },
+ };
+
+ Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
+ }
}
#[derive(Clone, Debug)]
ctor: &Constructor<'tcx>,
ty: Ty<'tcx>,
) -> Self {
- let sub_pattern_tys = constructor_sub_pattern_tys(cx, ctor, ty);
- self.0.extend(sub_pattern_tys.into_iter().map(|ty| Pat {
- ty,
- span: DUMMY_SP,
- kind: box PatKind::Wild,
- }));
+ self.0.extend(ctor.wildcard_subpatterns(cx, ty));
self.apply_constructor(cx, ctor, ty)
}
ctor: &Constructor<'tcx>,
ty: Ty<'tcx>,
) -> Self {
- let arity = constructor_arity(cx, ctor, ty);
+ let arity = ctor.arity(cx, ty);
let pat = {
let len = self.0.len() as u64;
- let mut pats = self.0.drain((len - arity) as usize..).rev();
-
- match ty.kind {
- ty::Adt(..) | ty::Tuple(..) => {
- let pats = pats
- .enumerate()
- .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
- .collect();
-
- if let ty::Adt(adt, substs) = ty.kind {
- if adt.is_enum() {
- PatKind::Variant {
- adt_def: adt,
- substs,
- variant_index: ctor.variant_index_for_adt(cx, adt),
- subpatterns: pats,
- }
- } else {
- PatKind::Leaf { subpatterns: pats }
- }
- } else {
- PatKind::Leaf { subpatterns: pats }
- }
- }
-
- ty::Ref(..) => PatKind::Deref { subpattern: pats.nth(0).unwrap() },
-
- ty::Slice(_) | ty::Array(..) => {
- PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] }
- }
-
- _ => match *ctor {
- ConstantValue(value, _) => PatKind::Constant { value },
- ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange {
- lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
- hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
- end,
- }),
- _ => PatKind::Wild,
- },
- }
+ let pats = self.0.drain((len - arity) as usize..).rev();
+ ctor.apply(cx, ty, pats)
};
- self.0.push(Pat { ty, span: DUMMY_SP, kind: Box::new(pat) });
+ self.0.push(pat);
self
}
}
}
-// A request for missing constructor data in terms of either:
-// - whether or not there any missing constructors; or
-// - the actual set of missing constructors.
-#[derive(PartialEq)]
-enum MissingCtorsInfo {
- Emptiness,
- Ctors,
-}
-
-// Used by `compute_missing_ctors`.
-#[derive(Debug, PartialEq)]
-enum MissingCtors<'tcx> {
- Empty,
- NonEmpty,
-
- // Note that the Vec can be empty.
- Ctors(Vec<Constructor<'tcx>>),
-}
-
-// When `info` is `MissingCtorsInfo::Ctors`, compute a set of constructors
-// equivalent to `all_ctors \ used_ctors`. When `info` is
-// `MissingCtorsInfo::Emptiness`, just determines if that set is empty or not.
-// (The split logic gives a performance win, because we always need to know if
-// the set is empty, but we rarely need the full set, and it can be expensive
-// to compute the full set.)
-fn compute_missing_ctors<'tcx>(
- info: MissingCtorsInfo,
+type MissingConstructors<'a, 'tcx, F> =
+ std::iter::FlatMap<std::slice::Iter<'a, Constructor<'tcx>>, Vec<Constructor<'tcx>>, F>;
+// Compute a set of constructors equivalent to `all_ctors \ used_ctors`. This
+// returns an iterator, so that we only construct the whole set if needed.
+fn compute_missing_ctors<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- all_ctors: &Vec<Constructor<'tcx>>,
- used_ctors: &Vec<Constructor<'tcx>>,
-) -> MissingCtors<'tcx> {
- let mut missing_ctors = vec![];
-
- for req_ctor in all_ctors {
+ all_ctors: &'a Vec<Constructor<'tcx>>,
+ used_ctors: &'a Vec<Constructor<'tcx>>,
+) -> MissingConstructors<'a, 'tcx, impl FnMut(&'a Constructor<'tcx>) -> Vec<Constructor<'tcx>>> {
+ all_ctors.iter().flat_map(move |req_ctor| {
let mut refined_ctors = vec![req_ctor.clone()];
for used_ctor in used_ctors {
if used_ctor == req_ctor {
}
// If the constructor patterns that have been considered so far
- // already cover the entire range of values, then we the
+ // already cover the entire range of values, then we know the
// constructor is not missing, and we can move on to the next one.
if refined_ctors.is_empty() {
break;
}
}
+
// If a constructor has not been matched, then it is missing.
// We add `refined_ctors` instead of `req_ctor`, because then we can
// provide more detailed error information about precisely which
// ranges have been omitted.
- if info == MissingCtorsInfo::Emptiness {
- if !refined_ctors.is_empty() {
- // The set is non-empty; return early.
- return MissingCtors::NonEmpty;
- }
- } else {
- missing_ctors.extend(refined_ctors);
- }
- }
-
- if info == MissingCtorsInfo::Emptiness {
- // If we reached here, the set is empty.
- MissingCtors::Empty
- } else {
- MissingCtors::Ctors(missing_ctors)
- }
+ refined_ctors
+ })
}
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
pub fn is_useful<'p, 'a, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
- v: &[&Pat<'tcx>],
+ v: &PatStack<'_, 'tcx>,
witness: WitnessPreference,
hir_id: HirId,
) -> Usefulness<'tcx> {
assert!(rows.iter().all(|r| r.len() == v.len()));
- let (ty, span) = rows
- .iter()
- .map(|r| (r[0].ty, r[0].span))
+ let (ty, span) = matrix
+ .heads()
+ .map(|r| (r.ty, r.span))
.find(|(ty, _)| !ty.references_error())
- .unwrap_or((v[0].ty, v[0].span));
+ .unwrap_or((v.head().ty, v.head().span));
let pcx = PatCtxt {
// TyErr is used to represent the type of wildcard patterns matching
// against inaccessible (private) fields of structs, so that we won't
// introducing uninhabited patterns for inaccessible fields. We
// need to figure out how to model that.
ty,
- max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))),
+ max_slice_length: max_slice_length(cx, matrix.heads().chain(Some(v.head()))),
span,
};
- debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
+ debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
- if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
+ if let Some(constructors) = pat_constructors(cx, v.head(), pcx) {
debug!("is_useful - expanding constructors: {:#?}", constructors);
split_grouped_constructors(
cx.tcx,
} else {
debug!("is_useful - expanding wildcard");
- let used_ctors: Vec<Constructor<'_>> = rows
- .iter()
- .flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
- .collect();
+ let used_ctors: Vec<Constructor<'_>> =
+ matrix.heads().flat_map(|p| pat_constructors(cx, p, pcx).unwrap_or(vec![])).collect();
debug!("used_ctors = {:#?}", used_ctors);
// `all_ctors` are all the constructors for the given type, which
// should all be represented (or caught with the wild pattern `_`).
// needed for that case.
// Missing constructors are those that are not matched by any
- // non-wildcard patterns in the current column. We always determine if
- // the set is empty, but we only fully construct them on-demand,
- // because they're rarely used and can be big.
- let cheap_missing_ctors = compute_missing_ctors(
- MissingCtorsInfo::Emptiness,
- cx.tcx,
- cx.param_env,
- &all_ctors,
- &used_ctors,
- );
+ // non-wildcard patterns in the current column. To determine if
+ // the set is empty, we can check that `.peek().is_none()`, so
+ // we only fully construct them on-demand, because they're rarely used and can be big.
+ let mut missing_ctors =
+ compute_missing_ctors(cx.tcx, cx.param_env, &all_ctors, &used_ctors).peekable();
let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
debug!(
- "cheap_missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
- cheap_missing_ctors, is_privately_empty, is_declared_nonexhaustive
+ "missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
+ missing_ctors.peek().is_none(),
+ is_privately_empty,
+ is_declared_nonexhaustive
);
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
|| is_declared_nonexhaustive
|| (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
- if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
+ if missing_ctors.peek().is_none() && !is_non_exhaustive {
+ drop(missing_ctors); // It was borrowing `all_ctors`, which we want to move.
split_grouped_constructors(
cx.tcx,
cx.param_env,
.find(|result| result.is_useful())
.unwrap_or(NotUseful)
} else {
- let matrix = rows
- .iter()
- .filter_map(|r| {
- if r[0].is_wildcard() { Some(SmallVec::from_slice(&r[1..])) } else { None }
- })
- .collect();
- match is_useful(cx, &matrix, &v[1..], witness, hir_id) {
+ let matrix = matrix.specialize_wildcard();
+ let v = v.to_tail();
+ match is_useful(cx, &matrix, &v, witness, hir_id) {
UsefulWithWitness(pats) => {
let cx = &*cx;
// In this case, there's at least one "free"
})
.collect()
} else {
- let expensive_missing_ctors = compute_missing_ctors(
- MissingCtorsInfo::Ctors,
- cx.tcx,
- cx.param_env,
- &all_ctors,
- &used_ctors,
- );
- if let MissingCtors::Ctors(missing_ctors) = expensive_missing_ctors {
- pats.into_iter()
- .flat_map(|witness| {
- missing_ctors.iter().map(move |ctor| {
- // Extends the witness with a "wild" version of this
- // constructor, that matches everything that can be built with
- // it. For example, if `ctor` is a `Constructor::Variant` for
- // `Option::Some`, this pushes the witness for `Some(_)`.
- witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
- })
+ let missing_ctors: Vec<_> = missing_ctors.collect();
+ pats.into_iter()
+ .flat_map(|witness| {
+ missing_ctors.iter().map(move |ctor| {
+ // Extends the witness with a "wild" version of this
+ // constructor, that matches everything that can be built with
+ // it. For example, if `ctor` is a `Constructor::Variant` for
+ // `Option::Some`, this pushes the witness for `Some(_)`.
+ witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
})
- .collect()
- } else {
- bug!("cheap missing ctors")
- }
+ })
+ .collect()
};
UsefulWithWitness(new_witnesses)
}
/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
fn is_useful_specialized<'p, 'a, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
- &Matrix(ref m): &Matrix<'p, 'tcx>,
- v: &[&Pat<'tcx>],
+ matrix: &Matrix<'p, 'tcx>,
+ v: &PatStack<'_, 'tcx>,
ctor: Constructor<'tcx>,
lty: Ty<'tcx>,
witness: WitnessPreference,
hir_id: HirId,
) -> Usefulness<'tcx> {
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
- let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
- let wild_patterns_owned: Vec<_> =
- sub_pat_tys.iter().map(|ty| Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild }).collect();
+
+ let wild_patterns_owned = ctor.wildcard_subpatterns(cx, lty);
let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
- let matrix =
- Matrix(m.iter().filter_map(|r| specialize(cx, &r, &ctor, &wild_patterns)).collect());
- match specialize(cx, v, &ctor, &wild_patterns) {
+ let matrix = matrix.specialize_constructor(cx, &ctor, &wild_patterns);
+ match v.specialize_constructor(cx, &ctor, &wild_patterns) {
Some(v) => match is_useful(cx, &matrix, &v, witness, hir_id) {
UsefulWithWitness(witnesses) => UsefulWithWitness(
witnesses
}
}
-/// This computes the arity of a constructor. The arity of a constructor
-/// is how many subpattern patterns of that constructor should be expanded to.
-///
-/// For instance, a tuple pattern `(_, 42, Some([]))` has the arity of 3.
-/// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> u64 {
- debug!("constructor_arity({:#?}, {:?})", ctor, ty);
- match ty.kind {
- ty::Tuple(ref fs) => fs.len() as u64,
- ty::Slice(..) | ty::Array(..) => match *ctor {
- Slice(length) => length,
- ConstantValue(..) => 0,
- _ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
- },
- ty::Ref(..) => 1,
- ty::Adt(adt, _) => adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.len() as u64,
- _ => 0,
- }
-}
-
/// This computes the types of the sub patterns that a constructor should be
/// expanded to.
///
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ctors: Vec<Constructor<'tcx>>,
- &Matrix(ref m): &Matrix<'p, 'tcx>,
+ matrix: &Matrix<'p, 'tcx>,
ty: Ty<'tcx>,
span: Span,
hir_id: Option<HirId>,
let mut overlaps = vec![];
// `borders` is the set of borders between equivalence classes: each equivalence
// class lies between 2 borders.
- let row_borders = m
+ let row_borders = matrix
+ .0
.iter()
.flat_map(|row| {
- IntRange::from_pat(tcx, param_env, row[0]).map(|r| (r, row.len()))
+ IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len()))
})
.flat_map(|(range, row_len)| {
let intersection = ctor_range.intersection(&range);
subpatterns: &'p [FieldPat<'tcx>],
wild_patterns: &[&'p Pat<'tcx>],
is_non_exhaustive: bool,
-) -> SmallVec<[&'p Pat<'tcx>; 2]> {
+) -> PatStack<'p, 'tcx> {
let mut result = SmallVec::from_slice(wild_patterns);
for subpat in subpatterns {
}
debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
- result
+ PatStack::from_vec(result)
}
/// This is the main specialization step. It expands the first pattern in the given row
/// different patterns.
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
/// fields filled with wild patterns.
-fn specialize<'p, 'a: 'p, 'tcx>(
+fn specialize<'p, 'a: 'p, 'q: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
- r: &[&'p Pat<'tcx>],
+ r: &PatStack<'q, 'tcx>,
constructor: &Constructor<'tcx>,
wild_patterns: &[&'p Pat<'tcx>],
-) -> Option<SmallVec<[&'p Pat<'tcx>; 2]>> {
- let pat = &r[0];
+) -> Option<PatStack<'p, 'tcx>> {
+ let pat = r.head();
- let head = match *pat.kind {
+ let new_head = match *pat.kind {
PatKind::AscribeUserType { ref subpattern, .. } => {
- specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns)
+ specialize(cx, &PatStack::from_pattern(subpattern), constructor, wild_patterns)
}
- PatKind::Binding { .. } | PatKind::Wild => Some(SmallVec::from_slice(wild_patterns)),
+ PatKind::Binding { .. } | PatKind::Wild => Some(PatStack::from_slice(wild_patterns)),
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
let ref variant = adt_def.variants[variant_index];
Some(patterns_for_variant(cx, subpatterns, wild_patterns, false))
}
- PatKind::Deref { ref subpattern } => Some(smallvec![subpattern]),
+ PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
PatKind::Constant { value } if constructor.is_slice() => {
// We extract an `Option` for the pointer because slices of zero
let (pat_lo, pat_hi) = pat.range.into_inner();
let (ctor_lo, ctor_hi) = ctor.range.into_inner();
assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
- smallvec![]
+ PatStack::default()
}),
_ => None,
}
// range so intersection actually devolves into being covered
// by the pattern.
match constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat) {
- Ok(true) => Some(smallvec![]),
+ Ok(true) => Some(PatStack::default()),
Ok(false) | Err(ErrorReported) => None,
}
}
suffix,
cx.param_env,
) {
- Ok(true) => Some(smallvec![]),
+ Ok(true) => Some(PatStack::default()),
Ok(false) => None,
Err(ErrorReported) => None,
}
bug!("support for or-patterns has not been fully implemented yet.");
}
};
- debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
+ debug!("specialize({:#?}, {:#?}) = {:#?}", r.head(), wild_patterns, new_head);
- head.map(|mut head| {
- head.extend_from_slice(&r[1..]);
- head
+ new_head.map(|head| {
+ let mut head = head.0;
+ head.extend_from_slice(&r.0[1..]);
+ PatStack::from_vec(head)
})
}