rust/src/librustc_const_eval/_match.rs
Ariel Ben-Yehuda 98fbccee0c fix comments
2018-01-13 23:41:11 +02:00

1102 lines
42 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use self::Constructor::*;
use self::Usefulness::*;
use self::WitnessPreference::*;
use rustc::middle::const_val::ConstVal;
use eval::{compare_const_vals};
use rustc_const_math::ConstInt;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use pattern::{FieldPattern, Pattern, PatternKind};
use pattern::{PatternFoldable, PatternFolder};
use rustc::hir::def_id::DefId;
use rustc::hir::RangeEnd;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::mir::Field;
use rustc::util::common::ErrorReported;
use syntax_pos::{Span, DUMMY_SP};
use arena::TypedArena;
use std::cmp::{self, Ordering};
use std::fmt;
use std::iter::{FromIterator, IntoIterator, repeat};
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
-> &'a Pattern<'tcx>
{
cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
}
struct LiteralExpander;
impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
match (&pat.ty.sty, &*pat.kind) {
(&ty::TyRef(_, mt), &PatternKind::Constant { ref value }) => {
Pattern {
ty: pat.ty,
span: pat.span,
kind: box PatternKind::Deref {
subpattern: Pattern {
ty: mt.ty,
span: pat.span,
kind: box PatternKind::Constant { value: value.clone() },
}
}
}
}
(_, &PatternKind::Binding { subpattern: Some(ref s), .. }) => {
s.fold_with(self)
}
_ => pat.super_fold_with(self)
}
}
}
impl<'tcx> Pattern<'tcx> {
fn is_wildcard(&self) -> bool {
match *self.kind {
PatternKind::Binding { subpattern: None, .. } | PatternKind::Wild =>
true,
_ => false
}
}
}
pub struct Matrix<'a, 'tcx: 'a>(Vec<Vec<&'a Pattern<'tcx>>>);
impl<'a, 'tcx> Matrix<'a, 'tcx> {
pub fn empty() -> Self {
Matrix(vec![])
}
pub fn push(&mut self, row: Vec<&'a Pattern<'tcx>>) {
self.0.push(row)
}
}
/// Pretty-printer for matrices of patterns, example:
/// ++++++++++++++++++++++++++
/// + _ + [] +
/// ++++++++++++++++++++++++++
/// + true + [First] +
/// ++++++++++++++++++++++++++
/// + true + [Second(true)] +
/// ++++++++++++++++++++++++++
/// + false + [_] +
/// ++++++++++++++++++++++++++
/// + _ + [_, _, ..tail] +
/// ++++++++++++++++++++++++++
impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\n")?;
let &Matrix(ref m) = self;
let pretty_printed_matrix: Vec<Vec<String>> = 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<usize> = (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::<usize>() + column_count * 3 + 1;
let br = repeat('+').take(total_width).collect::<String>();
write!(f, "{}\n", br)?;
for row in pretty_printed_matrix {
write!(f, "+")?;
for (column, pat_str) in row.into_iter().enumerate() {
write!(f, " ")?;
write!(f, "{:1$}", pat_str, column_widths[column])?;
write!(f, " +")?;
}
write!(f, "\n")?;
write!(f, "{}\n", br)?;
}
Ok(())
}
}
impl<'a, 'tcx> FromIterator<Vec<&'a Pattern<'tcx>>> for Matrix<'a, 'tcx> {
fn from_iter<T: IntoIterator<Item=Vec<&'a Pattern<'tcx>>>>(iter: T) -> Self
{
Matrix(iter.into_iter().collect())
}
}
//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
/// The module in which the match occurs. This is necessary for
/// checking inhabited-ness of types because whether a type is (visibly)
/// inhabited can depend on whether it was defined in the current module or
/// not. eg. `struct Foo { _private: ! }` cannot be seen to be empty
/// outside it's module and should not be matchable with an empty match
/// statement.
pub module: DefId,
pub pattern_arena: &'a TypedArena<Pattern<'tcx>>,
pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>,
}
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
pub fn create_and_enter<F, R>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
module: DefId,
f: F) -> R
where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
{
let pattern_arena = TypedArena::new();
f(MatchCheckCtxt {
tcx,
module,
pattern_arena: &pattern_arena,
byte_array_map: FxHashMap(),
})
}
// convert a byte-string pattern to a list of u8 patterns.
fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Pattern<'tcx>>
where 'a: 'p
{
let pattern_arena = &*self.pattern_arena;
let tcx = self.tcx;
self.byte_array_map.entry(pat).or_insert_with(|| {
match pat.kind {
box PatternKind::Constant {
value: &ty::Const { val: ConstVal::ByteStr(b), .. }
} => {
b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern {
ty: tcx.types.u8,
span: pat.span,
kind: box PatternKind::Constant {
value: tcx.mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::U8(b)),
ty: tcx.types.u8
})
}
})).collect()
}
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
}
}).clone()
}
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
if self.tcx.sess.features.borrow().never_type {
self.tcx.is_ty_uninhabited_from(self.module, ty)
} else {
false
}
}
fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
match ty.sty {
ty::TyAdt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(),
_ => false,
}
}
fn is_local(&self, ty: Ty<'tcx>) -> bool {
match ty.sty {
ty::TyAdt(adt_def, ..) => adt_def.did.is_local(),
_ => false,
}
}
fn is_variant_uninhabited(&self,
variant: &'tcx ty::VariantDef,
substs: &'tcx ty::subst::Substs<'tcx>)
-> bool
{
if self.tcx.sess.features.borrow().never_type {
self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
} else {
false
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Constructor<'tcx> {
/// The constructor of all patterns that don't vary by constructor,
/// e.g. struct patterns and fixed-length arrays.
Single,
/// Enum variants.
Variant(DefId),
/// Literal values.
ConstantValue(&'tcx ty::Const<'tcx>),
/// Ranges of literal values (`2...5` and `2..5`).
ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
/// Array patterns of length n.
Slice(u64),
}
impl<'tcx> Constructor<'tcx> {
fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
match self {
&Variant(vid) => adt.variant_index_with_id(vid),
&Single => {
assert!(!adt.is_enum());
0
}
_ => bug!("bad constructor {:?} for adt {:?}", self, adt)
}
}
}
#[derive(Clone)]
pub enum Usefulness<'tcx> {
Useful,
UsefulWithWitness(Vec<Witness<'tcx>>),
NotUseful
}
impl<'tcx> Usefulness<'tcx> {
fn is_useful(&self) -> bool {
match *self {
NotUseful => false,
_ => true
}
}
}
#[derive(Copy, Clone)]
pub enum WitnessPreference {
ConstructWitness,
LeaveOutWitness
}
#[derive(Copy, Clone, Debug)]
struct PatternContext<'tcx> {
ty: Ty<'tcx>,
max_slice_length: u64,
}
/// A stack of patterns in reverse order of construction
#[derive(Clone)]
pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
impl<'tcx> Witness<'tcx> {
pub fn single_pattern(&self) -> &Pattern<'tcx> {
assert_eq!(self.0.len(), 1);
&self.0[0]
}
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| {
Pattern {
ty,
span: DUMMY_SP,
kind: box PatternKind::Wild,
}
}));
self.apply_constructor(cx, ctor, ty)
}
/// Constructs a partial witness for a pattern given a list of
/// patterns expanded by the specialization step.
///
/// When a pattern P is discovered to be useful, this function is used bottom-up
/// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
/// of values, V, where each value in that set is not covered by any previously
/// used patterns and is covered by the pattern P'. Examples:
///
/// left_ty: tuple of 3 elements
/// pats: [10, 20, _] => (10, 20, _)
///
/// left_ty: struct X { a: (bool, &'static str), b: usize}
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
fn apply_constructor<'a>(
mut self,
cx: &MatchCheckCtxt<'a,'tcx>,
ctor: &Constructor<'tcx>,
ty: Ty<'tcx>)
-> Self
{
let arity = constructor_arity(cx, ctor, ty);
let pat = {
let len = self.0.len() as u64;
let mut pats = self.0.drain((len-arity) as usize..).rev();
match ty.sty {
ty::TyAdt(..) |
ty::TyTuple(..) => {
let pats = pats.enumerate().map(|(i, p)| {
FieldPattern {
field: Field::new(i),
pattern: p
}
}).collect();
if let ty::TyAdt(adt, substs) = ty.sty {
if adt.is_enum() {
PatternKind::Variant {
adt_def: adt,
substs,
variant_index: ctor.variant_index_for_adt(adt),
subpatterns: pats
}
} else {
PatternKind::Leaf { subpatterns: pats }
}
} else {
PatternKind::Leaf { subpatterns: pats }
}
}
ty::TyRef(..) => {
PatternKind::Deref { subpattern: pats.nth(0).unwrap() }
}
ty::TySlice(_) | ty::TyArray(..) => {
PatternKind::Slice {
prefix: pats.collect(),
slice: None,
suffix: vec![]
}
}
_ => {
match *ctor {
ConstantValue(value) => PatternKind::Constant { value },
_ => PatternKind::Wild,
}
}
}
};
self.0.push(Pattern {
ty,
span: DUMMY_SP,
kind: Box::new(pat),
});
self
}
}
/// This determines the set of all possible constructors of a pattern matching
/// values of type `left_ty`. For vectors, this would normally be an infinite set
/// but is instead bounded by the maximum fixed length of slice patterns in
/// the column of patterns being analyzed.
///
/// This intentionally does not list ConstantValue specializations for
/// non-booleans, because we currently assume that there is always a
/// "non-standard constant" that matches. See issue #12483.
///
/// We make sure to omit constructors that are statically impossible. eg for
/// Option<!> we do not include Some(_) in the returned list of constructors.
fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
pcx: PatternContext<'tcx>)
-> Vec<Constructor<'tcx>>
{
debug!("all_constructors({:?})", pcx.ty);
match pcx.ty.sty {
ty::TyBool => {
[true, false].iter().map(|&b| {
ConstantValue(cx.tcx.mk_const(ty::Const {
val: ConstVal::Bool(b),
ty: cx.tcx.types.bool
}))
}).collect()
}
ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => {
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
if len != 0 && cx.is_uninhabited(sub_ty) {
vec![]
} else {
vec![Slice(len)]
}
}
// Treat arrays of a constant but unknown length like slices.
ty::TyArray(ref sub_ty, _) |
ty::TySlice(ref sub_ty) => {
if cx.is_uninhabited(sub_ty) {
vec![Slice(0)]
} else {
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
}
}
ty::TyAdt(def, substs) if def.is_enum() => {
def.variants.iter()
.filter(|v| !cx.is_variant_uninhabited(v, substs))
.map(|v| Variant(v.did))
.collect()
}
_ => {
if cx.is_uninhabited(pcx.ty) {
vec![]
} else {
vec![Single]
}
}
}
}
fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
_cx: &mut MatchCheckCtxt<'a, 'tcx>,
patterns: I) -> u64
where I: Iterator<Item=&'p Pattern<'tcx>>
{
// The exhaustiveness-checking paper does not include any details on
// checking variable-length slice patterns. However, they are matched
// by an infinite collection of fixed-length array patterns.
//
// Checking the infinite set directly would take an infinite amount
// of time. However, it turns out that for each finite set of
// patterns `P`, all sufficiently large array lengths are equivalent:
//
// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
// to exactly the subset `Pₜ` of `P` can be transformed to a slice
// `sₘ` for each sufficiently-large length `m` that applies to exactly
// the same subset of `P`.
//
// Because of that, each witness for reachability-checking from one
// of the sufficiently-large lengths can be transformed to an
// equally-valid witness from any other length, so we only have
// to check slice lengths from the "minimal sufficiently-large length"
// and below.
//
// Note that the fact that there is a *single* `sₘ` for each `m`
// not depending on the specific pattern in `P` is important: if
// you look at the pair of patterns
// `[true, ..]`
// `[.., false]`
// Then any slice of length ≥1 that matches one of these two
// patterns can be be trivially turned to a slice of any
// other length ≥1 that matches them and vice-versa - for
// but the slice from length 2 `[false, true]` that matches neither
// of these patterns can't be turned to a slice from length 1 that
// matches neither of these patterns, so we have to consider
// slices from length 2 there.
//
// Now, to see that that length exists and find it, observe that slice
// patterns are either "fixed-length" patterns (`[_, _, _]`) or
// "variable-length" patterns (`[_, .., _]`).
//
// For fixed-length patterns, all slices with lengths *longer* than
// the pattern's length have the same outcome (of not matching), so
// as long as `L` is greater than the pattern's length we can pick
// any `sₘ` from that length and get the same result.
//
// For variable-length patterns, the situation is more complicated,
// because as seen above the precise value of `sₘ` matters.
//
// However, for each variable-length pattern `p` with a prefix of length
// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
// `slₚ` elements are examined.
//
// Therefore, as long as `L` is positive (to avoid concerns about empty
// types), all elements after the maximum prefix length and before
// the maximum suffix length are not examined by any variable-length
// pattern, and therefore can be added/removed without affecting
// them - creating equivalent patterns from any sufficiently-large
// length.
//
// Of course, if fixed-length patterns exist, we must be sure
// that our length is large enough to miss them all, so
// we can pick `L = max(FIXED_LEN+1 {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
//
// for example, with the above pair of patterns, all elements
// but the first and last can be added/removed, so any
// witness of length ≥2 (say, `[false, false, true]`) can be
// turned to a witness from any other length ≥2.
let mut max_prefix_len = 0;
let mut max_suffix_len = 0;
let mut max_fixed_len = 0;
for row in patterns {
match *row.kind {
PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => {
max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64);
}
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
}
PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
}
_ => {}
}
}
cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len)
}
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
/// The algorithm from the paper has been modified to correctly handle empty
/// types. The changes are:
/// (0) We don't exit early if the pattern matrix has zero rows. We just
/// continue to recurse over columns.
/// (1) all_constructors will only return constructors that are statically
/// possible. eg. it will only return Ok for Result<T, !>
///
/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
/// to a set of such vectors `m` - this is defined as there being a set of
/// inputs that will match `v` but not any of the sets in `m`.
///
/// All the patterns at each column of the `matrix ++ v` matrix must
/// have the same type, except that wildcard (PatternKind::Wild) patterns
/// with type TyErr are also allowed, even if the "type of the column"
/// is not TyErr. That is used to represent private fields, as using their
/// real type would assert that they are inhabited.
///
/// This is used both for reachability checking (if a pattern isn't useful in
/// relation to preceding patterns, it is not reachable) and exhaustiveness
/// checking (if a wildcard pattern is useful in relation to a matrix, the
/// matrix isn't exhaustive).
pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
v: &[&'p Pattern<'tcx>],
witness: WitnessPreference)
-> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:?}, {:?})", matrix, v);
// The base case. We are pattern-matching on () and the return value is
// based on whether our matrix has a row or not.
// NOTE: This could potentially be optimized by checking rows.is_empty()
// first and then, if v is non-empty, the return value is based on whether
// 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,
}
} else {
NotUseful
}
};
assert!(rows.iter().all(|r| r.len() == v.len()));
let pcx = PatternContext {
// TyErr is used to represent the type of wildcard patterns matching
// against inaccessible (private) fields of structs, so that we won't
// be able to observe whether the types of the struct's fields are
// inhabited.
//
// If the field is truely inaccessible, then all the patterns
// matching against it must be wildcard patterns, so its type
// does not matter.
//
// However, if we are matching against non-wildcard patterns, we
// need to know the real type of the field so we can specialize
// against it. This primarily occurs through constants - they
// can include contents for fields that are inaccessible at the
// location of the match. In that case, the field's type is
// inhabited - by the constant - so we can just use it.
//
// FIXME: this might lead to "unstable" behavior with macro hygiene
// introducing uninhabited patterns for inaccessible fields. We
// need to figure out how to model that.
ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
.unwrap_or(v[0].ty),
max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
};
debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]);
if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
debug!("is_useful - expanding constructors: {:?}", constructors);
constructors.into_iter().map(|c|
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
).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[0], pcx).unwrap_or(vec![])
}).collect();
debug!("used_ctors = {:?}", used_ctors);
let all_ctors = all_constructors(cx, pcx);
debug!("all_ctors = {:?}", all_ctors);
let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
!used_ctors.contains(*c)
}).cloned().collect();
// `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.
//
// Therefore, if there is some pattern that is unmatched by `matrix`,
// it will still be unmatched if the first constructor is replaced by
// any of the constructors in `missing_ctors`
//
// However, if our scrutinee is *privately* an empty enum, we
// must treat it as though it had an "unknown" constructor (in
// that case, all other patterns obviously can't be variants)
// to avoid exposing its emptyness. See the `match_privately_empty`
// test for details.
//
// FIXME: currently the only way I know of something can
// be a privately-empty enum is when the never_type
// feature flag is not present, so this is only
// needed for that case.
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!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}",
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;
if missing_ctors.is_empty() && !is_non_exhaustive {
all_ctors.into_iter().map(|c| {
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
} else {
let matrix = rows.iter().filter_map(|r| {
if r[0].is_wildcard() {
Some(r[1..].to_vec())
} else {
None
}
}).collect();
match is_useful(cx, &matrix, &v[1..], witness) {
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
// `(<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
// rather than each individual constructor
pats.into_iter().map(|mut witness| {
witness.0.push(Pattern {
ty: pcx.ty,
span: DUMMY_SP,
kind: box PatternKind::Wild,
});
witness
}).collect()
} else {
pats.into_iter().flat_map(|witness| {
missing_ctors.iter().map(move |ctor| {
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
})
}).collect()
};
UsefulWithWitness(new_witnesses)
}
result => result
}
}
}
}
fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
&Matrix(ref m): &Matrix<'p, 'tcx>,
v: &[&'p Pattern<'tcx>],
ctor: Constructor<'tcx>,
lty: Ty<'tcx>,
witness: WitnessPreference) -> 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| {
Pattern {
ty,
span: DUMMY_SP,
kind: box PatternKind::Wild,
}
}).collect();
let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
let matrix = Matrix(m.iter().flat_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) {
UsefulWithWitness(witnesses) => UsefulWithWitness(
witnesses.into_iter()
.map(|witness| witness.apply_constructor(cx, &ctor, lty))
.collect()
),
result => result
},
None => NotUseful
}
}
/// Determines the constructors that the given pattern can be specialized to.
///
/// 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.
///
/// Returns None in case of a catch-all, which can't be specialized.
fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
pat: &Pattern<'tcx>,
pcx: PatternContext)
-> Option<Vec<Constructor<'tcx>>>
{
match *pat.kind {
PatternKind::Binding { .. } | PatternKind::Wild =>
None,
PatternKind::Leaf { .. } | PatternKind::Deref { .. } =>
Some(vec![Single]),
PatternKind::Variant { adt_def, variant_index, .. } =>
Some(vec![Variant(adt_def.variants[variant_index].did)]),
PatternKind::Constant { value } =>
Some(vec![ConstantValue(value)]),
PatternKind::Range { lo, hi, end } =>
Some(vec![ConstantRange(lo, hi, end)]),
PatternKind::Array { .. } => match pcx.ty.sty {
ty::TyArray(_, length) => Some(vec![
Slice(length.val.to_const_int().unwrap().to_u64().unwrap())
]),
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
},
PatternKind::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())
} else {
Some(vec![Slice(pat_len)])
}
}
}
}
/// 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, ctor: &Constructor, ty: Ty) -> u64 {
debug!("constructor_arity({:?}, {:?})", ctor, ty);
match ty.sty {
ty::TyTuple(ref fs, _) => fs.len() as u64,
ty::TySlice(..) | ty::TyArray(..) => match *ctor {
Slice(length) => length,
ConstantValue(_) => 0,
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
},
ty::TyRef(..) => 1,
ty::TyAdt(adt, _) => {
adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
}
_ => 0
}
}
/// This computes the types of the sub patterns that a constructor should be
/// expanded to.
///
/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
ctor: &Constructor,
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
{
debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty);
match ty.sty {
ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
Slice(length) => (0..length).map(|_| ty).collect(),
ConstantValue(_) => vec![],
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
},
ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
ty::TyAdt(adt, substs) => {
if adt.is_box() {
// Use T as the sub pattern type of Box<T>.
vec![substs[0].as_type().unwrap()]
} else {
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
let is_visible = adt.is_enum()
|| field.vis.is_accessible_from(cx.module, cx.tcx);
if is_visible {
field.ty(cx.tcx, substs)
} else {
// 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.
cx.tcx.types.err
}
}).collect()
}
}
_ => vec![],
}
}
fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
ctor: &Constructor,
prefix: &[Pattern],
slice: &Option<Pattern>,
suffix: &[Pattern])
-> Result<bool, ErrorReported> {
let data = match *ctor {
ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data,
_ => bug!()
};
let pat_len = prefix.len() + suffix.len();
if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
return Ok(false);
}
for (ch, pat) in
data[..prefix.len()].iter().zip(prefix).chain(
data[data.len()-suffix.len()..].iter().zip(suffix))
{
match pat.kind {
box PatternKind::Constant { value } => match value.val {
ConstVal::Integral(ConstInt::U8(u)) => {
if u != *ch {
return Ok(false);
}
},
_ => span_bug!(pat.span, "bad const u8 {:?}", value)
},
_ => {}
}
}
Ok(true)
}
fn constructor_covered_by_range(tcx: TyCtxt, span: Span,
ctor: &Constructor,
from: &ConstVal, to: &ConstVal,
end: RangeEnd)
-> Result<bool, ErrorReported> {
let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less);
let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
match *ctor {
ConstantValue(value) => {
let to = cmp_to(&value.val)?;
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
Ok(cmp_from(&value.val)? && end)
},
ConstantRange(from, to, RangeEnd::Included) => {
let to = cmp_to(&to.val)?;
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
Ok(cmp_from(&from.val)? && end)
},
ConstantRange(from, to, RangeEnd::Excluded) => {
let to = cmp_to(&to.val)?;
let end = (to == Ordering::Less) ||
(end == RangeEnd::Excluded && to == Ordering::Equal);
Ok(cmp_from(&from.val)? && end)
}
Single => Ok(true),
_ => bug!(),
}
}
fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
subpatterns: &'p [FieldPattern<'tcx>],
wild_patterns: &[&'p Pattern<'tcx>])
-> Vec<&'p Pattern<'tcx>>
{
let mut result = wild_patterns.to_owned();
for subpat in subpatterns {
result[subpat.field.index()] = &subpat.pattern;
}
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result);
result
}
/// This is the main specialization step. It expands the first pattern in the given row
/// 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.
///
/// 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: 'a>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
r: &[&'p Pattern<'tcx>],
constructor: &Constructor,
wild_patterns: &[&'p Pattern<'tcx>])
-> Option<Vec<&'p Pattern<'tcx>>>
{
let pat = &r[0];
let head: Option<Vec<&Pattern>> = match *pat.kind {
PatternKind::Binding { .. } | PatternKind::Wild => {
Some(wild_patterns.to_owned())
},
PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
let ref variant = adt_def.variants[variant_index];
if *constructor == Variant(variant.did) {
Some(patterns_for_variant(subpatterns, wild_patterns))
} else {
None
}
}
PatternKind::Leaf { ref subpatterns } => {
Some(patterns_for_variant(subpatterns, wild_patterns))
}
PatternKind::Deref { ref subpattern } => {
Some(vec![subpattern])
}
PatternKind::Constant { value } => {
match *constructor {
Slice(..) => match value.val {
ConstVal::ByteStr(b) => {
if wild_patterns.len() == b.data.len() {
Some(cx.lower_byte_str_pattern(pat))
} else {
None
}
}
_ => span_bug!(pat.span,
"unexpected const-val {:?} with ctor {:?}", value, constructor)
},
_ => {
match constructor_covered_by_range(
cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}
}
}
PatternKind::Range { lo, hi, ref end } => {
match constructor_covered_by_range(
cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone()
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}
PatternKind::Array { ref prefix, ref slice, ref suffix } |
PatternKind::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
}
} else {
None
}
}
ConstantValue(..) => {
match slice_pat_covered_by_constructor(
cx.tcx, pat.span, constructor, prefix, slice, suffix
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None
}
}
_ => span_bug!(pat.span,
"unexpected ctor {:?} for slice pat", constructor)
}
}
};
debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head);
head.map(|mut head| {
head.extend_from_slice(&r[1 ..]);
head
})
}