change match checking to use HAIR

no intended functional changes
This commit is contained in:
Ariel Ben-Yehuda 2016-09-26 02:53:26 +03:00
parent 04a92a1f56
commit e313d8b290
8 changed files with 386 additions and 263 deletions

1
src/Cargo.lock generated
View File

@ -330,6 +330,7 @@ dependencies = [
name = "rustc_const_eval"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"graphviz 0.0.0",
"log 0.0.0",
"rustc 0.0.0",

View File

@ -9,6 +9,7 @@ path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
arena = { path = "../libarena" }
log = { path = "../liblog" }
serialize = { path = "../libserialize" }
rustc = { path = "../librustc" }

View File

@ -13,20 +13,20 @@ use self::Usefulness::*;
use self::WitnessPreference::*;
use rustc::middle::const_val::ConstVal;
use eval::{eval_const_expr, compare_const_vals};
use eval::{compare_const_vals};
use rustc_data_structures::indexed_vec::Idx;
use pattern::{FieldPattern, Pattern, PatternKind};
use pattern::{PatternFoldable, PatternFolder};
use rustc::hir::def::*;
use rustc::hir::def_id::{DefId};
use rustc::hir::pat_util::def_to_path;
use rustc::ty::{self, Ty, TyCtxt};
use std::cmp::Ordering;
use std::fmt;
use std::iter::{FromIterator, IntoIterator, repeat};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::hir;
use rustc::hir::def::CtorKind;
use rustc::hir::{Pat, PatKind};
use rustc::hir::print::pat_to_string;
use rustc::util::common::ErrorReported;
use syntax::ast::{self, DUMMY_NODE_ID};
@ -34,53 +34,69 @@ use syntax::codemap::Spanned;
use syntax::ptr::P;
use syntax_pos::{Span, DUMMY_SP};
use arena::TypedArena;
use std::cmp::Ordering;
use std::fmt;
use std::iter::{FromIterator, IntoIterator, repeat};
pub fn lower_pat<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: &Pat)
-> &'a Pattern<'tcx>
{
cx.pattern_arena.alloc(
LiteralExpander.fold_pattern(&Pattern::from_hir(cx.tcx, 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)
}
}
}
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
id: DUMMY_NODE_ID,
node: PatKind::Wild,
span: DUMMY_SP
};
pub const DUMMY_WILD_PATTERN : Pattern<'static, 'static> = Pattern {
pat: DUMMY_WILD_PAT,
pattern_ty: None
};
#[derive(Copy, Clone)]
pub struct Pattern<'a, 'tcx> {
pat: &'a Pat,
pattern_ty: Option<Ty<'tcx>>
}
impl<'a, 'tcx> Pattern<'a, 'tcx> {
fn as_raw(self) -> &'a Pat {
let mut pat = self.pat;
while let PatKind::Binding(.., Some(ref s)) = pat.node {
pat = s;
impl<'tcx> Pattern<'tcx> {
fn is_wildcard(&self) -> bool {
match *self.kind {
PatternKind::Binding { subpattern: None, .. } | PatternKind::Wild =>
true,
_ => false
}
return pat;
}
pub fn span(self) -> Span {
self.pat.span
}
}
impl<'a, 'tcx> fmt::Debug for Pattern<'a, 'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {:?}", pat_to_string(self.pat), self.pattern_ty)
}
}
pub struct Matrix<'a, 'tcx>(Vec<Vec<Pattern<'a, 'tcx>>>);
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<Pattern<'a, 'tcx>>) {
pub fn push(&mut self, row: Vec<&'a Pattern<'tcx>>) {
self.0.push(row)
}
}
@ -129,8 +145,8 @@ impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
}
}
impl<'a, 'tcx> FromIterator<Vec<Pattern<'a, 'tcx>>> for Matrix<'a, 'tcx> {
fn from_iter<T: IntoIterator<Item=Vec<Pattern<'a, 'tcx>>>>(iter: T) -> Self
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())
}
@ -140,6 +156,34 @@ impl<'a, 'tcx> FromIterator<Vec<Pattern<'a, 'tcx>>> for Matrix<'a, 'tcx> {
pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub param_env: ty::ParameterEnvironment<'tcx>,
/// A wild pattern with an error type - it exists to avoid having to normalize
/// associated types to get field types.
pub wild_pattern: &'a Pattern<'tcx>,
pub pattern_arena: &'a TypedArena<Pattern<'tcx>>,
}
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
pub fn create_and_enter<F, R>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParameterEnvironment<'tcx>,
f: F) -> R
where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
{
let wild_pattern = Pattern {
ty: tcx.types.err,
span: DUMMY_SP,
kind: box PatternKind::Wild
};
let pattern_arena = TypedArena::new();
f(MatchCheckCtxt {
tcx: tcx,
param_env: param_env,
wild_pattern: &wild_pattern,
pattern_arena: &pattern_arena,
})
}
}
#[derive(Clone, Debug, PartialEq)]
@ -163,7 +207,11 @@ impl Constructor {
-> &'a ty::VariantDefData<'tcx, 'container> {
match self {
&Variant(vid) => adt.variant_with_id(vid),
_ => adt.struct_variant()
&Single => {
assert_eq!(adt.variants.len(), 1);
&adt.variants[0]
}
_ => bug!("bad constructor {:?} for adt {:?}", self, adt)
}
}
}
@ -320,6 +368,7 @@ fn missing_constructors(cx: &MatchCheckCtxt, matrix: &Matrix,
matrix.0.iter()
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
.collect();
debug!("used_constructors = {:?}", used_constructors);
all_constructors(cx, pcx).into_iter()
.filter(|c| !used_constructors.contains(c))
.collect()
@ -335,28 +384,28 @@ fn all_constructors(_cx: &MatchCheckCtxt, pcx: PatternContext) -> Vec<Constructo
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
ty::TySlice(_) =>
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect(),
ty::TyAdt(def, _) if def.is_enum() =>
ty::TyAdt(def, _) if def.is_enum() && def.variants.len() > 1 =>
def.variants.iter().map(|v| Variant(v.did)).collect(),
_ => vec![Single]
}
}
// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
//
// Whether a vector `v` of patterns is 'useful' in relation to a set of such
// vectors `m` is defined as there being a set of inputs that will match `v`
// but not any of the sets in `m`.
//
// 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).
// Note: is_useful doesn't work on empty types, as the paper notes.
// So it assumes that v is non-empty.
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
///
/// Whether a vector `v` of patterns is 'useful' in relation to a set of such
/// vectors `m` is defined as there being a set of inputs that will match `v`
/// but not any of the sets in `m`.
///
/// 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).
///
/// Note: is_useful doesn't work on empty types, as the paper notes.
/// So it assumes that v is non-empty.
pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
matrix: &Matrix<'a, 'tcx>,
v: &[Pattern<'a, 'tcx>],
v: &[&'a Pattern<'tcx>],
witness: WitnessPreference)
-> Usefulness {
let &Matrix(ref rows) = matrix;
@ -375,17 +424,11 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
assert!(rows.iter().all(|r| r.len() == v.len()));
let pcx = PatternContext {
ty: match rows.iter().filter_map(|r| r[0].pattern_ty).next()
.or_else(|| v[0].pattern_ty)
{
Some(ty) => ty,
None => {
// all patterns are wildcards - we can pick any type we want
cx.tcx.types.bool
}
},
max_slice_length: rows.iter().filter_map(|row| match row[0].pat.node {
PatKind::Slice(ref before, _, ref after) => Some(before.len() + after.len()),
ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
.unwrap_or(v[0].ty),
max_slice_length: rows.iter().filter_map(|row| match *row[0].kind {
PatternKind::Slice { ref prefix, slice: _, ref suffix } =>
Some(prefix.len() + suffix.len()),
_ => None
}).max().map_or(0, |v| v + 1)
};
@ -407,9 +450,10 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
} else {
let matrix = rows.iter().filter_map(|r| {
match r[0].as_raw().node {
PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()),
_ => None,
if r[0].is_wildcard() {
Some(r[1..].to_vec())
} else {
None
}
}).collect();
match is_useful(cx, &matrix, &v[1..], witness) {
@ -429,7 +473,7 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
fn is_useful_specialized<'a, 'tcx>(
cx: &MatchCheckCtxt<'a, 'tcx>,
&Matrix(ref m): &Matrix<'a, 'tcx>,
v: &[Pattern<'a, 'tcx>],
v: &[&'a Pattern<'tcx>],
ctor: Constructor,
lty: Ty<'tcx>,
witness: WitnessPreference) -> Usefulness
@ -459,42 +503,30 @@ fn is_useful_specialized<'a, 'tcx>(
/// `[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(cx: &MatchCheckCtxt,
p: Pattern,
fn pat_constructors(_cx: &MatchCheckCtxt,
pat: &Pattern,
pcx: PatternContext)
-> Option<Vec<Constructor>>
{
let pat = p.as_raw();
match pat.node {
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
match cx.tcx.expect_def(pat.id) {
Def::Variant(id) | Def::VariantCtor(id, _) => Some(vec![Variant(id)]),
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) => Some(vec![Single]),
Def::Const(..) | Def::AssociatedConst(..) =>
span_bug!(p.span(), "const pattern should've been rewritten"),
def => span_bug!(p.span(), "pat_constructors: unexpected definition {:?}", def),
},
PatKind::Lit(ref expr) =>
Some(vec![ConstantValue(eval_const_expr(cx.tcx, &expr))]),
PatKind::Range(ref lo, ref hi) =>
Some(vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))]),
PatKind::Slice(ref before, ref slice, ref after) =>
match pcx.ty.sty {
ty::TyArray(..) => Some(vec![Single]),
ty::TySlice(_) if slice.is_some() => {
Some((before.len() + after.len()..pcx.max_slice_length+1)
.map(|length| Slice(length))
.collect())
}
ty::TySlice(_) => Some(vec!(Slice(before.len() + after.len()))),
_ => span_bug!(pat.span, "pat_constructors: unexpected \
slice pattern type {:?}", pcx.ty)
},
PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) =>
Some(vec![Single]),
PatKind::Binding(..) | PatKind::Wild =>
match *pat.kind {
PatternKind::Binding { .. } | PatternKind::Wild =>
None,
PatternKind::Leaf { .. } | PatternKind::Deref { .. } | PatternKind::Array { .. } =>
Some(vec![Single]),
PatternKind::Variant { adt_def, variant_index, .. } =>
Some(vec![Variant(adt_def.variants[variant_index].did)]),
PatternKind::Constant { ref value } =>
Some(vec![ConstantValue(value.clone())]),
PatternKind::Range { ref lo, ref hi } =>
Some(vec![ConstantRange(lo.clone(), hi.clone())]),
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
let pat_len = prefix.len() + suffix.len();
if slice.is_some() {
Some((pat_len..pcx.max_slice_length+1).map(Slice).collect())
} else {
Some(vec![Slice(pat_len)])
}
}
}
}
@ -540,20 +572,20 @@ fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
}
pub fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
pat: &'a Pat)
-> Pattern<'a, 'tcx>
fn patterns_for_variant<'a, 'tcx>(
cx: &MatchCheckCtxt<'a, 'tcx>,
subpatterns: &'a [FieldPattern<'tcx>],
arity: usize)
-> Vec<&'a Pattern<'tcx>>
{
let pat_ty = cx.tcx.pat_ty(pat);
Pattern {
pat: pat,
pattern_ty: Some(match pat.node {
PatKind::Binding(hir::BindByRef(..), ..) => {
pat_ty.builtin_deref(false, ty::NoPreference).unwrap().ty
}
_ => pat_ty
})
let mut result = vec![cx.wild_pattern; arity];
for subpat in subpatterns {
result[subpat.field.index()] = &subpat.pattern;
}
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, arity, result);
result
}
/// This is the main specialization step. It expands the first pattern in the given row
@ -564,118 +596,34 @@ pub fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
/// different patterns.
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
/// fields filled with wild patterns.
fn specialize<'a, 'b, 'tcx>(
cx: &MatchCheckCtxt<'b, 'tcx>,
r: &[Pattern<'a, 'tcx>],
fn specialize<'a, 'tcx>(
cx: &MatchCheckCtxt<'a, 'tcx>,
r: &[&'a Pattern<'tcx>],
constructor: &Constructor, col: usize, arity: usize)
-> Option<Vec<Pattern<'a, 'tcx>>>
-> Option<Vec<&'a Pattern<'tcx>>>
{
let pat = r[col].as_raw();
let &Pat {
id: pat_id, ref node, span: pat_span
} = pat;
let wpat = |pat: &'a Pat| wrap_pat(cx, pat);
let pat = &r[col];
let head: Option<Vec<Pattern>> = match *node {
PatKind::Binding(..) | PatKind::Wild =>
Some(vec![DUMMY_WILD_PATTERN; arity]),
let head: Option<Vec<&Pattern>> = match *pat.kind {
PatternKind::Binding { .. } | PatternKind::Wild =>
Some(vec![cx.wild_pattern; arity]),
PatKind::Path(..) => {
match cx.tcx.expect_def(pat_id) {
Def::Const(..) | Def::AssociatedConst(..) =>
span_bug!(pat_span, "const pattern should've \
been rewritten"),
Def::VariantCtor(id, CtorKind::Const) if *constructor != Variant(id) => None,
Def::VariantCtor(_, CtorKind::Const) |
Def::StructCtor(_, CtorKind::Const) => Some(Vec::new()),
def => span_bug!(pat_span, "specialize: unexpected \
definition {:?}", def),
}
}
PatKind::TupleStruct(_, ref args, ddpos) => {
match cx.tcx.expect_def(pat_id) {
Def::Const(..) | Def::AssociatedConst(..) =>
span_bug!(pat_span, "const pattern should've \
been rewritten"),
Def::VariantCtor(id, CtorKind::Fn) if *constructor != Variant(id) => None,
Def::VariantCtor(_, CtorKind::Fn) |
Def::StructCtor(_, CtorKind::Fn) => {
match ddpos {
Some(ddpos) => {
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| {
wpat(p)
}).collect();
pats.extend(repeat(DUMMY_WILD_PATTERN).take(arity - args.len()));
pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
Some(pats)
}
None => Some(args.iter().map(|p| wpat(p)).collect())
}
}
def => span_bug!(pat_span, "specialize: unexpected definition: {:?}", def)
}
}
PatKind::Struct(_, ref pattern_fields, _) => {
let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap();
let variant = constructor.variant_for_adt(adt);
let def_variant = adt.variant_of_def(cx.tcx.expect_def(pat_id));
if variant.did == def_variant.did {
Some(variant.fields.iter().map(|sf| {
match pattern_fields.iter().find(|f| f.node.name == sf.name) {
Some(ref f) => wpat(&f.node.pat),
_ => DUMMY_WILD_PATTERN
}
}).collect())
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(cx, subpatterns, arity))
} else {
None
}
}
PatKind::Tuple(ref args, Some(ddpos)) => {
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| wpat(p)).collect();
pats.extend(repeat(DUMMY_WILD_PATTERN).take(arity - args.len()));
pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
Some(pats)
}
PatKind::Tuple(ref args, None) =>
Some(args.iter().map(|p| wpat(&**p)).collect()),
PatternKind::Leaf { ref subpatterns } => Some(patterns_for_variant(cx, subpatterns, arity)),
PatternKind::Deref { ref subpattern } => Some(vec![subpattern]),
PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) =>
Some(vec![wpat(&**inner)]),
PatKind::Lit(ref expr) => {
match r[col].pattern_ty {
Some(&ty::TyS { sty: ty::TyRef(_, mt), .. }) => {
// HACK: handle string literals. A string literal pattern
// serves both as an unary reference pattern and as a
// nullary value pattern, depending on the type.
Some(vec![Pattern {
pat: pat,
pattern_ty: Some(mt.ty)
}])
}
Some(ty) => {
assert_eq!(constructor_arity(cx, constructor, ty), 0);
let expr_value = eval_const_expr(cx.tcx, &expr);
match range_covered_by_constructor(
cx.tcx, expr.span, constructor, &expr_value, &expr_value
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}
None => span_bug!(pat.span, "literal pattern {:?} has no type", pat)
}
}
PatKind::Range(ref from, ref to) => {
let from_value = eval_const_expr(cx.tcx, &from);
let to_value = eval_const_expr(cx.tcx, &to);
PatternKind::Constant { ref value } => {
assert_eq!(constructor_arity(cx, constructor, pat.ty), 0);
match range_covered_by_constructor(
cx.tcx, pat_span, constructor, &from_value, &to_value
cx.tcx, pat.span, constructor, value, value
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
@ -683,31 +631,39 @@ fn specialize<'a, 'b, 'tcx>(
}
}
PatKind::Slice(ref before, ref slice, ref after) => {
let pat_len = before.len() + after.len();
match *constructor {
Single => {
// Fixed-length vectors.
PatternKind::Range { ref lo, ref hi } => {
match range_covered_by_constructor(
cx.tcx, pat.span, constructor, lo, hi
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}
PatternKind::Array { ref prefix, slice: _, ref suffix } => {
let pat_len = prefix.len() + suffix.len();
Some(
prefix.iter().chain(
repeat(cx.wild_pattern).take(arity - pat_len).chain(
suffix.iter()
)).collect())
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
let pat_len = prefix.len() + suffix.len();
if let Some(slice_count) = arity.checked_sub(pat_len) {
if slice_count == 0 || slice.is_some() {
Some(
before.iter().map(|p| wpat(p)).chain(
repeat(DUMMY_WILD_PATTERN).take(arity - pat_len).chain(
after.iter().map(|p| wpat(p))
)).collect())
},
Slice(length) if pat_len <= length && slice.is_some() => {
Some(
before.iter().map(|p| wpat(p)).chain(
repeat(DUMMY_WILD_PATTERN).take(arity - pat_len).chain(
after.iter().map(|p| wpat(p))
prefix.iter().chain(
repeat(cx.wild_pattern).take(slice_count).chain(
suffix.iter()
)).collect())
} else {
None
}
Slice(length) if pat_len == length => {
Some(
before.iter().map(|p| wpat(p)).chain(
after.iter().map(|p| wpat(p))
).collect())
}
_ => None
} else {
None
}
}
};
@ -720,12 +676,15 @@ fn specialize<'a, 'b, 'tcx>(
})
}
pub fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F)
-> Option<A> where
pub fn is_refutable<'a, 'tcx, A, F>(
cx: &MatchCheckCtxt<'a, 'tcx>,
pat: &'a Pattern<'tcx>,
refutable: F)
-> Option<A> where
F: FnOnce(&Witness) -> A,
{
let pats = Matrix(vec!(vec!(wrap_pat(cx, pat))));
match is_useful(cx, &pats, &[DUMMY_WILD_PATTERN], ConstructWitness) {
let pats = Matrix(vec![vec![pat]]);
match is_useful(cx, &pats, &[cx.wild_pattern], ConstructWitness) {
UsefulWithWitness(pats) => Some(refutable(&pats[0])),
NotUseful => None,
Useful => bug!()

View File

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use _match::{MatchCheckCtxt, Matrix, wrap_pat, is_refutable, is_useful};
use _match::{DUMMY_WILD_PATTERN, DUMMY_WILD_PAT};
use _match::{MatchCheckCtxt, Matrix, lower_pat, is_refutable, is_useful};
use _match::{DUMMY_WILD_PAT};
use _match::Usefulness::*;
use _match::WitnessPreference::*;
@ -58,9 +58,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> {
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut MatchCheckCtxt {
tcx: tcx,
param_env: tcx.empty_parameter_environment(),
MatchCheckCtxt::create_and_enter(tcx, tcx.empty_parameter_environment(), |mut cx| {
tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut cx);
});
tcx.sess.abort_if_errors();
}
@ -138,7 +137,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
.iter()
.filter(|&&(_, guard)| guard.is_none())
.flat_map(|arm| &arm.0)
.map(|pat| vec![wrap_pat(cx, &pat)])
.map(|pat| vec![lower_pat(cx, &pat)])
.collect();
check_exhaustive(cx, scrut.span, &matrix, source);
},
@ -218,7 +217,7 @@ fn check_arms(cx: &MatchCheckCtxt,
let mut printed_if_let_err = false;
for &(ref pats, guard) in arms {
for pat in pats {
let v = vec![wrap_pat(cx, &pat)];
let v = vec![lower_pat(cx, &pat)];
match is_useful(cx, &seen, &v[..], LeaveOutWitness) {
NotUseful => {
@ -292,7 +291,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
sp: Span,
matrix: &Matrix<'a, 'tcx>,
source: hir::MatchSource) {
match is_useful(cx, matrix, &[DUMMY_WILD_PATTERN], ConstructWitness) {
match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) {
UsefulWithWitness(pats) => {
let witnesses = if pats.is_empty() {
vec![DUMMY_WILD_PAT]
@ -483,7 +482,7 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) {
"local binding"
};
is_refutable(cx, pat, |uncovered_pat| {
is_refutable(cx, &lower_pat(cx, pat), |uncovered_pat| {
let pattern_string = pat_to_string(uncovered_pat.single_pattern());
struct_span_err!(cx.tcx.sess, pat.span, E0005,
"refutable pattern in {}: `{}` not covered",

View File

@ -31,6 +31,7 @@
#![feature(box_patterns)]
#![feature(box_syntax)]
extern crate arena;
#[macro_use] extern crate syntax;
#[macro_use] extern crate log;
#[macro_use] extern crate rustc;

View File

@ -11,7 +11,7 @@
use eval;
use rustc::middle::const_val::ConstVal;
use rustc::mir::repr::{Field, Literal, BorrowKind, Mutability};
use rustc::mir::repr::{Field, BorrowKind, Mutability};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::hir::{self, PatKind};
use rustc::hir::def::Def;
@ -78,8 +78,8 @@ pub enum PatternKind<'tcx> {
},
Range {
lo: Literal<'tcx>,
hi: Literal<'tcx>,
lo: ConstVal,
hi: ConstVal,
},
/// matches against a slice, checking the length and extracting elements
@ -111,9 +111,7 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
PatKind::Range(ref lo, ref hi) => {
let lo = eval::eval_const_expr(tcx.global_tcx(), lo);
let lo = Literal::Value { value: lo };
let hi = eval::eval_const_expr(tcx.global_tcx(), hi);
let hi = Literal::Value { value: hi };
PatternKind::Range { lo: lo, hi: hi }
},
@ -375,3 +373,167 @@ impl<'a, 'gcx, 'tcx> PatternKind<'tcx> {
}
}
}
pub trait PatternFoldable<'tcx> : Sized {
fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.super_fold_with(folder)
}
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
}
pub trait PatternFolder<'tcx> : Sized {
fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> {
pattern.super_fold_with(self)
}
fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> {
kind.super_fold_with(self)
}
}
impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
let content: T = (**self).fold_with(folder);
box content
}
}
impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.iter().map(|t| t.fold_with(folder)).collect()
}
}
impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self{
self.as_ref().map(|t| t.fold_with(folder))
}
}
macro_rules! CopyImpls {
($($ty:ty),+) => {
$(
impl<'tcx> PatternFoldable<'tcx> for $ty {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, _: &mut F) -> Self {
self.clone()
}
}
)+
}
}
macro_rules! TcxCopyImpls {
($($ty:ident),+) => {
$(
impl<'tcx> PatternFoldable<'tcx> for $ty<'tcx> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, _: &mut F) -> Self {
*self
}
}
)+
}
}
CopyImpls!{ Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal }
TcxCopyImpls!{ Ty, BindingMode, AdtDef }
impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
FieldPattern {
field: self.field.fold_with(folder),
pattern: self.pattern.fold_with(folder)
}
}
}
impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> {
fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
folder.fold_pattern(self)
}
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
Pattern {
ty: self.ty.fold_with(folder),
span: self.span.fold_with(folder),
kind: self.kind.fold_with(folder)
}
}
}
impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
folder.fold_pattern_kind(self)
}
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
match *self {
PatternKind::Wild => PatternKind::Wild,
PatternKind::Binding {
mutability,
name,
mode,
var,
ty,
ref subpattern,
} => PatternKind::Binding {
mutability: mutability.fold_with(folder),
name: name.fold_with(folder),
mode: mode.fold_with(folder),
var: var.fold_with(folder),
ty: ty.fold_with(folder),
subpattern: subpattern.fold_with(folder),
},
PatternKind::Variant {
adt_def,
variant_index,
ref subpatterns,
} => PatternKind::Variant {
adt_def: adt_def.fold_with(folder),
variant_index: variant_index.fold_with(folder),
subpatterns: subpatterns.fold_with(folder)
},
PatternKind::Leaf {
ref subpatterns,
} => PatternKind::Leaf {
subpatterns: subpatterns.fold_with(folder),
},
PatternKind::Deref {
ref subpattern,
} => PatternKind::Deref {
subpattern: subpattern.fold_with(folder),
},
PatternKind::Constant {
ref value
} => PatternKind::Constant {
value: value.fold_with(folder)
},
PatternKind::Range {
ref lo,
ref hi
} => PatternKind::Range {
lo: lo.fold_with(folder),
hi: hi.fold_with(folder)
},
PatternKind::Slice {
ref prefix,
ref slice,
ref suffix,
} => PatternKind::Slice {
prefix: prefix.fold_with(folder),
slice: slice.fold_with(folder),
suffix: suffix.fold_with(folder)
},
PatternKind::Array {
ref prefix,
ref slice,
ref suffix
} => PatternKind::Array {
prefix: prefix.fold_with(folder),
slice: slice.fold_with(folder),
suffix: suffix.fold_with(folder)
},
}
}
}

View File

@ -73,8 +73,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Test {
span: match_pair.pattern.span,
kind: TestKind::Range {
lo: lo.clone(),
hi: hi.clone(),
lo: Literal::Value { value: lo.clone() },
hi: Literal::Value { value: hi.clone() },
ty: match_pair.pattern.ty.clone(),
},
}

View File

@ -19,19 +19,19 @@ use Cake::*;
const BOO: (Cake, Cake) = (Marmor, BlackForest);
//~^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: enum variants
const FOO: Cake = BOO.1;
//~^^^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: enum variants
const FOO: Cake = BOO.1; //~ NOTE for expression here
const fn foo() -> Cake {
Marmor
//~^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: enum variants
//~^^^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: enum variants
}
const WORKS: Cake = Marmor;
const GOO: Cake = foo(); //~ NOTE for expression here
const GOO: Cake = foo();
fn main() {
match BlackForest {