change match checking to use HAIR
no intended functional changes
This commit is contained in:
parent
04a92a1f56
commit
e313d8b290
8 changed files with 386 additions and 263 deletions
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
|
@ -330,6 +330,7 @@ dependencies = [
|
||||||
name = "rustc_const_eval"
|
name = "rustc_const_eval"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arena 0.0.0",
|
||||||
"graphviz 0.0.0",
|
"graphviz 0.0.0",
|
||||||
"log 0.0.0",
|
"log 0.0.0",
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
|
|
|
@ -9,6 +9,7 @@ path = "lib.rs"
|
||||||
crate-type = ["dylib"]
|
crate-type = ["dylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
arena = { path = "../libarena" }
|
||||||
log = { path = "../liblog" }
|
log = { path = "../liblog" }
|
||||||
serialize = { path = "../libserialize" }
|
serialize = { path = "../libserialize" }
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
|
|
|
@ -13,20 +13,20 @@ use self::Usefulness::*;
|
||||||
use self::WitnessPreference::*;
|
use self::WitnessPreference::*;
|
||||||
|
|
||||||
use rustc::middle::const_val::ConstVal;
|
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::def_id::{DefId};
|
||||||
use rustc::hir::pat_util::def_to_path;
|
use rustc::hir::pat_util::def_to_path;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::fmt;
|
|
||||||
use std::iter::{FromIterator, IntoIterator, repeat};
|
|
||||||
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
use rustc::hir::def::CtorKind;
|
||||||
use rustc::hir::{Pat, PatKind};
|
use rustc::hir::{Pat, PatKind};
|
||||||
use rustc::hir::print::pat_to_string;
|
|
||||||
use rustc::util::common::ErrorReported;
|
use rustc::util::common::ErrorReported;
|
||||||
|
|
||||||
use syntax::ast::{self, DUMMY_NODE_ID};
|
use syntax::ast::{self, DUMMY_NODE_ID};
|
||||||
|
@ -34,53 +34,69 @@ use syntax::codemap::Spanned;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
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 {
|
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
|
||||||
id: DUMMY_NODE_ID,
|
id: DUMMY_NODE_ID,
|
||||||
node: PatKind::Wild,
|
node: PatKind::Wild,
|
||||||
span: DUMMY_SP
|
span: DUMMY_SP
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const DUMMY_WILD_PATTERN : Pattern<'static, 'static> = Pattern {
|
impl<'tcx> Pattern<'tcx> {
|
||||||
pat: DUMMY_WILD_PAT,
|
fn is_wildcard(&self) -> bool {
|
||||||
pattern_ty: None
|
match *self.kind {
|
||||||
};
|
PatternKind::Binding { subpattern: None, .. } | PatternKind::Wild =>
|
||||||
|
true,
|
||||||
#[derive(Copy, Clone)]
|
_ => false
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pat;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn span(self) -> Span {
|
|
||||||
self.pat.span
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> fmt::Debug for Pattern<'a, 'tcx> {
|
pub struct Matrix<'a, 'tcx: 'a>(Vec<Vec<&'a Pattern<'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>>>);
|
|
||||||
|
|
||||||
impl<'a, 'tcx> Matrix<'a, 'tcx> {
|
impl<'a, 'tcx> Matrix<'a, 'tcx> {
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Matrix(vec![])
|
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)
|
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> {
|
impl<'a, 'tcx> FromIterator<Vec<&'a Pattern<'tcx>>> for Matrix<'a, 'tcx> {
|
||||||
fn from_iter<T: IntoIterator<Item=Vec<Pattern<'a, 'tcx>>>>(iter: T) -> Self
|
fn from_iter<T: IntoIterator<Item=Vec<&'a Pattern<'tcx>>>>(iter: T) -> Self
|
||||||
{
|
{
|
||||||
Matrix(iter.into_iter().collect())
|
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 struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
||||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
pub param_env: ty::ParameterEnvironment<'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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -163,7 +207,11 @@ impl Constructor {
|
||||||
-> &'a ty::VariantDefData<'tcx, 'container> {
|
-> &'a ty::VariantDefData<'tcx, 'container> {
|
||||||
match self {
|
match self {
|
||||||
&Variant(vid) => adt.variant_with_id(vid),
|
&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()
|
matrix.0.iter()
|
||||||
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
|
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
|
||||||
.collect();
|
.collect();
|
||||||
|
debug!("used_constructors = {:?}", used_constructors);
|
||||||
all_constructors(cx, pcx).into_iter()
|
all_constructors(cx, pcx).into_iter()
|
||||||
.filter(|c| !used_constructors.contains(c))
|
.filter(|c| !used_constructors.contains(c))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -335,28 +384,28 @@ fn all_constructors(_cx: &MatchCheckCtxt, pcx: PatternContext) -> Vec<Constructo
|
||||||
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
||||||
ty::TySlice(_) =>
|
ty::TySlice(_) =>
|
||||||
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect(),
|
(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(),
|
def.variants.iter().map(|v| Variant(v.did)).collect(),
|
||||||
_ => vec![Single]
|
_ => vec![Single]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
|
/// 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
|
/// 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`
|
/// vectors `m` is defined as there being a set of inputs that will match `v`
|
||||||
// but not any of the sets in `m`.
|
/// but not any of the sets in `m`.
|
||||||
//
|
///
|
||||||
// This is used both for reachability checking (if a pattern isn't useful in
|
/// This is used both for reachability checking (if a pattern isn't useful in
|
||||||
// relation to preceding patterns, it is not reachable) and exhaustiveness
|
/// relation to preceding patterns, it is not reachable) and exhaustiveness
|
||||||
// checking (if a wildcard pattern is useful in relation to a matrix, the
|
/// checking (if a wildcard pattern is useful in relation to a matrix, the
|
||||||
// matrix isn't exhaustive).
|
/// matrix isn't exhaustive).
|
||||||
|
///
|
||||||
// Note: is_useful doesn't work on empty types, as the paper notes.
|
/// Note: is_useful doesn't work on empty types, as the paper notes.
|
||||||
// So it assumes that v is non-empty.
|
/// So it assumes that v is non-empty.
|
||||||
pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
matrix: &Matrix<'a, 'tcx>,
|
matrix: &Matrix<'a, 'tcx>,
|
||||||
v: &[Pattern<'a, 'tcx>],
|
v: &[&'a Pattern<'tcx>],
|
||||||
witness: WitnessPreference)
|
witness: WitnessPreference)
|
||||||
-> Usefulness {
|
-> Usefulness {
|
||||||
let &Matrix(ref rows) = matrix;
|
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()));
|
assert!(rows.iter().all(|r| r.len() == v.len()));
|
||||||
|
|
||||||
let pcx = PatternContext {
|
let pcx = PatternContext {
|
||||||
ty: match rows.iter().filter_map(|r| r[0].pattern_ty).next()
|
ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
|
||||||
.or_else(|| v[0].pattern_ty)
|
.unwrap_or(v[0].ty),
|
||||||
{
|
max_slice_length: rows.iter().filter_map(|row| match *row[0].kind {
|
||||||
Some(ty) => ty,
|
PatternKind::Slice { ref prefix, slice: _, ref suffix } =>
|
||||||
None => {
|
Some(prefix.len() + suffix.len()),
|
||||||
// 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()),
|
|
||||||
_ => None
|
_ => None
|
||||||
}).max().map_or(0, |v| v + 1)
|
}).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)
|
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
|
||||||
} else {
|
} else {
|
||||||
let matrix = rows.iter().filter_map(|r| {
|
let matrix = rows.iter().filter_map(|r| {
|
||||||
match r[0].as_raw().node {
|
if r[0].is_wildcard() {
|
||||||
PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()),
|
Some(r[1..].to_vec())
|
||||||
_ => None,
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
match is_useful(cx, &matrix, &v[1..], witness) {
|
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>(
|
fn is_useful_specialized<'a, 'tcx>(
|
||||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
&Matrix(ref m): &Matrix<'a, 'tcx>,
|
&Matrix(ref m): &Matrix<'a, 'tcx>,
|
||||||
v: &[Pattern<'a, 'tcx>],
|
v: &[&'a Pattern<'tcx>],
|
||||||
ctor: Constructor,
|
ctor: Constructor,
|
||||||
lty: Ty<'tcx>,
|
lty: Ty<'tcx>,
|
||||||
witness: WitnessPreference) -> Usefulness
|
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.
|
/// `[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.
|
/// Returns None in case of a catch-all, which can't be specialized.
|
||||||
fn pat_constructors(cx: &MatchCheckCtxt,
|
fn pat_constructors(_cx: &MatchCheckCtxt,
|
||||||
p: Pattern,
|
pat: &Pattern,
|
||||||
pcx: PatternContext)
|
pcx: PatternContext)
|
||||||
-> Option<Vec<Constructor>>
|
-> Option<Vec<Constructor>>
|
||||||
{
|
{
|
||||||
let pat = p.as_raw();
|
match *pat.kind {
|
||||||
match pat.node {
|
PatternKind::Binding { .. } | PatternKind::Wild =>
|
||||||
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 =>
|
|
||||||
None,
|
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)
|
Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
|
fn patterns_for_variant<'a, 'tcx>(
|
||||||
pat: &'a Pat)
|
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
-> Pattern<'a, 'tcx>
|
subpatterns: &'a [FieldPattern<'tcx>],
|
||||||
|
arity: usize)
|
||||||
|
-> Vec<&'a Pattern<'tcx>>
|
||||||
{
|
{
|
||||||
let pat_ty = cx.tcx.pat_ty(pat);
|
let mut result = vec![cx.wild_pattern; arity];
|
||||||
Pattern {
|
|
||||||
pat: pat,
|
for subpat in subpatterns {
|
||||||
pattern_ty: Some(match pat.node {
|
result[subpat.field.index()] = &subpat.pattern;
|
||||||
PatKind::Binding(hir::BindByRef(..), ..) => {
|
|
||||||
pat_ty.builtin_deref(false, ty::NoPreference).unwrap().ty
|
|
||||||
}
|
|
||||||
_ => pat_ty
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, arity, result);
|
||||||
|
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 first pattern in the given row
|
||||||
|
@ -564,118 +596,34 @@ pub fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
|
||||||
/// different patterns.
|
/// different patterns.
|
||||||
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
||||||
/// fields filled with wild patterns.
|
/// fields filled with wild patterns.
|
||||||
fn specialize<'a, 'b, 'tcx>(
|
fn specialize<'a, 'tcx>(
|
||||||
cx: &MatchCheckCtxt<'b, 'tcx>,
|
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
r: &[Pattern<'a, 'tcx>],
|
r: &[&'a Pattern<'tcx>],
|
||||||
constructor: &Constructor, col: usize, arity: usize)
|
constructor: &Constructor, col: usize, arity: usize)
|
||||||
-> Option<Vec<Pattern<'a, 'tcx>>>
|
-> Option<Vec<&'a Pattern<'tcx>>>
|
||||||
{
|
{
|
||||||
let pat = r[col].as_raw();
|
let pat = &r[col];
|
||||||
let &Pat {
|
|
||||||
id: pat_id, ref node, span: pat_span
|
|
||||||
} = pat;
|
|
||||||
let wpat = |pat: &'a Pat| wrap_pat(cx, pat);
|
|
||||||
|
|
||||||
let head: Option<Vec<Pattern>> = match *node {
|
let head: Option<Vec<&Pattern>> = match *pat.kind {
|
||||||
PatKind::Binding(..) | PatKind::Wild =>
|
PatternKind::Binding { .. } | PatternKind::Wild =>
|
||||||
Some(vec![DUMMY_WILD_PATTERN; arity]),
|
Some(vec![cx.wild_pattern; arity]),
|
||||||
|
|
||||||
PatKind::Path(..) => {
|
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
|
||||||
match cx.tcx.expect_def(pat_id) {
|
let ref variant = adt_def.variants[variant_index];
|
||||||
Def::Const(..) | Def::AssociatedConst(..) =>
|
if *constructor == Variant(variant.did) {
|
||||||
span_bug!(pat_span, "const pattern should've \
|
Some(patterns_for_variant(cx, subpatterns, arity))
|
||||||
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())
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Tuple(ref args, Some(ddpos)) => {
|
PatternKind::Leaf { ref subpatterns } => Some(patterns_for_variant(cx, subpatterns, arity)),
|
||||||
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| wpat(p)).collect();
|
PatternKind::Deref { ref subpattern } => Some(vec![subpattern]),
|
||||||
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()),
|
|
||||||
|
|
||||||
PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) =>
|
PatternKind::Constant { ref value } => {
|
||||||
Some(vec![wpat(&**inner)]),
|
assert_eq!(constructor_arity(cx, constructor, pat.ty), 0);
|
||||||
|
|
||||||
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);
|
|
||||||
match range_covered_by_constructor(
|
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(true) => Some(vec![]),
|
||||||
Ok(false) => None,
|
Ok(false) => None,
|
||||||
|
@ -683,31 +631,39 @@ fn specialize<'a, 'b, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
PatternKind::Range { ref lo, ref hi } => {
|
||||||
let pat_len = before.len() + after.len();
|
match range_covered_by_constructor(
|
||||||
match *constructor {
|
cx.tcx, pat.span, constructor, lo, hi
|
||||||
Single => {
|
) {
|
||||||
// Fixed-length vectors.
|
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(
|
Some(
|
||||||
before.iter().map(|p| wpat(p)).chain(
|
prefix.iter().chain(
|
||||||
repeat(DUMMY_WILD_PATTERN).take(arity - pat_len).chain(
|
repeat(cx.wild_pattern).take(slice_count).chain(
|
||||||
after.iter().map(|p| wpat(p))
|
suffix.iter()
|
||||||
)).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))
|
|
||||||
)).collect())
|
)).collect())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
Slice(length) if pat_len == length => {
|
} else {
|
||||||
Some(
|
None
|
||||||
before.iter().map(|p| wpat(p)).chain(
|
|
||||||
after.iter().map(|p| wpat(p))
|
|
||||||
).collect())
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -720,12 +676,15 @@ fn specialize<'a, 'b, 'tcx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F)
|
pub fn is_refutable<'a, 'tcx, A, F>(
|
||||||
-> Option<A> where
|
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
|
pat: &'a Pattern<'tcx>,
|
||||||
|
refutable: F)
|
||||||
|
-> Option<A> where
|
||||||
F: FnOnce(&Witness) -> A,
|
F: FnOnce(&Witness) -> A,
|
||||||
{
|
{
|
||||||
let pats = Matrix(vec!(vec!(wrap_pat(cx, pat))));
|
let pats = Matrix(vec![vec![pat]]);
|
||||||
match is_useful(cx, &pats, &[DUMMY_WILD_PATTERN], ConstructWitness) {
|
match is_useful(cx, &pats, &[cx.wild_pattern], ConstructWitness) {
|
||||||
UsefulWithWitness(pats) => Some(refutable(&pats[0])),
|
UsefulWithWitness(pats) => Some(refutable(&pats[0])),
|
||||||
NotUseful => None,
|
NotUseful => None,
|
||||||
Useful => bug!()
|
Useful => bug!()
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use _match::{MatchCheckCtxt, Matrix, wrap_pat, is_refutable, is_useful};
|
use _match::{MatchCheckCtxt, Matrix, lower_pat, is_refutable, is_useful};
|
||||||
use _match::{DUMMY_WILD_PATTERN, DUMMY_WILD_PAT};
|
use _match::{DUMMY_WILD_PAT};
|
||||||
use _match::Usefulness::*;
|
use _match::Usefulness::*;
|
||||||
use _match::WitnessPreference::*;
|
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>) {
|
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut MatchCheckCtxt {
|
MatchCheckCtxt::create_and_enter(tcx, tcx.empty_parameter_environment(), |mut cx| {
|
||||||
tcx: tcx,
|
tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut cx);
|
||||||
param_env: tcx.empty_parameter_environment(),
|
|
||||||
});
|
});
|
||||||
tcx.sess.abort_if_errors();
|
tcx.sess.abort_if_errors();
|
||||||
}
|
}
|
||||||
|
@ -138,7 +137,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&&(_, guard)| guard.is_none())
|
.filter(|&&(_, guard)| guard.is_none())
|
||||||
.flat_map(|arm| &arm.0)
|
.flat_map(|arm| &arm.0)
|
||||||
.map(|pat| vec![wrap_pat(cx, &pat)])
|
.map(|pat| vec![lower_pat(cx, &pat)])
|
||||||
.collect();
|
.collect();
|
||||||
check_exhaustive(cx, scrut.span, &matrix, source);
|
check_exhaustive(cx, scrut.span, &matrix, source);
|
||||||
},
|
},
|
||||||
|
@ -218,7 +217,7 @@ fn check_arms(cx: &MatchCheckCtxt,
|
||||||
let mut printed_if_let_err = false;
|
let mut printed_if_let_err = false;
|
||||||
for &(ref pats, guard) in arms {
|
for &(ref pats, guard) in arms {
|
||||||
for pat in pats {
|
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) {
|
match is_useful(cx, &seen, &v[..], LeaveOutWitness) {
|
||||||
NotUseful => {
|
NotUseful => {
|
||||||
|
@ -292,7 +291,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
matrix: &Matrix<'a, 'tcx>,
|
matrix: &Matrix<'a, 'tcx>,
|
||||||
source: hir::MatchSource) {
|
source: hir::MatchSource) {
|
||||||
match is_useful(cx, matrix, &[DUMMY_WILD_PATTERN], ConstructWitness) {
|
match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) {
|
||||||
UsefulWithWitness(pats) => {
|
UsefulWithWitness(pats) => {
|
||||||
let witnesses = if pats.is_empty() {
|
let witnesses = if pats.is_empty() {
|
||||||
vec![DUMMY_WILD_PAT]
|
vec![DUMMY_WILD_PAT]
|
||||||
|
@ -483,7 +482,7 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) {
|
||||||
"local binding"
|
"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());
|
let pattern_string = pat_to_string(uncovered_pat.single_pattern());
|
||||||
struct_span_err!(cx.tcx.sess, pat.span, E0005,
|
struct_span_err!(cx.tcx.sess, pat.span, E0005,
|
||||||
"refutable pattern in {}: `{}` not covered",
|
"refutable pattern in {}: `{}` not covered",
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
|
||||||
|
extern crate arena;
|
||||||
#[macro_use] extern crate syntax;
|
#[macro_use] extern crate syntax;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate rustc;
|
#[macro_use] extern crate rustc;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use eval;
|
use eval;
|
||||||
|
|
||||||
use rustc::middle::const_val::ConstVal;
|
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::ty::{self, TyCtxt, AdtDef, Ty, Region};
|
||||||
use rustc::hir::{self, PatKind};
|
use rustc::hir::{self, PatKind};
|
||||||
use rustc::hir::def::Def;
|
use rustc::hir::def::Def;
|
||||||
|
@ -78,8 +78,8 @@ pub enum PatternKind<'tcx> {
|
||||||
},
|
},
|
||||||
|
|
||||||
Range {
|
Range {
|
||||||
lo: Literal<'tcx>,
|
lo: ConstVal,
|
||||||
hi: Literal<'tcx>,
|
hi: ConstVal,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// matches against a slice, checking the length and extracting elements
|
/// 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) => {
|
PatKind::Range(ref lo, ref hi) => {
|
||||||
let lo = eval::eval_const_expr(tcx.global_tcx(), lo);
|
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 = eval::eval_const_expr(tcx.global_tcx(), hi);
|
||||||
let hi = Literal::Value { value: hi };
|
|
||||||
PatternKind::Range { lo: lo, hi: 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)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -73,8 +73,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
Test {
|
Test {
|
||||||
span: match_pair.pattern.span,
|
span: match_pair.pattern.span,
|
||||||
kind: TestKind::Range {
|
kind: TestKind::Range {
|
||||||
lo: lo.clone(),
|
lo: Literal::Value { value: lo.clone() },
|
||||||
hi: hi.clone(),
|
hi: Literal::Value { value: hi.clone() },
|
||||||
ty: match_pair.pattern.ty.clone(),
|
ty: match_pair.pattern.ty.clone(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,19 +19,19 @@ use Cake::*;
|
||||||
const BOO: (Cake, Cake) = (Marmor, BlackForest);
|
const BOO: (Cake, Cake) = (Marmor, BlackForest);
|
||||||
//~^ ERROR: constant evaluation error [E0080]
|
//~^ ERROR: constant evaluation error [E0080]
|
||||||
//~| unimplemented constant expression: enum variants
|
//~| 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 {
|
const fn foo() -> Cake {
|
||||||
Marmor
|
Marmor
|
||||||
//~^ ERROR: constant evaluation error [E0080]
|
//~^ ERROR: constant evaluation error [E0080]
|
||||||
//~| unimplemented constant expression: enum variants
|
//~| unimplemented constant expression: enum variants
|
||||||
//~^^^ ERROR: constant evaluation error [E0080]
|
|
||||||
//~| unimplemented constant expression: enum variants
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const WORKS: Cake = Marmor;
|
const WORKS: Cake = Marmor;
|
||||||
|
|
||||||
const GOO: Cake = foo(); //~ NOTE for expression here
|
const GOO: Cake = foo();
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match BlackForest {
|
match BlackForest {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue