diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 907c84b6f8cf0..8e06955c7cdc4 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -11,20 +11,24 @@ /// (without being so rigorous). /// /// The core of the algorithm revolves about a "usefulness" check. In particular, we -/// are trying to compute a predicate `U(P, p_{m + 1})` where `P` is a list of patterns -/// of length `m` for a compound (product) type with `n` components (we refer to this as -/// a matrix). `U(P, p_{m + 1})` represents whether, given an existing list of patterns -/// `p_1 ..= p_m`, adding a new pattern will be "useful" (that is, cover previously- +/// are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as +/// a matrix). `U(P, p)` represents whether, given an existing list of patterns +/// `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously- /// uncovered values of the type). /// /// If we have this predicate, then we can easily compute both exhaustiveness of an /// entire set of patterns and the individual usefulness of each one. /// (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard /// match doesn't increase the number of values we're matching) -/// (b) a pattern `p_i` is not useful if `U(P[0..=(i-1), p_i)` is false (i.e., adding a +/// (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a /// pattern to those that have come before it doesn't increase the number of values /// we're matching). /// +/// During the course of the algorithm, the rows of the matrix won't just be individual patterns, +/// but rather partially-deconstructed patterns in the form of a list of patterns. The paper +/// calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the +/// new pattern `p`. +/// /// For example, say we have the following: /// ``` /// // x: (Option, Result<()>) @@ -34,93 +38,155 @@ /// (None, Err(_)) => {} /// } /// ``` -/// Here, the matrix `P` is 3 x 2 (rows x columns). +/// Here, the matrix `P` starts as: /// [ -/// [Some(true), _], -/// [None, Err(())], -/// [None, Err(_)], +/// [(Some(true), _)], +/// [(None, Err(()))], +/// [(None, Err(_))], /// ] /// We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering -/// `[Some(false), _]`, for instance). In addition, row 3 is not useful, because +/// `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because /// all the values it covers are already covered by row 2. /// -/// To compute `U`, we must have two other concepts. -/// 1. `S(c, P)` is a "specialized matrix", where `c` is a constructor (like `Some` or -/// `None`). You can think of it as filtering `P` to just the rows whose *first* pattern -/// can cover `c` (and expanding OR-patterns into distinct patterns), and then expanding -/// the constructor into all of its components. -/// The specialization of a row vector is computed by `specialize`. +/// A list of patterns can be thought of as a stack, because we are mainly interested in the top of +/// the stack at any given point, and we can pop or apply constructors to get new pattern-stacks. +/// To match the paper, the top of the stack is at the beginning / on the left. +/// +/// There are two important operations on pattern-stacks necessary to understand the algorithm: +/// 1. We can pop a given constructor off the top of a stack. This operation is called +/// `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or +/// `None`) and `p` a pattern-stack. +/// If the pattern on top of the stack can cover `c`, this removes the constructor and +/// pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. +/// Otherwise the pattern-stack is discarded. +/// This essentially filters those pattern-stacks whose top covers the constructor `c` and +/// discards the others. +/// +/// For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we +/// pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the +/// `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get +/// nothing back. /// -/// It is computed as follows. For each row `p_i` of P, we have four cases: -/// 1.1. `p_(i,1) = c(r_1, .., r_a)`. Then `S(c, P)` has a corresponding row: -/// r_1, .., r_a, p_(i,2), .., p_(i,n) -/// 1.2. `p_(i,1) = c'(r_1, .., r_a')` where `c ≠ c'`. Then `S(c, P)` has no -/// corresponding row. -/// 1.3. `p_(i,1) = _`. Then `S(c, P)` has a corresponding row: -/// _, .., _, p_(i,2), .., p_(i,n) -/// 1.4. `p_(i,1) = r_1 | r_2`. Then `S(c, P)` has corresponding rows inlined from: -/// S(c, (r_1, p_(i,2), .., p_(i,n))) -/// S(c, (r_2, p_(i,2), .., p_(i,n))) +/// This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` +/// on top of the stack, and we have four cases: +/// 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We +/// push onto the stack the arguments of this constructor, and return the result: +/// r_1, .., r_a, p_2, .., p_n +/// 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and +/// return nothing. +/// 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has +/// arguments (its arity), and return the resulting stack: +/// _, .., _, p_2, .., p_n +/// 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting +/// stack: +/// S(c, (r_1, p_2, .., p_n)) +/// S(c, (r_2, p_2, .., p_n)) /// -/// 2. `D(P)` is a "default matrix". This is used when we know there are missing -/// constructor cases, but there might be existing wildcard patterns, so to check the -/// usefulness of the matrix, we have to check all its *other* components. -/// The default matrix is computed inline in `is_useful`. +/// 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is +/// a pattern-stack. +/// This is used when we know there are missing constructor cases, but there might be +/// existing wildcard patterns, so to check the usefulness of the matrix, we have to check +/// all its *other* components. /// -/// It is computed as follows. For each row `p_i` of P, we have three cases: -/// 1.1. `p_(i,1) = c(r_1, .., r_a)`. Then `D(P)` has no corresponding row. -/// 1.2. `p_(i,1) = _`. Then `D(P)` has a corresponding row: -/// p_(i,2), .., p_(i,n) -/// 1.3. `p_(i,1) = r_1 | r_2`. Then `D(P)` has corresponding rows inlined from: -/// D((r_1, p_(i,2), .., p_(i,n))) -/// D((r_2, p_(i,2), .., p_(i,n))) +/// It is computed as follows. We look at the pattern `p_1` on top of the stack, +/// and we have three cases: +/// 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. +/// 1.2. `p_1 = _`. We return the rest of the stack: +/// p_2, .., p_n +/// 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting +/// stack. +/// D((r_1, p_2, .., p_n)) +/// D((r_2, p_2, .., p_n)) +/// +/// Note that the OR-patterns are not always used directly in Rust, but are used to derive the +/// exhaustive integer matching rules, so they're written here for posterity. +/// +/// Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by +/// working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with +/// the given constructor, and popping a wildcard keeps those rows that start with a wildcard. /// -/// Note that the OR-patterns are not always used directly in Rust, but are used to derive -/// the exhaustive integer matching rules, so they're written here for posterity. /// /// The algorithm for computing `U` /// ------------------------------- /// The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). /// That means we're going to check the components from left-to-right, so the algorithm -/// operates principally on the first component of the matrix and new pattern `p_{m + 1}`. +/// operates principally on the first component of the matrix and new pattern-stack `p`. /// This algorithm is realised in the `is_useful` function. /// /// Base case. (`n = 0`, i.e., an empty tuple pattern) /// - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), -/// then `U(P, p_{m + 1})` is false. -/// - Otherwise, `P` must be empty, so `U(P, p_{m + 1})` is true. +/// then `U(P, p)` is false. +/// - Otherwise, `P` must be empty, so `U(P, p)` is true. /// /// Inductive step. (`n > 0`, i.e., whether there's at least one column /// [which may then be expanded into further columns later]) -/// We're going to match on the new pattern, `p_{m + 1}`. -/// - If `p_{m + 1} == c(r_1, .., r_a)`, then we have a constructor pattern. -/// Thus, the usefulness of `p_{m + 1}` can be reduced to whether it is useful when -/// we ignore all the patterns in `P` that involve other constructors. This is where -/// `S(c, P)` comes in: -/// `U(P, p_{m + 1}) := U(S(c, P), S(c, p_{m + 1}))` +/// We're going to match on the top of the new pattern-stack, `p_1`. +/// - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. +/// Then, the usefulness of `p_1` can be reduced to whether it is useful when +/// we ignore all the patterns in the first column of `P` that involve other constructors. +/// This is where `S(c, P)` comes in: +/// `U(P, p) := U(S(c, P), S(c, p))` /// This special case is handled in `is_useful_specialized`. -/// - If `p_{m + 1} == _`, then we have two more cases: -/// + All the constructors of the first component of the type exist within -/// all the rows (after having expanded OR-patterns). In this case: -/// `U(P, p_{m + 1}) := ∨(k ϵ constructors) U(S(k, P), S(k, p_{m + 1}))` -/// I.e., the pattern `p_{m + 1}` is only useful when all the constructors are -/// present *if* its later components are useful for the respective constructors -/// covered by `p_{m + 1}` (usually a single constructor, but all in the case of `_`). -/// + Some constructors are not present in the existing rows (after having expanded -/// OR-patterns). However, there might be wildcard patterns (`_`) present. Thus, we -/// are only really concerned with the other patterns leading with wildcards. This is -/// where `D` comes in: -/// `U(P, p_{m + 1}) := U(D(P), p_({m + 1},2), .., p_({m + 1},n))` -/// - If `p_{m + 1} == r_1 | r_2`, then the usefulness depends on each separately: -/// `U(P, p_{m + 1}) := U(P, (r_1, p_({m + 1},2), .., p_({m + 1},n))) -/// || U(P, (r_2, p_({m + 1},2), .., p_({m + 1},n)))` +/// +/// For example, if `P` is: +/// [ +/// [Some(true), _], +/// [None, 0], +/// ] +/// and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only +/// matches values that row 2 doesn't. For row 1 however, we need to dig into the +/// arguments of `Some` to know whether some new value is covered. So we compute +/// `U([[true, _]], [false, 0])`. +/// +/// - If `p_1 == _`, then we look at the list of constructors that appear in the first +/// component of the rows of `P`: +/// + If there are some constructors that aren't present, then we might think that the +/// wildcard `_` is useful, since it covers those constructors that weren't covered +/// before. +/// That's almost correct, but only works if there were no wildcards in those first +/// components. So we need to check that `p` is useful with respect to the rows that +/// start with a wildcard, if there are any. This is where `D` comes in: +/// `U(P, p) := U(D(P), D(p))` +/// +/// For example, if `P` is: +/// [ +/// [_, true, _], +/// [None, false, 1], +/// ] +/// and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we +/// only had row 2, we'd know that `p` is useful. However row 1 starts with a +/// wildcard, so we need to check whether `U([[true, _]], [false, 1])`. +/// +/// + Otherwise, all possible constructors (for the relevant type) are present. In this +/// case we must check whether the wildcard pattern covers any unmatched value. For +/// that, we can think of the `_` pattern as a big OR-pattern that covers all +/// possible constructors. For `Option`, that would mean `_ = None | Some(_)` for +/// example. The wildcard pattern is useful in this case if it is useful when +/// specialized to one of the possible constructors. So we compute: +/// `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` +/// +/// For example, if `P` is: +/// [ +/// [Some(true), _], +/// [None, false], +/// ] +/// and `p` is [_, false], both `None` and `Some` constructors appear in the first +/// components of `P`. We will therefore try popping both constructors in turn: we +/// compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]], +/// [false]) for the `None` constructor. The first case returns true, so we know that +/// `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched +/// before. +/// +/// - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: +/// `U(P, p) := U(P, (r_1, p_2, .., p_n)) +/// || U(P, (r_2, p_2, .., p_n))` /// /// Modifications to the algorithm /// ------------------------------ /// The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for /// example uninhabited types and variable-length slice patterns. These are drawn attention to -/// throughout the code below. I'll make a quick note here about how exhaustive integer matching -/// is accounted for, though. +/// throughout the code below. I'll make a quick note here about how exhaustive integer matching is +/// accounted for, though. /// /// Exhaustive integer matching /// --------------------------- @@ -150,12 +216,11 @@ /// invalid, because we want a disjunction over every *integer* in each range, not just a /// disjunction over every range. This is a bit more tricky to deal with: essentially we need /// to form equivalence classes of subranges of the constructor range for which the behaviour -/// of the matrix `P` and new pattern `p_{m + 1}` are the same. This is described in more +/// of the matrix `P` and new pattern `p` are the same. This is described in more /// detail in `split_grouped_constructors`. /// + If some constructors are missing from the matrix, it turns out we don't need to do /// anything special (because we know none of the integers are actually wildcards: i.e., we /// can't span wildcards using ranges). - use self::Constructor::*; use self::Usefulness::*; use self::WitnessPreference::*; @@ -163,31 +228,32 @@ use self::WitnessPreference::*; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; +use super::{compare_const_vals, PatternFoldable, PatternFolder}; use super::{FieldPat, Pat, PatKind, PatRange}; -use super::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; -use rustc::hir::{RangeEnd, HirId}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; -use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; +use rustc::hir::{HirId, RangeEnd}; +use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx}; +use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable}; +use rustc::lint; +use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc::mir::Field; -use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer}; +use rustc::util::captures::Captures; use rustc::util::common::ErrorReported; -use rustc::lint; use syntax::attr::{SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; use arena::TypedArena; -use smallvec::{SmallVec, smallvec}; -use std::cmp::{self, Ordering, min, max}; +use smallvec::{smallvec, SmallVec}; +use std::cmp::{self, max, min, Ordering}; +use std::convert::TryInto; use std::fmt; use std::iter::{FromIterator, IntoIterator}; use std::ops::RangeInclusive; use std::u128; -use std::convert::TryInto; pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> { LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat) @@ -216,11 +282,8 @@ impl LiteralExpander<'tcx> { // the easy case, deref a reference (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => { let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); - ConstValue::ByRef { - alloc, - offset: p.offset, - } - }, + ConstValue::ByRef { alloc, offset: p.offset } + } // unsize array to slice if pattern is array but match value or other patterns are slice (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { assert_eq!(t, u); @@ -229,12 +292,11 @@ impl LiteralExpander<'tcx> { start: p.offset.bytes().try_into().unwrap(), end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(), } - }, + } // fat pointers stay the same - | (ConstValue::Slice { .. }, _, _) + (ConstValue::Slice { .. }, _, _) | (_, ty::Slice(_), ty::Slice(_)) - | (_, ty::Str, ty::Str) - => val, + | (_, ty::Str, ty::Str) => val, // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), } @@ -247,30 +309,27 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> { match (&pat.ty.kind, &*pat.kind) { ( &ty::Ref(_, rty, _), - &PatKind::Constant { value: Const { - val, - ty: ty::TyS { kind: ty::Ref(_, crty, _), .. }, - } }, - ) => { - Pat { - ty: pat.ty, - span: pat.span, - kind: box PatKind::Deref { - subpattern: Pat { - ty: rty, - span: pat.span, - kind: box PatKind::Constant { value: self.tcx.mk_const(Const { + &PatKind::Constant { + value: Const { val, ty: ty::TyS { kind: ty::Ref(_, crty, _), .. } }, + }, + ) => Pat { + ty: pat.ty, + span: pat.span, + kind: box PatKind::Deref { + subpattern: Pat { + ty: rty, + span: pat.span, + kind: box PatKind::Constant { + value: self.tcx.mk_const(Const { val: self.fold_const_value_deref(*val, rty, crty), ty: rty, - }) }, - } - } - } - } - (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => { - s.fold_with(self) - } - _ => pat.super_fold_with(self) + }), + }, + }, + }, + }, + (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self), + _ => pat.super_fold_with(self), } } } @@ -278,53 +337,156 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> { impl<'tcx> Pat<'tcx> { fn is_wildcard(&self) -> bool { match *self.kind { - PatKind::Binding { subpattern: None, .. } | PatKind::Wild => - true, - _ => false + PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true, + _ => false, } } } -/// A 2D matrix. Nx1 matrices are very common, which is why `SmallVec[_; 2]` -/// works well for each row. -pub struct Matrix<'p, 'tcx>(Vec; 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> { + self.0.iter().map(|p| *p) + } + + /// This computes `D(self)`. See top of the file for explanations. + fn specialize_wildcard(&self) -> Option { + 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> + 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> { + fn default() -> Self { + PatStack(smallvec![]) + } +} + +impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { + fn from_iter(iter: T) -> Self + where + T: IntoIterator>, + { + PatStack(iter.into_iter().collect()) + } +} + +/// A 2D matrix. +pub struct Matrix<'p, 'tcx>(Vec>); 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> + 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: -/// ++++++++++++++++++++++++++ -/// + _ + [] + -/// ++++++++++++++++++++++++++ -/// + true + [First] + -/// ++++++++++++++++++++++++++ -/// + true + [Second(true)] + -/// ++++++++++++++++++++++++++ -/// + false + [_] + -/// ++++++++++++++++++++++++++ -/// + _ + [_, _, ..tail] + -/// ++++++++++++++++++++++++++ +/// +++++++++++++++++++++++++++++ +/// + _ + [] + +/// +++++++++++++++++++++++++++++ +/// + true + [First] + +/// +++++++++++++++++++++++++++++ +/// + true + [Second(true)] + +/// +++++++++++++++++++++++++++++ +/// + false + [_] + +/// +++++++++++++++++++++++++++++ +/// + _ + [_, _, tail @ ..] + +/// +++++++++++++++++++++++++++++ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\n")?; let &Matrix(ref m) = self; - let pretty_printed_matrix: Vec> = m.iter().map(|row| { - row.iter().map(|pat| format!("{:?}", pat)).collect() - }).collect(); + let pretty_printed_matrix: Vec> = + m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0); assert!(m.iter().all(|row| row.len() == column_count)); - let column_widths: Vec = (0..column_count).map(|col| { - pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0) - }).collect(); + let column_widths: Vec = (0..column_count) + .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)) + .collect(); let total_width = column_widths.iter().cloned().sum::() + column_count * 3 + 1; let br = "+".repeat(total_width); @@ -343,9 +505,10 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { } } -impl<'p, 'tcx> FromIterator; 2]>> for Matrix<'p, 'tcx> { +impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { fn from_iter(iter: T) -> Self - where T: IntoIterator; 2]>> + where + T: IntoIterator>, { Matrix(iter.into_iter().collect()) } @@ -461,7 +624,7 @@ impl<'tcx> Constructor<'tcx> { VariantIdx::new(0) } ConstantValue(c, _) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c), - _ => bug!("bad constructor {:?} for adt {:?}", self, adt) + _ => bug!("bad constructor {:?} for adt {:?}", self, adt), } } @@ -482,20 +645,229 @@ impl<'tcx> Constructor<'tcx> { _ => bug!("bad constructor being displayed: `{:?}", self), } } + + // Returns the set of constructors covered by `self` but not by + // anything in `other_ctors`. + fn subtract_ctors( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + other_ctors: &Vec>, + ) -> Vec> { + let mut refined_ctors = vec![self.clone()]; + for other_ctor in other_ctors { + if other_ctor == self { + // 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, other_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); + } + + // 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; + } + } + + // If a constructor has not been matched, then it is missing. + // We add `refined_ctors` instead of `self`, because then we can + // provide more detailed error information about precisely which + // ranges have been omitted. + refined_ctors + } + + /// 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> + 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`: `Constructor::Single` + /// `ty`: `(u32, u32, u32)` + /// `pats`: `[10, 20, _]` + /// returns `(10, 20, _)` + /// + /// `self`: `Constructor::Variant(Option::Some)` + /// `ty`: `Option` + /// `pats`: `[false]` + /// returns `Some(false)` + fn apply<'a>( + &self, + cx: &MatchCheckCtxt<'a, 'tcx>, + ty: Ty<'tcx>, + pats: impl IntoIterator>, + ) -> Pat<'tcx> { + let mut subpatterns = pats.into_iter(); + let pat = match ty.kind { + ty::Adt(..) | ty::Tuple(..) => { + let subpatterns = subpatterns + .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, + } + } else { + PatKind::Leaf { subpatterns } + } + } else { + PatKind::Leaf { subpatterns } + } + } + + ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() }, + + ty::Slice(_) | ty::Array(..) => { + PatKind::Slice { prefix: subpatterns.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 subpatterns = self.wildcard_subpatterns(cx, ty).rev(); + self.apply(cx, ty, subpatterns) + } } #[derive(Clone, Debug)] pub enum Usefulness<'tcx> { Useful, UsefulWithWitness(Vec>), - NotUseful + NotUseful, } impl<'tcx> Usefulness<'tcx> { + fn new_useful(preference: WitnessPreference) -> Self { + match preference { + ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]), + LeaveOutWitness => Useful, + } + } + fn is_useful(&self) -> bool { match *self { NotUseful => false, - _ => true + _ => true, + } + } + + fn apply_constructor( + self, + cx: &MatchCheckCtxt<'_, 'tcx>, + ctor: &Constructor<'tcx>, + ty: Ty<'tcx>, + ) -> Self { + match self { + UsefulWithWitness(witnesses) => UsefulWithWitness( + witnesses + .into_iter() + .map(|witness| witness.apply_constructor(cx, &ctor, ty)) + .collect(), + ), + x => x, + } + } + + fn apply_wildcard(self, ty: Ty<'tcx>) -> Self { + match self { + UsefulWithWitness(witnesses) => { + let wild = Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild }; + UsefulWithWitness( + witnesses + .into_iter() + .map(|mut witness| { + witness.0.push(wild.clone()); + witness + }) + .collect(), + ) + } + x => x, + } + } + + fn apply_missing_ctors( + self, + cx: &MatchCheckCtxt<'_, 'tcx>, + ty: Ty<'tcx>, + missing_ctors: &MissingConstructors<'tcx>, + ) -> Self { + match self { + UsefulWithWitness(witnesses) => { + let new_patterns: Vec<_> = + missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, ty)).collect(); + // Add the new patterns to each witness + UsefulWithWitness( + witnesses + .into_iter() + .flat_map(|witness| { + new_patterns.iter().map(move |pat| { + let mut witness = witness.clone(); + witness.0.push(pat.clone()); + witness + }) + }) + .collect(), + ) + } + x => x, } } } @@ -503,7 +875,7 @@ impl<'tcx> Usefulness<'tcx> { #[derive(Copy, Clone, Debug)] pub enum WitnessPreference { ConstructWitness, - LeaveOutWitness + LeaveOutWitness, } #[derive(Copy, Clone, Debug)] @@ -554,24 +926,6 @@ impl<'tcx> Witness<'tcx> { 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. /// @@ -587,73 +941,18 @@ impl<'tcx> Witness<'tcx> { /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } fn apply_constructor<'a>( mut self, - cx: &MatchCheckCtxt<'a,'tcx>, + cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, - ty: Ty<'tcx>) - -> Self - { - let arity = constructor_arity(cx, ctor, ty); + ty: Ty<'tcx>, + ) -> Self { + 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 } @@ -672,37 +971,33 @@ fn all_constructors<'a, 'tcx>( ) -> Vec> { debug!("all_constructors({:?})", pcx.ty); let ctors = match pcx.ty.kind { - ty::Bool => { - [true, false].iter().map(|&b| { - ConstantValue(ty::Const::from_bool(cx.tcx, b), pcx.span) - }).collect() - } + ty::Bool => [true, false] + .iter() + .map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b), pcx.span)) + .collect(), ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { let len = len.eval_usize(cx.tcx, cx.param_env); - if len != 0 && cx.is_uninhabited(sub_ty) { - vec![] - } else { - vec![Slice(len)] - } + if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { vec![Slice(len)] } } // Treat arrays of a constant but unknown length like slices. - ty::Array(ref sub_ty, _) | - ty::Slice(ref sub_ty) => { + ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => { if cx.is_uninhabited(sub_ty) { vec![Slice(0)] } else { - (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() + (0..pcx.max_slice_length + 1).map(|length| Slice(length)).collect() } } - ty::Adt(def, substs) if def.is_enum() => { - def.variants.iter() - .filter(|v| { - !cx.tcx.features().exhaustive_patterns || - !v.uninhabited_from(cx.tcx, substs, def.adt_kind()).contains(cx.tcx, cx.module) - }) - .map(|v| Variant(v.def_id)) - .collect() - } + ty::Adt(def, substs) if def.is_enum() => def + .variants + .iter() + .filter(|v| { + !cx.tcx.features().exhaustive_patterns + || !v + .uninhabited_from(cx.tcx, substs, def.adt_kind()) + .contains(cx.tcx, cx.module) + }) + .map(|v| Variant(v.def_id)) + .collect(), ty::Char => { vec![ // The valid Unicode Scalar Value ranges. @@ -822,15 +1117,13 @@ where PatKind::Constant { value } => { // extract the length of an array/slice from a constant match (value.val, &value.ty.kind) { - (_, ty::Array(_, n)) => max_fixed_len = cmp::max( - max_fixed_len, - n.eval_usize(cx.tcx, cx.param_env), - ), - (ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max( - max_fixed_len, - (end - start) as u64, - ), - _ => {}, + (_, ty::Array(_, n)) => { + max_fixed_len = cmp::max(max_fixed_len, n.eval_usize(cx.tcx, cx.param_env)) + } + (ConstValue::Slice { start, end, .. }, ty::Slice(_)) => { + max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64) + } + _ => {} } } PatKind::Slice { ref prefix, slice: None, ref suffix } => { @@ -907,7 +1200,7 @@ impl<'tcx> IntRange<'tcx> { // This is a more general form of the previous branch. val } else { - return None + return None; }; let val = val ^ bias; Some(IntRange { range: val..=val, ty, span }) @@ -978,7 +1271,7 @@ impl<'tcx> IntRange<'tcx> { } box PatKind::AscribeUserType { ref subpattern, .. } => { pat = subpattern; - }, + } _ => return None, } } @@ -991,7 +1284,7 @@ impl<'tcx> IntRange<'tcx> { let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; 1u128 << (bits - 1) } - _ => 0 + _ => 0, } } @@ -1020,34 +1313,43 @@ impl<'tcx> IntRange<'tcx> { param_env: ty::ParamEnv<'tcx>, ranges: Vec>, ) -> Vec> { - let ranges = ranges.into_iter().filter_map(|r| { - IntRange::from_ctor(tcx, param_env, &r).map(|i| i.range) - }); + let ranges = ranges + .into_iter() + .filter_map(|r| IntRange::from_ctor(tcx, param_env, &r).map(|i| i.range)); let mut remaining_ranges = vec![]; let ty = self.ty; let (lo, hi) = self.range.into_inner(); for subrange in ranges { let (subrange_lo, subrange_hi) = subrange.into_inner(); - if lo > subrange_hi || subrange_lo > hi { + if lo > subrange_hi || subrange_lo > hi { // The pattern doesn't intersect with the subrange at all, // so the subrange remains untouched. - remaining_ranges.push( - Self::range_to_ctor(tcx, ty, subrange_lo..=subrange_hi, self.span), - ); + remaining_ranges.push(Self::range_to_ctor( + tcx, + ty, + subrange_lo..=subrange_hi, + self.span, + )); } else { if lo > subrange_lo { // The pattern intersects an upper section of the // subrange, so a lower section will remain. - remaining_ranges.push( - Self::range_to_ctor(tcx, ty, subrange_lo..=(lo - 1), self.span), - ); + remaining_ranges.push(Self::range_to_ctor( + tcx, + ty, + subrange_lo..=(lo - 1), + self.span, + )); } if hi < subrange_hi { // The pattern intersects a lower section of the // subrange, so an upper section will remain. - remaining_ranges.push( - Self::range_to_ctor(tcx, ty, (hi + 1)..=subrange_hi, self.span), - ); + remaining_ranges.push(Self::range_to_ctor( + tcx, + ty, + (hi + 1)..=subrange_hi, + self.span, + )); } } } @@ -1084,79 +1386,49 @@ impl<'tcx> IntRange<'tcx> { } } -// 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>, + used_ctors: Vec>, } -// 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>, + used_ctors: Vec>, + ) -> Self { + MissingConstructors { tcx, param_env, all_ctors, used_ctors } + } - // Note that the Vec can be empty. - Ctors(Vec>), -} + fn into_inner(self) -> (Vec>, Vec>) { + (self.all_ctors, self.used_ctors) + } -// 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>, - used_ctors: &Vec>, -) -> 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); - } + 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() + } - // 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; - } - } else { - missing_ctors.extend(refined_ctors); - } + /// Iterate over all_ctors \ used_ctors + fn iter<'a>(&'a self) -> impl Iterator> + Captures<'a> { + self.all_ctors.iter().flat_map(move |req_ctor| { + req_ctor.subtract_ctors(self.tcx, self.param_env, &self.used_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) } } @@ -1185,8 +1457,8 @@ fn compute_missing_ctors<'tcx>( pub fn is_useful<'p, 'a, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, matrix: &Matrix<'p, 'tcx>, - v: &[&Pat<'tcx>], - witness: WitnessPreference, + v: &PatStack<'_, 'tcx>, + witness_preference: WitnessPreference, hir_id: HirId, ) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; @@ -1199,21 +1471,19 @@ pub fn is_useful<'p, 'a, 'tcx>( // the type of the tuple we're checking is inhabited or not. if v.is_empty() { return if rows.is_empty() { - match witness { - ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]), - LeaveOutWitness => Useful, - } + Usefulness::new_useful(witness_preference) } else { NotUseful - } + }; }; 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 @@ -1235,31 +1505,41 @@ pub fn is_useful<'p, 'a, 'tcx>( // 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, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id), - ).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id) - ).find(|result| result.is_useful()).unwrap_or(NotUseful) + cx.tcx, + cx.param_env, + constructors, + matrix, + pcx.ty, + pcx.span, + Some(hir_id), + ) + .into_iter() + .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> = rows.iter().flat_map(|row| { - pat_constructors(cx, row[0], pcx).unwrap_or(vec![]) - }).collect(); + let used_ctors: Vec> = + 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. @@ -1280,118 +1560,98 @@ pub fn is_useful<'p, 'a, 'tcx>( // 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); + + debug!( + "missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", + missing_ctors.is_empty(), + is_privately_empty, + is_declared_nonexhaustive ); - 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); - // For privately empty and non-exhaustive enums, we work as if there were an "extra" // `_` constructor for the type, so we can never match over all constructors. - let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive || - (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching); + let is_non_exhaustive = is_privately_empty + || 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, all_ctors, matrix, pcx.ty, DUMMY_SP, None, + cx.tcx, + cx.param_env, + all_ctors, + matrix, + pcx.ty, + DUMMY_SP, + None, ) - .into_iter() - .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id)) - .find(|result| result.is_useful()) - .unwrap_or(NotUseful) + .into_iter() + .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[0].is_wildcard() { - Some(SmallVec::from_slice(&r[1..])) - } else { - None - } - }).collect(); - match is_useful(cx, &matrix, &v[1..], witness, hir_id) { - UsefulWithWitness(pats) => { - let cx = &*cx; - // In this case, there's at least one "free" - // constructor that is only matched against by - // wildcard patterns. - // - // There are 2 ways we can report a witness here. - // Commonly, we can report all the "free" - // constructors as witnesses, e.g., if we have: - // - // ``` - // enum Direction { N, S, E, W } - // let Direction::N = ...; - // ``` - // - // we can report 3 witnesses: `S`, `E`, and `W`. - // - // However, there are 2 cases where we don't want - // to do this and instead report a single `_` witness: - // - // 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: - // ``` - // let err: io::ErrorKind = ...; - // match err { - // io::ErrorKind::NotFound => {}, - // } - // ``` - // we don't want to show every possible IO error, - // but instead have `_` as the witness (this is - // actually *required* if the user specified *all* - // IO errors, but is probably what we want in every - // case). - // - // 2) If the user didn't actually specify a constructor - // in this arm, e.g., in - // ``` - // let x: (Direction, Direction, bool) = ...; - // let (_, _, false) = x; - // ``` - // we don't want to show all 16 possible witnesses - // `(, , 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 - // 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() - } 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") - } - }; - UsefulWithWitness(new_witnesses) - } - result => result + let matrix = matrix.specialize_wildcard(); + let v = v.to_tail(); + let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id); + + // In this case, there's at least one "free" + // constructor that is only matched against by + // wildcard patterns. + // + // There are 2 ways we can report a witness here. + // Commonly, we can report all the "free" + // constructors as witnesses, e.g., if we have: + // + // ``` + // enum Direction { N, S, E, W } + // let Direction::N = ...; + // ``` + // + // we can report 3 witnesses: `S`, `E`, and `W`. + // + // However, there are 2 cases where we don't want + // to do this and instead report a single `_` witness: + // + // 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 themselves, e.g., in an example like: + // ``` + // let err: io::ErrorKind = ...; + // match err { + // io::ErrorKind::NotFound => {}, + // } + // ``` + // we don't want to show every possible IO error, + // but instead have `_` as the witness (this is + // actually *required* if the user specified *all* + // IO errors, but is probably what we want in every + // case). + // + // 2) If the user didn't actually specify a constructor + // in this arm, e.g., in + // ``` + // let x: (Direction, Direction, bool) = ...; + // let (_, _, false) = x; + // ``` + // we don't want to show all 16 possible witnesses + // `(, , true)` - we are + // satisfied with `(_, _, true)`. In this case, + // `used_ctors` is empty. + if is_non_exhaustive || missing_ctors.all_ctors_are_missing() { + // All constructors are unused. Add a wild pattern + // rather than each individual constructor. + usefulness.apply_wildcard(pcx.ty) + } else { + // 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(_)`. + usefulness.apply_missing_ctors(cx, pcx.ty, &missing_ctors) } } } @@ -1401,39 +1661,22 @@ pub fn is_useful<'p, 'a, 'tcx>( /// 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, + 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) { - UsefulWithWitness(witnesses) => UsefulWithWitness( - witnesses.into_iter() - .map(|witness| witness.apply_constructor(cx, &ctor, lty)) - .collect() - ), - result => result - } - None => NotUseful - } + + 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); + v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns) + .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id)) + .map(|u| u.apply_constructor(cx, &ctor, lty)) + .unwrap_or(NotUseful) } /// Determines the constructors that the given pattern can be specialized to. @@ -1441,7 +1684,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>( /// In most cases, there's only one constructor that a specific pattern /// represents, such as a specific enum variant or a specific literal value. /// Slice patterns, however, can match slices of different lengths. For instance, -/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. +/// `[a, b, tail @ ..]` can match a slice of length 2, 3, 4 and so on. /// /// Returns `None` in case of a catch-all, which can't be specialized. fn pat_constructors<'tcx>( @@ -1450,32 +1693,28 @@ fn pat_constructors<'tcx>( pcx: PatCtxt<'tcx>, ) -> Option>> { match *pat.kind { - PatKind::AscribeUserType { ref subpattern, .. } => - pat_constructors(cx, subpattern, pcx), + PatKind::AscribeUserType { ref subpattern, .. } => pat_constructors(cx, subpattern, pcx), PatKind::Binding { .. } | PatKind::Wild => None, PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(vec![Single]), PatKind::Variant { adt_def, variant_index, .. } => { Some(vec![Variant(adt_def.variants[variant_index].def_id)]) } PatKind::Constant { value } => Some(vec![ConstantValue(value, pat.span)]), - PatKind::Range(PatRange { lo, hi, end }) => - Some(vec![ConstantRange( - lo.eval_bits(cx.tcx, cx.param_env, lo.ty), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty), - lo.ty, - end, - pat.span, - )]), + PatKind::Range(PatRange { lo, hi, end }) => Some(vec![ConstantRange( + lo.eval_bits(cx.tcx, cx.param_env, lo.ty), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + lo.ty, + end, + pat.span, + )]), PatKind::Array { .. } => match pcx.ty.kind { - ty::Array(_, length) => Some(vec![ - Slice(length.eval_usize(cx.tcx, cx.param_env)) - ]), - _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) + ty::Array(_, length) => Some(vec![Slice(length.eval_usize(cx.tcx, cx.param_env))]), + _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty), }, PatKind::Slice { ref prefix, ref slice, ref suffix } => { let pat_len = prefix.len() as u64 + suffix.len() as u64; if slice.is_some() { - Some((pat_len..pcx.max_slice_length+1).map(Slice).collect()) + Some((pat_len..pcx.max_slice_length + 1).map(Slice).collect()) } else { Some(vec![Slice(pat_len)]) } @@ -1486,28 +1725,6 @@ fn pat_constructors<'tcx>( } } -/// 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. /// @@ -1523,8 +1740,8 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( ty::Slice(ty) | ty::Array(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(..) => vec![], - _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) - } + _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), + }, ty::Ref(_, rty, _) => vec![rty], ty::Adt(adt, substs) => { if adt.is_box() { @@ -1533,30 +1750,37 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( } else { let variant = &adt.variants[ctor.variant_index_for_adt(cx, adt)]; let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(ty); - variant.fields.iter().map(|field| { - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); - match (is_visible, is_non_exhaustive, is_uninhabited) { - // Treat all uninhabited types in non-exhaustive variants as `TyErr`. - (_, true, true) => cx.tcx.types.err, - // Treat all non-visible fields as `TyErr`. They can't appear in any - // other pattern from this match (because they are private), so their - // type does not matter - but we don't want to know they are uninhabited. - (false, ..) => cx.tcx.types.err, - (true, ..) => { - let ty = field.ty(cx.tcx, substs); - match ty.kind { - // If the field type returned is an array of an unknown - // size return an TyErr. - ty::Array(_, len) - if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => - cx.tcx.types.err, - _ => ty, + variant + .fields + .iter() + .map(|field| { + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); + match (is_visible, is_non_exhaustive, is_uninhabited) { + // Treat all uninhabited types in non-exhaustive variants as `TyErr`. + (_, true, true) => cx.tcx.types.err, + // Treat all non-visible fields as `TyErr`. They can't appear in any + // other pattern from this match (because they are private), so their + // type does not matter - but we don't want to know they are + // uninhabited. + (false, ..) => cx.tcx.types.err, + (true, ..) => { + let ty = field.ty(cx.tcx, substs); + match ty.kind { + // If the field type returned is an array of an unknown size + // return an TyErr. + ty::Array(_, len) + if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => + { + cx.tcx.types.err + } + _ => ty, + } } - }, - } - }).collect() + } + }) + .collect() } } _ => vec![], @@ -1581,17 +1805,20 @@ fn slice_pat_covered_by_const<'tcx>( let n = n.eval_usize(tcx, param_env); let ptr = Pointer::new(AllocId(0), offset); alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap() - }, + } (ConstValue::Slice { data, start, end }, ty::Slice(t)) => { assert_eq!(*t, tcx.types.u8); let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64)); data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap() - }, + } // FIXME(oli-obk): create a way to extract fat pointers from ByRef (_, ty::Slice(_)) => return Ok(false), _ => bug!( "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}", - const_val, prefix, slice, suffix, + const_val, + prefix, + slice, + suffix, ), }; @@ -1600,9 +1827,10 @@ fn slice_pat_covered_by_const<'tcx>( return Ok(false); } - for (ch, pat) in - data[..prefix.len()].iter().zip(prefix).chain( - data[data.len()-suffix.len()..].iter().zip(suffix)) + for (ch, pat) in data[..prefix.len()] + .iter() + .zip(prefix) + .chain(data[data.len() - suffix.len()..].iter().zip(suffix)) { match pat.kind { box PatKind::Constant { value } => { @@ -1673,7 +1901,7 @@ fn split_grouped_constructors<'p, 'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ctors: Vec>, - &Matrix(ref m): &Matrix<'p, 'tcx>, + matrix: &Matrix<'p, 'tcx>, ty: Ty<'tcx>, span: Span, hir_id: Option, @@ -1715,9 +1943,11 @@ fn split_grouped_constructors<'p, 'tcx>( let mut overlaps = vec![]; // `borders` is the set of borders between equivalence classes: each equivalence // class lies between 2 borders. - let row_borders = m.iter() + 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); @@ -1742,11 +1972,11 @@ fn split_grouped_constructors<'p, 'tcx>( 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. - for IntRange { range, .. } in borders.windows(2).filter_map(|window| { - match (window[0], window[1]) { + // 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)) => { if n < m { Some(IntRange { range: n..=(m - 1), ty, span }) @@ -1758,8 +1988,8 @@ fn split_grouped_constructors<'p, 'tcx>( Some(IntRange { range: n..=u128::MAX, ty, span }) } (Border::AfterMax, _) => None, - } - }) { + }) + { split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span)); } } @@ -1788,10 +2018,13 @@ fn lint_overlapping_patterns( err.span_label(ctor_range.span, "overlapping patterns"); for int_range in overlaps { // Use the real type for user display of the ranges: - err.span_label(int_range.span, &format!( - "this range overlaps on `{}`", - IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP).display(tcx), - )); + err.span_label( + int_range.span, + &format!( + "this range overlaps on `{}`", + IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP).display(tcx), + ), + ); } err.emit(); } @@ -1809,8 +2042,9 @@ fn constructor_covered_by_range<'tcx>( _ => bug!("`constructor_covered_by_range` called with {:?}", pat), }; trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); - let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, param_env, ty) - .map(|res| res != Ordering::Less); + let cmp_from = |c_from| { + compare_const_vals(tcx, c_from, from, param_env, ty).map(|res| res != Ordering::Less) + }; let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, param_env, ty); macro_rules! some_or_ok { ($e:expr) => { @@ -1823,37 +2057,31 @@ fn constructor_covered_by_range<'tcx>( match *ctor { ConstantValue(value, _) => { let to = some_or_ok!(cmp_to(value)); - let end = (to == Ordering::Less) || - (end == RangeEnd::Included && to == Ordering::Equal); + let end = + (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(value)) && end) - }, + } ConstantRange(from, to, ty, RangeEnd::Included, _) => { - let to = some_or_ok!(cmp_to(ty::Const::from_bits( - tcx, - to, - ty::ParamEnv::empty().and(ty), - ))); - let end = (to == Ordering::Less) || - (end == RangeEnd::Included && to == Ordering::Equal); + let to = + some_or_ok!(cmp_to(ty::Const::from_bits(tcx, to, ty::ParamEnv::empty().and(ty),))); + let end = + (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(ty::Const::from_bits( tcx, from, ty::ParamEnv::empty().and(ty), ))) && end) - }, + } ConstantRange(from, to, ty, RangeEnd::Excluded, _) => { - let to = some_or_ok!(cmp_to(ty::Const::from_bits( - tcx, - to, - ty::ParamEnv::empty().and(ty) - ))); - let end = (to == Ordering::Less) || - (end == RangeEnd::Excluded && to == Ordering::Equal); + let to = + some_or_ok!(cmp_to(ty::Const::from_bits(tcx, to, ty::ParamEnv::empty().and(ty)))); + let end = + (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(ty::Const::from_bits( tcx, from, - ty::ParamEnv::empty().and(ty))) - ) && end) + ty::ParamEnv::empty().and(ty) + ))) && end) } Single => Ok(true), _ => bug!(), @@ -1863,10 +2091,10 @@ fn constructor_covered_by_range<'tcx>( 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, -) -> SmallVec<[&'p Pat<'tcx>; 2]> { - let mut result = SmallVec::from_slice(wild_patterns); +) -> PatStack<'p, 'tcx> { + let mut result = SmallVec::from_slice(ctor_wild_subpatterns); for subpat in subpatterns { if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) { @@ -1874,33 +2102,34 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>( } } - debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result); - 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 +/// 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, 'tcx>( +fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, - r: &[&'p Pat<'tcx>], + pat: &'q Pat<'tcx>, constructor: &Constructor<'tcx>, - wild_patterns: &[&'p Pat<'tcx>], -) -> Option; 2]>> { - let pat = &r[0]; - - let head = match *pat.kind { - PatKind::AscribeUserType { ref subpattern, .. } => { - specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns) - } + ctor_wild_subpatterns: &[&'p Pat<'tcx>], +) -> Option> { + let result = match *pat.kind { + PatKind::AscribeUserType { ref subpattern, .. } => PatStack::from_pattern(subpattern) + .specialize_constructor(cx, constructor, ctor_wild_subpatterns), PatKind::Binding { .. } | PatKind::Wild => { - Some(SmallVec::from_slice(wild_patterns)) + Some(PatStack::from_slice(ctor_wild_subpatterns)) } PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { @@ -1908,16 +2137,16 @@ fn specialize<'p, 'a: 'p, 'tcx>( 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(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 @@ -1925,39 +2154,28 @@ fn specialize<'p, 'a: 'p, 'tcx>( // just integers. The only time they should be pointing to memory // is when they are subslices of nonzero slices. let (alloc, offset, n, ty) = match value.ty.kind { - ty::Array(t, n) => { - match value.val { - ConstValue::ByRef { offset, alloc, .. } => ( - alloc, - offset, - n.eval_usize(cx.tcx, cx.param_env), - t, - ), - _ => span_bug!( - pat.span, - "array pattern is {:?}", value, - ), + ty::Array(t, n) => match value.val { + ConstValue::ByRef { offset, alloc, .. } => { + (alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t) } + _ => span_bug!(pat.span, "array pattern is {:?}", value,), }, ty::Slice(t) => { match value.val { - ConstValue::Slice { data, start, end } => ( - data, - Size::from_bytes(start as u64), - (end - start) as u64, - t, - ), + ConstValue::Slice { data, start, end } => { + (data, Size::from_bytes(start as u64), (end - start) as u64, t) + } ConstValue::ByRef { .. } => { // FIXME(oli-obk): implement `deref` for `ConstValue` return None; - }, + } _ => span_bug!( pat.span, "slice pattern constant must be scalar pair but is {:?}", value, ), } - }, + } _ => span_bug!( pat.span, "unexpected const-val {:?} with ctor {:?}", @@ -1965,45 +2183,41 @@ fn specialize<'p, 'a: 'p, 'tcx>( 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); - (0..n).map(|i| { - let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; - let scalar = alloc.read_scalar( - &cx.tcx, ptr, layout.size, - ).ok()?; - let scalar = scalar.not_undef().ok()?; - let value = ty::Const::from_scalar(cx.tcx, scalar, ty); - let pattern = Pat { - ty, - span: pat.span, - kind: box PatKind::Constant { value }, - }; - Some(&*cx.pattern_arena.alloc(pattern)) - }).collect() + (0..n) + .map(|i| { + let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; + let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?; + let scalar = scalar.not_undef().ok()?; + let value = ty::Const::from_scalar(cx.tcx, scalar, ty); + let pattern = + Pat { ty, span: pat.span, kind: box PatKind::Constant { value } }; + Some(&*cx.pattern_arena.alloc(pattern)) + }) + .collect() } else { None } } - PatKind::Constant { .. } | - PatKind::Range { .. } => { + PatKind::Constant { .. } | PatKind::Range { .. } => { // If the constructor is a: // - Single value: add a row if the pattern contains the constructor. // - Range: add a row if the constructor intersects the pattern. if should_treat_range_exhaustively(cx.tcx, constructor) { - match (IntRange::from_ctor(cx.tcx, cx.param_env, constructor), - IntRange::from_pat(cx.tcx, cx.param_env, pat)) { - (Some(ctor), Some(pat)) => { - ctor.intersection(&pat).map(|_| { - 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![] - }) - } + match ( + IntRange::from_ctor(cx.tcx, cx.param_env, constructor), + IntRange::from_pat(cx.tcx, cx.param_env, pat), + ) { + (Some(ctor), Some(pat)) => ctor.intersection(&pat).map(|_| { + 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); + PatStack::default() + }), _ => None, } } else { @@ -2013,54 +2227,61 @@ fn specialize<'p, 'a: 'p, 'tcx>( // 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, } } } - PatKind::Array { ref prefix, ref slice, ref suffix } | - 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 slice_count == 0 || slice.is_some() { - Some(prefix.iter().chain( - wild_patterns.iter().map(|p| *p) - .skip(prefix.len()) - .take(slice_count) - .chain(suffix.iter()) - ).collect()) - } else { - None - } + PatKind::Array { ref prefix, ref slice, ref suffix } + | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor { + Slice(..) => { + let pat_len = prefix.len() + suffix.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( + ctor_wild_subpatterns + .iter() + .map(|p| *p) + .skip(prefix.len()) + .take(slice_count) + .chain(suffix.iter()), + ) + .collect(), + ) } else { None } + } else { + None } - ConstantValue(cv, _) => { - match slice_pat_covered_by_const( - cx.tcx, pat.span, cv, prefix, slice, suffix, cx.param_env, - ) { - Ok(true) => Some(smallvec![]), - Ok(false) => None, - Err(ErrorReported) => None - } + } + ConstantValue(cv, _) => { + match slice_pat_covered_by_const( + cx.tcx, + pat.span, + cv, + prefix, + slice, + suffix, + cx.param_env, + ) { + Ok(true) => Some(PatStack::default()), + Ok(false) => None, + Err(ErrorReported) => None, } - _ => span_bug!(pat.span, - "unexpected ctor {:?} for slice pat", constructor) } - } + _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor), + }, PatKind::Or { .. } => { bug!("support for or-patterns has not been fully implemented yet."); } }; - debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head); + debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result); - head.map(|mut head| { - head.extend_from_slice(&r[1 ..]); - head - }) + result } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 77f3768172fb4..9d370554e86b4 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -1,25 +1,24 @@ -use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; use super::_match::Usefulness::*; use super::_match::WitnessPreference::*; +use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}; -use super::{PatCtxt, PatternError, PatKind}; +use super::{PatCtxt, PatKind, PatternError}; +use rustc::lint; use rustc::session::Session; -use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; -use rustc::lint; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc::hir::HirId; use rustc::hir::def::*; use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc::hir::HirId; use rustc::hir::{self, Pat}; -use smallvec::smallvec; use std::slice; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use syntax_pos::{MultiSpan, Span, DUMMY_SP}; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match tcx.hir().as_local_hir_id(def_id) { @@ -100,13 +99,15 @@ impl PatCtxt<'_, '_> { ::rustc::mir::interpret::struct_error( self.tcx.at(pat_span), "could not evaluate float literal (see issue #31407)", - ).emit(); + ) + .emit(); } PatternError::NonConstPath(span) => { ::rustc::mir::interpret::struct_error( self.tcx.at(span), "runtime values cannot be referenced in patterns", - ).emit(); + ) + .emit(); } } } @@ -123,12 +124,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { check_legality_of_bindings_in_at_patterns(self, pat); } - fn check_match( - &mut self, - scrut: &hir::Expr, - arms: &'tcx [hir::Arm], - source: hir::MatchSource - ) { + fn check_match(&mut self, scrut: &hir::Expr, arms: &'tcx [hir::Arm], source: hir::MatchSource) { for arm in arms { // First, check legality of move bindings. self.check_patterns(arm.guard.is_some(), &arm.pat); @@ -141,31 +137,41 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { let mut have_errors = false; - let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| ( - // HACK(or_patterns; Centril | dlrobertson): Remove this and - // correctly handle exhaustiveness checking for nested or-patterns. - match &arm.pat.kind { - hir::PatKind::Or(pats) => pats, - _ => std::slice::from_ref(&arm.pat), - }.iter().map(|pat| { - let mut patcx = PatCtxt::new( - self.tcx, - self.param_env.and(self.identity_substs), - self.tables - ); - patcx.include_lint_checks(); - let pattern = - cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&pat))) as &_; - if !patcx.errors.is_empty() { - patcx.report_inlining_errors(pat.span); - have_errors = true; - } - (pattern, &**pat) - }).collect(), - arm.guard.as_ref().map(|g| match g { - hir::Guard::If(ref e) => &**e, + let inlined_arms: Vec<(Vec<_>, _)> = arms + .iter() + .map(|arm| { + ( + // HACK(or_patterns; Centril | dlrobertson): Remove this and + // correctly handle exhaustiveness checking for nested or-patterns. + match &arm.pat.kind { + hir::PatKind::Or(pats) => pats, + _ => std::slice::from_ref(&arm.pat), + } + .iter() + .map(|pat| { + let mut patcx = PatCtxt::new( + self.tcx, + self.param_env.and(self.identity_substs), + self.tables, + ); + patcx.include_lint_checks(); + let pattern = cx + .pattern_arena + .alloc(expand_pattern(cx, patcx.lower_pattern(&pat))) + as &_; + if !patcx.errors.is_empty() { + patcx.report_inlining_errors(pat.span); + have_errors = true; + } + (pattern, &**pat) + }) + .collect(), + arm.guard.as_ref().map(|g| match g { + hir::Guard::If(ref e) => &**e, + }), + ) }) - )).collect(); + .collect(); // Bail out early if inlining failed. if have_errors { @@ -191,17 +197,16 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { def_span = self.tcx.hir().span_if_local(def.did); if def.variants.len() < 4 && !def.variants.is_empty() { // keep around to point at the definition of non-covered variants - missing_variants = def.variants.iter() - .map(|variant| variant.ident) - .collect(); + missing_variants = + def.variants.iter().map(|variant| variant.ident).collect(); } let is_non_exhaustive_and_non_local = def.is_variant_list_non_exhaustive() && !def.did.is_local(); !(is_non_exhaustive_and_non_local) && def.variants.is_empty() - }, - _ => false + } + _ => false, } }; if !scrutinee_is_uninhabited { @@ -209,18 +214,25 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let mut err = create_e0004( self.tcx.sess, scrut.span, - format!("non-exhaustive patterns: {}", match missing_variants.len() { - 0 => format!("type `{}` is non-empty", pat_ty), - 1 => format!( - "pattern `{}` of type `{}` is not handled", - missing_variants[0].name, - pat_ty, - ), - _ => format!("multiple patterns of type `{}` are not handled", pat_ty), - }), + format!( + "non-exhaustive patterns: {}", + match missing_variants.len() { + 0 => format!("type `{}` is non-empty", pat_ty), + 1 => format!( + "pattern `{}` of type `{}` is not handled", + missing_variants[0].name, pat_ty, + ), + _ => format!( + "multiple patterns of type `{}` are not handled", + pat_ty + ), + } + ), + ); + err.help( + "ensure that all possible cases are being handled, \ + possibly by adding wildcards or more match arms", ); - err.help("ensure that all possible cases are being handled, \ - possibly by adding wildcards or more match arms"); if let Some(sp) = def_span { err.span_label(sp, format!("`{}` defined here", pat_ty)); } @@ -238,7 +250,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { .iter() .filter(|&&(_, guard)| guard.is_none()) .flat_map(|arm| &arm.0) - .map(|pat| smallvec![pat.0]) + .map(|pat| PatStack::from_pattern(pat.0)) .collect(); let scrut_ty = self.tables.node_type(scrut.hir_id); check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id); @@ -248,16 +260,13 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str, sp: Option) { let module = self.tcx.hir().get_module_parent(pat.hir_id); MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { - let mut patcx = PatCtxt::new(self.tcx, - self.param_env.and(self.identity_substs), - self.tables); + let mut patcx = + PatCtxt::new(self.tcx, self.param_env.and(self.identity_substs), self.tables); patcx.include_lint_checks(); let pattern = patcx.lower_pattern(pat); let pattern_ty = pattern.ty; let pattern = expand_pattern(cx, pattern); - let pats: Matrix<'_, '_> = vec![smallvec![ - &pattern - ]].into_iter().collect(); + let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(&pattern)].into_iter().collect(); let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) { Ok(_) => return, @@ -266,9 +275,12 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let joined_patterns = joined_uncovered_patterns(&witnesses); let mut err = struct_span_err!( - self.tcx.sess, pat.span, E0005, + self.tcx.sess, + pat.span, + E0005, "refutable pattern in {}: {} not covered", - origin, joined_patterns + origin, + joined_patterns ); let suggest_if_let = match &pat.kind { hir::PatKind::Path(hir::QPath::Resolved(None, path)) @@ -287,8 +299,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { }; if let (Some(span), true) = (sp, suggest_if_let) { - err.note("`let` bindings require an \"irrefutable pattern\", like a `struct` or \ - an `enum` with only one variant"); + err.note( + "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ + an `enum` with only one variant", + ); if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { err.span_suggestion( span, @@ -297,8 +311,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { Applicability::HasPlaceholders, ); } - err.note("for more information, visit \ - https://doc.rust-lang.org/book/ch18-02-refutability.html"); + err.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch18-02-refutability.html", + ); } adt_defined_here(cx, &mut err, pattern_ty, &witnesses); @@ -311,11 +327,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { /// This caused an irrefutable match failure in e.g. `let`. fn const_not_var(err: &mut DiagnosticBuilder<'_>, tcx: TyCtxt<'_>, pat: &Pat, path: &hir::Path) { let descr = path.res.descr(); - err.span_label(pat.span, format!( - "interpreted as {} {} pattern, not a new variable", - path.res.article(), - descr, - )); + err.span_label( + pat.span, + format!("interpreted as {} {} pattern, not a new variable", path.res.article(), descr,), + ); err.span_suggestion( pat.span, @@ -342,19 +357,26 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa } let pat_ty = cx.tables.pat_ty(p); if let ty::Adt(edef, _) = pat_ty.kind { - if edef.is_enum() && edef.variants.iter().any(|variant| { - variant.ident == ident && variant.ctor_kind == CtorKind::Const - }) { + if edef.is_enum() + && edef.variants.iter().any(|variant| { + variant.ident == ident && variant.ctor_kind == CtorKind::Const + }) + { let ty_path = cx.tcx.def_path_str(edef.did); - let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, + let mut err = struct_span_warn!( + cx.tcx.sess, + p.span, + E0170, "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", - ident, ty_path); + of the variants of the type `{}`", + ident, + ty_path + ); err.span_suggestion( p.span, "to match on the variant, qualify the path", format!("{}::{}", ty_path, ident), - Applicability::MachineApplicable + Applicability::MachineApplicable, ); err.emit(); } @@ -373,10 +395,8 @@ fn pat_is_catchall(pat: &Pat) -> bool { hir::PatKind::Binding(.., None) => true, hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s), hir::PatKind::Ref(ref s, _) => pat_is_catchall(s), - hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| { - pat_is_catchall(&p) - }), - _ => false + hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)), + _ => false, } } @@ -390,13 +410,14 @@ fn check_arms<'tcx>( let mut catchall = None; for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() { for &(pat, hir_pat) in pats { - let v = smallvec![pat]; + let v = PatStack::from_pattern(pat); match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) { NotUseful => { match source { - hir::MatchSource::IfDesugar { .. } | - hir::MatchSource::WhileDesugar => bug!(), + hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => { + bug!() + } hir::MatchSource::IfLetDesugar { .. } => { cx.tcx.lint_hir( lint::builtin::IRREFUTABLE_LET_PATTERNS, @@ -413,9 +434,11 @@ fn check_arms<'tcx>( 0 => { cx.tcx.lint_hir( lint::builtin::UNREACHABLE_PATTERNS, - hir_pat.hir_id, pat.span, - "unreachable pattern"); - }, + hir_pat.hir_id, + pat.span, + "unreachable pattern", + ); + } // The arm with the wildcard pattern. 1 => { cx.tcx.lint_hir( @@ -424,13 +447,12 @@ fn check_arms<'tcx>( pat.span, "irrefutable while-let pattern", ); - }, + } _ => bug!(), } } - hir::MatchSource::ForLoopDesugar | - hir::MatchSource::Normal => { + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { let mut err = cx.tcx.struct_span_lint_hir( lint::builtin::UNREACHABLE_PATTERNS, hir_pat.hir_id, @@ -447,12 +469,11 @@ fn check_arms<'tcx>( // Unreachable patterns in try and await expressions occur when one of // the arms are an uninhabited type. Which is OK. - hir::MatchSource::AwaitDesugar | - hir::MatchSource::TryDesugar => {} + hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} } } Useful => (), - UsefulWithWitness(_) => bug!() + UsefulWithWitness(_) => bug!(), } if guard.is_none() { seen.push(v); @@ -471,7 +492,7 @@ fn check_not_useful( hir_id: HirId, ) -> Result<(), Vec>> { let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild }; - match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness, hir_id) { + match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) { NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable. UsefulWithWitness(pats) => Err(if pats.is_empty() { vec![wild_pattern] @@ -496,14 +517,15 @@ fn check_exhaustive<'tcx>( let joined_patterns = joined_uncovered_patterns(&witnesses); let mut err = create_e0004( - cx.tcx.sess, sp, + cx.tcx.sess, + sp, format!("non-exhaustive patterns: {} not covered", joined_patterns), ); err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); adt_defined_here(cx, &mut err, scrut_ty, &witnesses); err.help( "ensure that all possible cases are being handled, \ - possibly by adding wildcards or more match arms" + possibly by adding wildcards or more match arms", ) .emit(); } @@ -556,7 +578,7 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec // Don't point at variants that have already been covered due to other patterns to avoid // visual clutter. for pattern in patterns { - use PatKind::{AscribeUserType, Deref, Variant, Or, Leaf}; + use PatKind::{AscribeUserType, Deref, Leaf, Or, Variant}; match &*pattern.kind { AscribeUserType { subpattern, .. } | Deref { subpattern } => { covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern))); @@ -568,13 +590,15 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec } covered.push(sp); - let pats = subpatterns.iter() + let pats = subpatterns + .iter() .map(|field_pattern| field_pattern.pattern.clone()) .collect::>(); covered.extend(maybe_point_at_variant(ty, &pats)); } Leaf { subpatterns } => { - let pats = subpatterns.iter() + let pats = subpatterns + .iter() .map(|field_pattern| field_pattern.pattern.clone()) .collect::>(); covered.extend(maybe_point_at_variant(ty, &pats)); @@ -659,7 +683,7 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pa struct AtBindingPatternVisitor<'a, 'b, 'tcx> { cx: &'a MatchVisitor<'b, 'tcx>, - bindings_allowed: bool + bindings_allowed: bool, } impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { @@ -671,10 +695,14 @@ impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { match pat.kind { hir::PatKind::Binding(.., ref subpat) => { if !self.bindings_allowed { - struct_span_err!(self.cx.tcx.sess, pat.span, E0303, - "pattern bindings are not allowed after an `@`") - .span_label(pat.span, "not allowed after `@`") - .emit(); + struct_span_err!( + self.cx.tcx.sess, + pat.span, + E0303, + "pattern bindings are not allowed after an `@`" + ) + .span_label(pat.span, "not allowed after `@`") + .emit(); } if subpat.is_some() {