about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-01-01 20:57:21 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-01-01 20:57:21 +0200
commitc001b0940c1597f422f41c308a55cc6e22f48e46 (patch)
tree8318a2e3b7af43f843e982218071eda7a3f49938
parente227433dc39ab13aa2368814169c049b8f876825 (diff)
rustc_const_eval: build Pattern instead of hir::Pat for pretty-printing.
-rw-r--r--src/librustc_const_eval/_match.rs145
-rw-r--r--src/librustc_const_eval/check_match.rs36
-rw-r--r--src/librustc_const_eval/pattern.rs155
3 files changed, 231 insertions, 105 deletions
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index ebe10349011..6d04975f533 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<Witness>),
+    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,
@@ -255,31 +252,17 @@ struct PatternContext<'tcx> {
     max_slice_length: usize,
 }
 
-
-fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
-    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<P<Pat>>);
+#[derive(Clone)]
+pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
 
-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 01b19e1f539..1bb0667409a 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(<head>)`, 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 e93178c89c2..03baebd7901 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<PatternError>,