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};
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>,
+ ctor_wild_subpatterns: &[&'q Pat<'tcx>],
+ ) -> Option<PatStack<'q, 'tcx>>
+ where
+ 'a: 'q,
+ 'p: 'q,
+ {
+ let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
+ new_heads.map(|mut new_head| {
+ new_head.0.extend_from_slice(&self.0[1..]);
+ new_head
+ })
+ }
}
impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
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>,
+ ctor_wild_subpatterns: &[&'q Pat<'tcx>],
+ ) -> Matrix<'q, 'tcx>
+ where
+ 'a: 'q,
+ 'p: 'q,
+ {
+ Matrix(
+ self.0
+ .iter()
+ .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
+ .collect(),
+ )
+ }
}
/// Pretty-printer for matrices of patterns, example:
_ => bug!("bad constructor being displayed: `{:?}", self),
}
}
+
+ /// This returns one wildcard pattern for each argument to this constructor.
+ fn wildcard_subpatterns<'a>(
+ &self,
+ cx: &MatchCheckCtxt<'a, 'tcx>,
+ ty: Ty<'tcx>,
+ ) -> impl Iterator<Item = Pat<'tcx>> + DoubleEndedIterator {
+ constructor_sub_pattern_tys(cx, self, ty).into_iter().map(|ty| Pat {
+ ty,
+ span: DUMMY_SP,
+ kind: box PatKind::Wild,
+ })
+ }
+
+ /// 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) }
+ }
+
+ /// Like `apply`, but where all the subpatterns are wildcards `_`.
+ fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
+ let pats = self.wildcard_subpatterns(cx, ty).rev();
+ self.apply(cx, ty, pats)
+ }
}
#[derive(Clone, Debug)]
self.0.into_iter().next().unwrap()
}
- fn push_wild_constructor<'a>(
- mut self,
- cx: &MatchCheckCtxt<'a, 'tcx>,
- 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.apply_constructor(cx, ctor, ty)
- }
-
/// Constructs a partial witness for a pattern given a list of
/// patterns expanded by the specialization step.
///
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,
+// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
+struct MissingConstructors<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ all_ctors: Vec<Constructor<'tcx>>,
+ used_ctors: Vec<Constructor<'tcx>>,
}
-// Used by `compute_missing_ctors`.
-#[derive(Debug, PartialEq)]
-enum MissingCtors<'tcx> {
- Empty,
- NonEmpty,
+impl<'tcx> MissingConstructors<'tcx> {
+ fn new(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ all_ctors: Vec<Constructor<'tcx>>,
+ used_ctors: Vec<Constructor<'tcx>>,
+ ) -> Self {
+ MissingConstructors { tcx, param_env, all_ctors, used_ctors }
+ }
+
+ fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
+ (self.all_ctors, self.used_ctors)
+ }
- // Note that the Vec can be empty.
- Ctors(Vec<Constructor<'tcx>>),
-}
+ fn is_empty(&self) -> bool {
+ self.iter().next().is_none()
+ }
+ /// Whether this contains all the constructors for the given type or only a
+ /// subset.
+ fn all_ctors_are_missing(&self) -> bool {
+ self.used_ctors.is_empty()
+ }
-// 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,
- 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 {
- let mut refined_ctors = vec![req_ctor.clone()];
- for used_ctor in used_ctors {
- if used_ctor == req_ctor {
- // If a constructor appears in a `match` arm, we can
- // eliminate it straight away.
- refined_ctors = vec![]
- } else if let Some(interval) = IntRange::from_ctor(tcx, param_env, used_ctor) {
- // Refine the required constructors for the type by subtracting
- // the range defined by the current constructor pattern.
- refined_ctors = interval.subtract_from(tcx, param_env, refined_ctors);
- }
+ /// Iterate over all_ctors \ used_ctors
+ fn iter<'a>(&'a self) -> impl Iterator<Item = Constructor<'tcx>> + Captures<'a> {
+ self.all_ctors.iter().flat_map(move |req_ctor| {
+ let mut refined_ctors = vec![req_ctor.clone()];
+ for used_ctor in &self.used_ctors {
+ if used_ctor == req_ctor {
+ // If a constructor appears in a `match` arm, we can
+ // eliminate it straight away.
+ refined_ctors = vec![]
+ } else if let Some(interval) =
+ IntRange::from_ctor(self.tcx, self.param_env, used_ctor)
+ {
+ // Refine the required constructors for the type by subtracting
+ // the range defined by the current constructor pattern.
+ refined_ctors = interval.subtract_from(self.tcx, self.param_env, refined_ctors);
+ }
- // If the constructor patterns that have been considered so far
- // already cover the entire range of values, then we 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;
+ // If the constructor patterns that have been considered so far
+ // 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;
+ }
}
- } else {
- missing_ctors.extend(refined_ctors);
- }
+
+ // 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.
+ refined_ctors
+ })
}
+}
- if info == MissingCtorsInfo::Emptiness {
- // If we reached here, the set is empty.
- MissingCtors::Empty
- } else {
- MissingCtors::Ctors(missing_ctors)
+impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let ctors: Vec<_> = self.iter().collect();
+ write!(f, "{:?}", ctors)
}
}
cx: &mut MatchCheckCtxt<'a, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
v: &PatStack<'_, 'tcx>,
- witness: WitnessPreference,
+ witness_preference: WitnessPreference,
hir_id: HirId,
) -> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix;
// the type of the tuple we're checking is inhabited or not.
if v.is_empty() {
return if rows.is_empty() {
- match witness {
+ match witness_preference {
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
LeaveOutWitness => Useful,
}
assert!(rows.iter().all(|r| r.len() == v.len()));
- let (ty, span) = rows
- .iter()
- .map(|r| (r.head().ty, r.head().span))
+ let (ty, span) = matrix
+ .heads()
+ .map(|r| (r.ty, r.span))
.find(|(ty, _)| !ty.references_error())
.unwrap_or((v.head().ty, v.head().span));
let pcx = PatCtxt {
// 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.head()).chain(Some(v.head()))),
+ max_slice_length: max_slice_length(cx, matrix.heads().chain(Some(v.head()))),
span,
};
Some(hir_id),
)
.into_iter()
- .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id))
+ .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
.find(|result| result.is_useful())
.unwrap_or(NotUseful)
} else {
debug!("is_useful - expanding wildcard");
- let used_ctors: Vec<Constructor<'_>> = rows
- .iter()
- .flat_map(|row| pat_constructors(cx, row.head(), 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 `_`).
let all_ctors = all_constructors(cx, pcx);
debug!("all_ctors = {:#?}", all_ctors);
+ 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);
+
// `missing_ctors` is the set of constructors from the same type as the
// first column of `matrix` that are matched only by wildcard patterns
// from the first column.
// 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 missing_ctors = MissingConstructors::new(cx.tcx, cx.param_env, all_ctors, used_ctors);
- 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.is_empty(),
+ 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.is_empty() && !is_non_exhaustive {
+ let (all_ctors, _) = missing_ctors.into_inner();
split_grouped_constructors(
cx.tcx,
cx.param_env,
None,
)
.into_iter()
- .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id))
+ .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
.find(|result| result.is_useful())
.unwrap_or(NotUseful)
} else {
- let matrix = rows
- .iter()
- .filter_map(|r| if r.head().is_wildcard() { Some(r.to_tail()) } else { None })
- .collect();
- match is_useful(cx, &matrix, &v.to_tail(), witness, hir_id) {
- UsefulWithWitness(pats) => {
+ let matrix = matrix.specialize_wildcard();
+ let v = v.to_tail();
+ match is_useful(cx, &matrix, &v, witness_preference, hir_id) {
+ UsefulWithWitness(witnesses) => {
let cx = &*cx;
// In this case, there's at least one "free"
// constructor that is only matched against by
// 1) If the user is matching against a non-exhaustive
// enum, there is no point in enumerating all possible
// variants, because the user can't actually match
- // against them himself, e.g., in an example like:
+ // against them themselves, e.g., in an example like:
// ```
// let err: io::ErrorKind = ...;
// match err {
// `(<direction-1>, <direction-2>, true)` - we are
// satisfied with `(_, _, true)`. In this case,
// `used_ctors` is empty.
- let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() {
- // All constructors are unused. Add wild patterns
+ let new_patterns = if is_non_exhaustive || missing_ctors.all_ctors_are_missing()
+ {
+ // All constructors are unused. Add a wild pattern
// rather than each individual constructor.
- pats.into_iter()
- .map(|mut witness| {
- witness.0.push(Pat {
- ty: pcx.ty,
- span: DUMMY_SP,
- kind: box PatKind::Wild,
- });
- witness
- })
- .collect()
+ vec![Pat { ty: pcx.ty, span: DUMMY_SP, kind: box PatKind::Wild }]
} 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)
- })
- })
- .collect()
- } else {
- bug!("cheap missing ctors")
- }
+ // Construct for each missing constructor 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`, we get the pattern `Some(_)`.
+ missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, pcx.ty)).collect()
};
+ // Add the new patterns to each witness
+ let new_witnesses = witnesses
+ .into_iter()
+ .flat_map(|witness| {
+ new_patterns.iter().map(move |pat| {
+ let mut witness = witness.clone();
+ witness.0.push(pat.clone());
+ witness
+ })
+ })
+ .collect();
UsefulWithWitness(new_witnesses)
}
result => result,
/// 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>,
+ matrix: &Matrix<'p, 'tcx>,
v: &PatStack<'_, 'tcx>,
ctor: Constructor<'tcx>,
lty: Ty<'tcx>,
- witness: WitnessPreference,
+ witness_preference: 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: 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) {
- Some(v) => match is_useful(cx, &matrix, &v, witness, hir_id) {
+
+ let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty).collect();
+ let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
+ let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
+ match v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns) {
+ Some(v) => match is_useful(cx, &matrix, &v, witness_preference, hir_id) {
UsefulWithWitness(witnesses) => UsefulWithWitness(
witnesses
.into_iter()
}
}
-/// 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.head()).map(|r| (r, row.len()))
lint_overlapping_patterns(tcx, hir_id, ctor_range, ty, overlaps);
- // We're going to iterate through every pair of borders, making sure that each
- // represents an interval of nonnegative length, and convert each such interval
- // into a constructor.
+ // We're going to iterate through every adjacent pair of borders, making sure that
+ // each represents an interval of nonnegative length, and convert each such
+ // interval into a constructor.
for IntRange { range, .. } in
borders.windows(2).filter_map(|window| match (window[0], window[1]) {
(Border::JustBefore(n), Border::JustBefore(m)) => {
fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
subpatterns: &'p [FieldPat<'tcx>],
- wild_patterns: &[&'p Pat<'tcx>],
+ ctor_wild_subpatterns: &[&'p Pat<'tcx>],
is_non_exhaustive: bool,
) -> PatStack<'p, 'tcx> {
- let mut result = SmallVec::from_slice(wild_patterns);
+ let mut result = SmallVec::from_slice(ctor_wild_subpatterns);
for subpat in subpatterns {
if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
}
}
- debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
+ debug!(
+ "patterns_for_variant({:#?}, {:#?}) = {:#?}",
+ subpatterns, ctor_wild_subpatterns, result
+ );
PatStack::from_vec(result)
}
-/// This is the main specialization step. It expands the first pattern in the given row
+/// This is the main specialization step. It expands the pattern
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
+/// Returns `None` if the pattern does not have the given constructor.
///
/// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
/// 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, 'q: 'p, 'tcx>(
+fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
- r: &PatStack<'q, 'tcx>,
+ pat: &'q Pat<'tcx>,
constructor: &Constructor<'tcx>,
- wild_patterns: &[&'p Pat<'tcx>],
+ ctor_wild_subpatterns: &[&'p Pat<'tcx>],
) -> Option<PatStack<'p, 'tcx>> {
- let pat = r.head();
+ let result = match *pat.kind {
+ PatKind::AscribeUserType { ref subpattern, .. } => PatStack::from_pattern(subpattern)
+ .specialize_constructor(cx, constructor, ctor_wild_subpatterns),
- let head = match *pat.kind {
- PatKind::AscribeUserType { ref subpattern, .. } => {
- specialize(cx, &PatStack::from_pattern(subpattern), constructor, wild_patterns)
+ PatKind::Binding { .. } | PatKind::Wild => {
+ Some(PatStack::from_slice(ctor_wild_subpatterns))
}
- 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];
let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty);
Some(Variant(variant.def_id))
.filter(|variant_constructor| variant_constructor == constructor)
- .map(|_| patterns_for_variant(cx, subpatterns, wild_patterns, is_non_exhaustive))
+ .map(|_| {
+ patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, is_non_exhaustive)
+ })
}
PatKind::Leaf { ref subpatterns } => {
- Some(patterns_for_variant(cx, subpatterns, wild_patterns, false))
+ Some(patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, false))
}
PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
constructor,
),
};
- if wild_patterns.len() as u64 == n {
+ if ctor_wild_subpatterns.len() as u64 == n {
// convert a constant slice/array pattern to a list of patterns.
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
let ptr = Pointer::new(AllocId(0), offset);
| PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
Slice(..) => {
let pat_len = prefix.len() + suffix.len();
- if let Some(slice_count) = wild_patterns.len().checked_sub(pat_len) {
+ if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
if slice_count == 0 || slice.is_some() {
Some(
prefix
.iter()
.chain(
- wild_patterns
+ ctor_wild_subpatterns
.iter()
.map(|p| *p)
.skip(prefix.len())
bug!("support for or-patterns has not been fully implemented yet.");
}
};
- debug!("specialize({:#?}, {:#?}) = {:#?}", r.head(), wild_patterns, head);
+ debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
- head.map(|head| {
- let mut head = head.0;
- head.extend_from_slice(&r.0[1..]);
- PatStack::from_vec(head)
- })
+ result
}