diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index ebe1034901104..6d04975f533da 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -23,18 +23,12 @@ use rustc_data_structures::indexed_vec::Idx; use pattern::{FieldPattern, Pattern, PatternKind}; use pattern::{PatternFoldable, PatternFolder}; -use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::hir; -use rustc::hir::def::CtorKind; -use rustc::hir::{Pat, PatKind}; +use rustc::mir::Field; use rustc::util::common::ErrorReported; -use syntax::ast::{self, DUMMY_NODE_ID}; -use syntax::codemap::Spanned; -use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; use arena::TypedArena; @@ -74,12 +68,6 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander { } } -pub const DUMMY_WILD_PAT: &'static Pat = &Pat { - id: DUMMY_NODE_ID, - node: PatKind::Wild, - span: DUMMY_SP -}; - impl<'tcx> Pattern<'tcx> { fn is_wildcard(&self) -> bool { match *self.kind { @@ -224,25 +212,34 @@ pub enum Constructor { } impl<'tcx> Constructor { - fn variant_for_adt(&self, adt: &'tcx ty::AdtDef) -> &'tcx ty::VariantDef { + fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize { match self { - &Variant(vid) => adt.variant_with_id(vid), + &Variant(vid) => adt.variant_index_with_id(vid), &Single => { assert_eq!(adt.variants.len(), 1); - &adt.variants[0] + 0 } _ => bug!("bad constructor {:?} for adt {:?}", self, adt) } } } -#[derive(Clone, PartialEq)] -pub enum Usefulness { +#[derive(Clone)] +pub enum Usefulness<'tcx> { Useful, - UsefulWithWitness(Vec), + UsefulWithWitness(Vec>), NotUseful } +impl<'tcx> Usefulness<'tcx> { + fn is_useful(&self) -> bool { + match *self { + NotUseful => false, + _ => true + } + } +} + #[derive(Copy, Clone)] pub enum WitnessPreference { ConstructWitness, @@ -255,31 +252,17 @@ struct PatternContext<'tcx> { max_slice_length: usize, } - -fn const_val_to_expr(value: &ConstVal) -> P { - let node = match value { - &ConstVal::Bool(b) => ast::LitKind::Bool(b), - _ => bug!() - }; - P(hir::Expr { - id: DUMMY_NODE_ID, - node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })), - span: DUMMY_SP, - attrs: ast::ThinVec::new(), - }) -} - /// A stack of patterns in reverse order of construction -#[derive(Clone, PartialEq, Eq)] -pub struct Witness(Vec>); +#[derive(Clone)] +pub struct Witness<'tcx>(Vec>); -impl Witness { - pub fn single_pattern(&self) -> &Pat { +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, 'tcx>( + fn push_wild_constructor<'a>( mut self, cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor, @@ -287,7 +270,7 @@ impl Witness { -> Self { let arity = constructor_arity(cx, ctor, ty); - self.0.extend(repeat(DUMMY_WILD_PAT).take(arity).map(|p| P(p.clone()))); + self.0.extend(repeat(cx.wild_pattern).take(arity).cloned()); self.apply_constructor(cx, ctor, ty) } @@ -305,7 +288,7 @@ impl Witness { /// /// left_ty: struct X { a: (bool, &'static str), b: usize} /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor<'a, 'tcx>( + fn apply_constructor<'a>( mut self, cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, @@ -318,60 +301,56 @@ impl Witness { let mut pats = self.0.drain(len-arity..).rev(); match ty.sty { - ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), - - ty::TyAdt(adt, _) => { - let v = ctor.variant_for_adt(adt); - let qpath = hir::QPath::Resolved(None, P(hir::Path { - span: DUMMY_SP, - def: Def::Err, - segments: vec![hir::PathSegment::from_name(v.name)].into(), - })); - match v.ctor_kind { - CtorKind::Fictive => { - let field_pats: hir::HirVec<_> = v.fields.iter() - .zip(pats) - .filter(|&(_, ref pat)| pat.node != PatKind::Wild) - .map(|(field, pat)| Spanned { - span: DUMMY_SP, - node: hir::FieldPat { - name: field.name, - pat: pat, - is_shorthand: false, - } - }).collect(); - let has_more_fields = field_pats.len() < arity; - PatKind::Struct(qpath, field_pats, has_more_fields) + ty::TyAdt(..) | + ty::TyTuple(..) => { + let pats = pats.enumerate().map(|(i, p)| { + FieldPattern { + field: Field::new(i), + pattern: p } - CtorKind::Fn => { - PatKind::TupleStruct(qpath, pats.collect(), None) + }).collect(); + + if let ty::TyAdt(adt, _) = ty.sty { + if adt.variants.len() > 1 { + PatternKind::Variant { + adt_def: adt, + variant_index: ctor.variant_index_for_adt(adt), + subpatterns: pats + } + } else { + PatternKind::Leaf { subpatterns: pats } } - CtorKind::Const => PatKind::Path(qpath) + } else { + PatternKind::Leaf { subpatterns: pats } } } - ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => { - PatKind::Ref(pats.nth(0).unwrap(), mutbl) + ty::TyRef(..) => { + PatternKind::Deref { subpattern: pats.nth(0).unwrap() } } ty::TySlice(_) | ty::TyArray(..) => { - PatKind::Slice(pats.collect(), None, hir::HirVec::new()) + PatternKind::Slice { + prefix: pats.collect(), + slice: None, + suffix: vec![] + } } _ => { match *ctor { - ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)), - _ => PatKind::Wild, + ConstantValue(ref v) => PatternKind::Constant { value: v.clone() }, + _ => PatternKind::Wild, } } } }; - self.0.push(P(hir::Pat { - id: DUMMY_NODE_ID, - node: pat, - span: DUMMY_SP - })); + self.0.push(Pattern { + ty: ty, + span: DUMMY_SP, + kind: Box::new(pat), + }); self } @@ -528,13 +507,13 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, matrix: &Matrix<'a, 'tcx>, v: &[&'a Pattern<'tcx>], witness: WitnessPreference) - -> Usefulness { + -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; debug!("is_useful({:?}, {:?})", matrix, v); if rows.is_empty() { return match witness { ConstructWitness => UsefulWithWitness(vec![Witness( - repeat(DUMMY_WILD_PAT).take(v.len()).map(|p| P(p.clone())).collect() + repeat(cx.wild_pattern).take(v.len()).cloned().collect() )]), LeaveOutWitness => Useful }; @@ -559,7 +538,7 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, 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 != &NotUseful).unwrap_or(NotUseful) + ).find(|result| result.is_useful()).unwrap_or(NotUseful) } else { debug!("is_useful - expanding wildcard"); let constructors = missing_constructors(cx, matrix, pcx); @@ -567,7 +546,7 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, if constructors.is_empty() { all_constructors(cx, pcx).into_iter().map(|c| { is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) - }).find(|result| result != &NotUseful).unwrap_or(NotUseful) + }).find(|result| result.is_useful()).unwrap_or(NotUseful) } else { let matrix = rows.iter().filter_map(|r| { if r[0].is_wildcard() { @@ -597,7 +576,7 @@ fn is_useful_specialized<'a, 'tcx>( v: &[&'a Pattern<'tcx>], ctor: Constructor, lty: Ty<'tcx>, - witness: WitnessPreference) -> Usefulness + witness: WitnessPreference) -> Usefulness<'tcx> { let arity = constructor_arity(cx, &ctor, lty); let matrix = Matrix(m.iter().flat_map(|r| { @@ -672,7 +651,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize }, ty::TyRef(..) => 1, ty::TyAdt(adt, _) => { - ctor.variant_for_adt(adt).fields.len() + adt.variants[ctor.variant_index_for_adt(adt)].fields.len() } _ => 0 } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 01b19e1f53979..1bb0667409acb 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -9,11 +9,10 @@ // except according to those terms. use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; -use _match::{DUMMY_WILD_PAT}; use _match::Usefulness::*; use _match::WitnessPreference::*; -use pattern::{Pattern, PatternContext, PatternError}; +use pattern::{Pattern, PatternContext, PatternError, PatternKind}; use eval::report_const_eval_err; @@ -230,9 +229,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { Useful => bug!() }; - let pattern_string = hir::print::to_string(&self.tcx.map, |s| { - s.print_pat(witness[0].single_pattern()) - }); + let pattern_string = witness[0].single_pattern().to_string(); let mut diag = struct_span_err!( self.tcx.sess, pat.span, E0005, "refutable pattern in {}: `{}` not covered", @@ -369,23 +366,21 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) { UsefulWithWitness(pats) => { let witnesses = if pats.is_empty() { - vec![DUMMY_WILD_PAT] + vec![cx.wild_pattern] } else { pats.iter().map(|w| w.single_pattern()).collect() }; match source { hir::MatchSource::ForLoopDesugar => { // `witnesses[0]` has the form `Some()`, peel off the `Some` - let witness = match witnesses[0].node { - PatKind::TupleStruct(_, ref pats, _) => match &pats[..] { - &[ref pat] => &**pat, + let witness = match *witnesses[0].kind { + PatternKind::Variant { ref subpatterns, .. } => match &subpatterns[..] { + &[ref pat] => &pat.pattern, _ => bug!(), }, _ => bug!(), }; - let pattern_string = hir::print::to_string(&cx.tcx.map, |s| { - s.print_pat(witness) - }); + let pattern_string = witness.to_string(); struct_span_err!(cx.tcx.sess, sp, E0297, "refutable pattern in `for` loop binding: \ `{}` not covered", @@ -394,24 +389,23 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, .emit(); }, _ => { - let pattern_strings: Vec<_> = witnesses.iter().map(|w| { - hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w)) - }).collect(); const LIMIT: usize = 3; - let joined_patterns = match pattern_strings.len() { + let joined_patterns = match witnesses.len() { 0 => bug!(), - 1 => format!("`{}`", pattern_strings[0]), + 1 => format!("`{}`", witnesses[0]), 2...LIMIT => { - let (tail, head) = pattern_strings.split_last().unwrap(); - format!("`{}`", head.join("`, `") + "` and `" + tail) + let (tail, head) = witnesses.split_last().unwrap(); + let head: Vec<_> = head.iter().map(|w| w.to_string()).collect(); + format!("`{}` and `{}`", head.join("`, `"), tail) }, _ => { - let (head, tail) = pattern_strings.split_at(LIMIT); + let (head, tail) = witnesses.split_at(LIMIT); + let head: Vec<_> = head.iter().map(|w| w.to_string()).collect(); format!("`{}` and {} more", head.join("`, `"), tail.len()) } }; - let label_text = match pattern_strings.len(){ + let label_text = match witnesses.len() { 1 => format!("pattern {} not covered", joined_patterns), _ => format!("patterns {} not covered", joined_patterns) }; diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index e93178c89c22b..03baebd7901c5 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -14,12 +14,13 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::hir::{self, PatKind}; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc_data_structures::indexed_vec::Idx; +use std::fmt; use syntax::ast; use syntax::ptr::P; use syntax_pos::Span; @@ -105,6 +106,158 @@ pub enum PatternKind<'tcx> { }, } +fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { + match *value { + ConstVal::Float(ref x) => write!(f, "{}", x), + ConstVal::Integral(ref i) => write!(f, "{}", i), + ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]), + ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]), + ConstVal::Bool(b) => write!(f, "{:?}", b), + ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Struct(_) | + ConstVal::Tuple(_) | + ConstVal::Function(_) | + ConstVal::Array(..) | + ConstVal::Repeat(..) | + ConstVal::Dummy => bug!("{:?} not printable in a pattern", value) + } +} + +impl<'tcx> fmt::Display for Pattern<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self.kind { + PatternKind::Wild => write!(f, "_"), + PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => { + let is_mut = match mode { + BindingMode::ByValue => mutability == Mutability::Mut, + BindingMode::ByRef(_, bk) => { + write!(f, "ref ")?; + bk == BorrowKind::Mut + } + }; + if is_mut { + write!(f, "mut ")?; + } + write!(f, "{}", name)?; + if let Some(ref subpattern) = *subpattern { + write!(f, " @ {}", subpattern)?; + } + Ok(()) + } + PatternKind::Variant { ref subpatterns, .. } | + PatternKind::Leaf { ref subpatterns } => { + let variant = match *self.kind { + PatternKind::Variant { adt_def, variant_index, .. } => { + Some(&adt_def.variants[variant_index]) + } + _ => if let ty::TyAdt(adt, _) = self.ty.sty { + Some(adt.struct_variant()) + } else { + None + } + }; + + let mut first = true; + let mut start_or_continue = || if first { first = false; "" } else { ", " }; + + if let Some(variant) = variant { + write!(f, "{}", variant.name)?; + + // Only for TyAdt we can have `S {...}`, + // which we handle separately here. + if variant.ctor_kind == CtorKind::Fictive { + write!(f, " {{ ")?; + + let mut printed = 0; + for p in subpatterns { + if let PatternKind::Wild = *p.pattern.kind { + continue; + } + let name = variant.fields[p.field.index()].name; + write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?; + printed += 1; + } + + if printed < variant.fields.len() { + write!(f, "{}..", start_or_continue())?; + } + + return write!(f, " }}"); + } + } + + let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len()); + if num_fields != 0 || variant.is_none() { + write!(f, "(")?; + for i in 0..num_fields { + write!(f, "{}", start_or_continue())?; + + // Common case: the field is where we expect it. + if let Some(p) = subpatterns.get(i) { + if p.field.index() == i { + write!(f, "{}", p.pattern)?; + continue; + } + } + + // Otherwise, we have to go looking for it. + if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { + write!(f, "{}", p.pattern)?; + } else { + write!(f, "_")?; + } + } + write!(f, ")")?; + } + + Ok(()) + } + PatternKind::Deref { ref subpattern } => { + match self.ty.sty { + ty::TyBox(_) => write!(f, "box ")?, + ty::TyRef(_, mt) => { + write!(f, "&")?; + if mt.mutbl == hir::MutMutable { + write!(f, "mut ")?; + } + } + _ => bug!("{} is a bad Deref pattern type", self.ty) + } + write!(f, "{}", subpattern) + } + PatternKind::Constant { ref value } => { + print_const_val(value, f) + } + PatternKind::Range { ref lo, ref hi } => { + print_const_val(lo, f)?; + write!(f, "...")?; + print_const_val(hi, f) + } + PatternKind::Slice { ref prefix, ref slice, ref suffix } | + PatternKind::Array { ref prefix, ref slice, ref suffix } => { + let mut first = true; + let mut start_or_continue = || if first { first = false; "" } else { ", " }; + write!(f, "[")?; + for p in prefix { + write!(f, "{}{}", start_or_continue(), p)?; + } + if let Some(ref slice) = *slice { + write!(f, "{}", start_or_continue())?; + match *slice.kind { + PatternKind::Wild => {} + _ => write!(f, "{}", slice)? + } + write!(f, "..")?; + } + for p in suffix { + write!(f, "{}{}", start_or_continue(), p)?; + } + write!(f, "]") + } + } + } +} + pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, pub errors: Vec,