about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_const_eval/check_match.rs7
-rw-r--r--src/librustc_const_eval/eval.rs130
-rw-r--r--src/librustc_const_eval/pattern.rs231
3 files changed, 180 insertions, 188 deletions
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 1bb0667409a..53e83815b46 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -116,13 +116,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
     fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) {
         for error in patcx.errors {
             match error {
-                PatternError::BadConstInPattern(span, def_id) => {
-                    self.tcx.sess.span_err(
-                        span,
-                        &format!("constants of the type `{}` \
-                                  cannot be used in patterns",
-                                 self.tcx.item_path_str(def_id)));
-                }
                 PatternError::StaticInPattern(span) => {
                     span_err!(self.tcx.sess, span, E0158,
                               "statics cannot be referenced in patterns");
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c736b4865e7..6b8e0e34c1d 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -18,7 +18,7 @@ use self::EvalHint::*;
 use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits;
-use rustc::hir::def::{Def, CtorKind};
+use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
@@ -26,16 +26,12 @@ use rustc::ty::subst::Substs;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::DefIdMap;
-use rustc::lint;
 
 use graphviz::IntoCow;
 use syntax::ast;
-use rustc::hir::{Expr, PatKind};
-use rustc::hir;
-use syntax::ptr::P;
-use syntax::codemap;
+use rustc::hir::{self, Expr};
 use syntax::attr::IntType;
-use syntax_pos::{self, Span};
+use syntax_pos::Span;
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
@@ -186,126 +182,6 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 }
 
-pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   expr: &Expr,
-                                   pat_id: ast::NodeId,
-                                   span: Span)
-                                   -> Result<P<hir::Pat>, DefId> {
-    let pat_ty = tcx.tables().expr_ty(expr);
-    debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
-    match pat_ty.sty {
-        ty::TyFloat(_) => {
-            tcx.sess.add_lint(
-                lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
-                pat_id,
-                span,
-                format!("floating point constants cannot be used in patterns"));
-        }
-        ty::TyAdt(adt_def, _) if adt_def.is_union() => {
-            // Matching on union fields is unsafe, we can't hide it in constants
-            tcx.sess.span_err(span, "cannot use unions in constant patterns");
-        }
-        ty::TyAdt(adt_def, _) => {
-            if !tcx.has_attr(adt_def.did, "structural_match") {
-                tcx.sess.add_lint(
-                    lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
-                    pat_id,
-                    span,
-                    format!("to use a constant of type `{}` \
-                             in a pattern, \
-                             `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                            tcx.item_path_str(adt_def.did),
-                            tcx.item_path_str(adt_def.did)));
-            }
-        }
-        _ => { }
-    }
-    let pat = match expr.node {
-        hir::ExprTup(ref exprs) =>
-            PatKind::Tuple(exprs.iter()
-                                .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
-                                .collect::<Result<_, _>>()?, None),
-
-        hir::ExprCall(ref callee, ref args) => {
-            let qpath = match callee.node {
-                hir::ExprPath(ref qpath) => qpath,
-                _ => bug!()
-            };
-            let def = tcx.tables().qpath_def(qpath, callee.id);
-            let ctor_path = if let hir::QPath::Resolved(_, ref path) = *qpath {
-                match def {
-                    Def::StructCtor(_, CtorKind::Fn) |
-                    Def::VariantCtor(_, CtorKind::Fn) => {
-                        Some(path.clone())
-                    }
-                    _ => None
-                }
-            } else {
-                None
-            };
-            match (def, ctor_path) {
-                (Def::Fn(..), None) | (Def::Method(..), None) => {
-                    PatKind::Lit(P(expr.clone()))
-                }
-                (_, Some(ctor_path)) => {
-                    let pats = args.iter()
-                                   .map(|expr| const_expr_to_pat(tcx, expr, pat_id, span))
-                                   .collect::<Result<_, _>>()?;
-                    PatKind::TupleStruct(hir::QPath::Resolved(None, ctor_path), pats, None)
-                }
-                _ => bug!()
-            }
-        }
-
-        hir::ExprStruct(ref qpath, ref fields, None) => {
-            let field_pats =
-                fields.iter()
-                      .map(|field| Ok(codemap::Spanned {
-                          span: syntax_pos::DUMMY_SP,
-                          node: hir::FieldPat {
-                              name: field.name.node,
-                              pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?,
-                              is_shorthand: false,
-                          },
-                      }))
-                      .collect::<Result<_, _>>()?;
-            PatKind::Struct(qpath.clone(), field_pats, false)
-        }
-
-        hir::ExprArray(ref exprs) => {
-            let pats = exprs.iter()
-                            .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
-                            .collect::<Result<_, _>>()?;
-            PatKind::Slice(pats, None, hir::HirVec::new())
-        }
-
-        hir::ExprPath(ref qpath) => {
-            let def = tcx.tables().qpath_def(qpath, expr.id);
-            match def {
-                Def::StructCtor(_, CtorKind::Const) |
-                Def::VariantCtor(_, CtorKind::Const) => {
-                    match expr.node {
-                        hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
-                            PatKind::Path(hir::QPath::Resolved(None, path.clone()))
-                        }
-                        _ => bug!()
-                    }
-                }
-                Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                    let substs = Some(tcx.tables().node_id_item_substs(expr.id)
-                        .unwrap_or_else(|| tcx.intern_substs(&[])));
-                    let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
-                    return const_expr_to_pat(tcx, expr, pat_id, span);
-                },
-                _ => bug!(),
-            }
-        }
-
-        _ => PatKind::Lit(P(expr.clone()))
-    };
-    Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
-}
-
 pub fn report_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 03baebd7901..b122d97a702 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -10,12 +10,12 @@
 
 use eval;
 
+use rustc::lint;
 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, CtorKind};
-use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 
 use rustc_data_structures::indexed_vec::Idx;
@@ -28,7 +28,6 @@ use syntax_pos::Span;
 #[derive(Clone, Debug)]
 pub enum PatternError {
     StaticInPattern(Span),
-    BadConstInPattern(Span, DefId),
     ConstEval(eval::ConstEvalErr),
 }
 
@@ -286,64 +285,20 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
         let kind = match pat.node {
             PatKind::Wild => PatternKind::Wild,
 
-            PatKind::Lit(ref value) => {
-                match eval::eval_const_expr_checked(self.tcx.global_tcx(), value) {
-                    Ok(value) => {
-                        PatternKind::Constant { value: value }
-                    }
-                    Err(e) => {
-                        self.errors.push(PatternError::ConstEval(e));
-                        PatternKind::Wild
-                    }
-                }
-            }
+            PatKind::Lit(ref value) => self.lower_lit(value),
 
             PatKind::Range(ref lo, ref hi) => {
-                let r_lo = eval::eval_const_expr_checked(self.tcx.global_tcx(), lo);
-                if let Err(ref e_lo) = r_lo {
-                    self.errors.push(PatternError::ConstEval(e_lo.clone()));
-                }
-
-                let r_hi = eval::eval_const_expr_checked(self.tcx.global_tcx(), hi);
-                if let Err(ref e_hi) = r_hi {
-                    self.errors.push(PatternError::ConstEval(e_hi.clone()));
-                }
-
-                if let (Ok(lo), Ok(hi)) = (r_lo, r_hi) {
-                    PatternKind::Range { lo: lo, hi: hi }
-                } else {
-                    PatternKind::Wild
+                match (self.lower_lit(lo), self.lower_lit(hi)) {
+                    (PatternKind::Constant { value: lo },
+                     PatternKind::Constant { value: hi }) => {
+                        PatternKind::Range { lo: lo, hi: hi }
+                    }
+                    _ => PatternKind::Wild
                 }
             }
 
             PatKind::Path(ref qpath) => {
-                let def = self.tcx.tables().qpath_def(qpath, pat.id);
-                match def {
-                    Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                        let tcx = self.tcx.global_tcx();
-                        let substs = tcx.tables().node_id_item_substs(pat.id)
-                            .unwrap_or_else(|| tcx.intern_substs(&[]));
-                        match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
-                            Some((const_expr, _const_ty)) => {
-                                match eval::const_expr_to_pat(
-                                    tcx, const_expr, pat.id, pat.span)
-                                {
-                                    Ok(pat) => return self.lower_pattern(&pat),
-                                    Err(_) => {
-                                        self.errors.push(PatternError::BadConstInPattern(
-                                            pat.span, def_id));
-                                        PatternKind::Wild
-                                    }
-                                }
-                            }
-                            None => {
-                                self.errors.push(PatternError::StaticInPattern(pat.span));
-                                PatternKind::Wild
-                            }
-                        }
-                    }
-                    _ => self.lower_variant_or_leaf(def, vec![])
-                }
+                return self.lower_path(qpath, pat.id, pat.id, pat.span);
             }
 
             PatKind::Ref(ref subpattern, _) |
@@ -600,6 +555,174 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             _ => bug!()
         }
     }
+
+    fn lower_path(&mut self,
+                  qpath: &hir::QPath,
+                  id: ast::NodeId,
+                  pat_id: ast::NodeId,
+                  span: Span)
+                  -> Pattern<'tcx> {
+        let def = self.tcx.tables().qpath_def(qpath, id);
+        let kind = match def {
+            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
+                let tcx = self.tcx.global_tcx();
+                let substs = tcx.tables().node_id_item_substs(id)
+                    .unwrap_or_else(|| tcx.intern_substs(&[]));
+                match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
+                    Some((const_expr, _const_ty)) => {
+                        return self.lower_const_expr(const_expr, pat_id, span);
+                    }
+                    None => {
+                        self.errors.push(PatternError::StaticInPattern(span));
+                        PatternKind::Wild
+                    }
+                }
+            }
+            _ => self.lower_variant_or_leaf(def, vec![])
+        };
+
+        Pattern {
+            span: span,
+            ty: self.tcx.tables().node_id_to_type(id),
+            kind: Box::new(kind),
+        }
+    }
+
+    fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
+        match eval::eval_const_expr_checked(self.tcx.global_tcx(), expr) {
+            Ok(value) => {
+                PatternKind::Constant { value: value }
+            }
+            Err(e) => {
+                self.errors.push(PatternError::ConstEval(e));
+                PatternKind::Wild
+            }
+        }
+    }
+
+    fn lower_const_expr(&mut self,
+                        expr: &hir::Expr,
+                        pat_id: ast::NodeId,
+                        span: Span)
+                        -> Pattern<'tcx> {
+        let pat_ty = self.tcx.tables().expr_ty(expr);
+        debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
+        match pat_ty.sty {
+            ty::TyFloat(_) => {
+                self.tcx.sess.add_lint(
+                    lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
+                    pat_id,
+                    span,
+                    format!("floating point constants cannot be used in patterns"));
+            }
+            ty::TyAdt(adt_def, _) if adt_def.is_union() => {
+                // Matching on union fields is unsafe, we can't hide it in constants
+                self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
+            }
+            ty::TyAdt(adt_def, _) => {
+                if !self.tcx.has_attr(adt_def.did, "structural_match") {
+                    self.tcx.sess.add_lint(
+                        lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
+                        pat_id,
+                        span,
+                        format!("to use a constant of type `{}` \
+                                 in a pattern, \
+                                 `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                                self.tcx.item_path_str(adt_def.did),
+                                self.tcx.item_path_str(adt_def.did)));
+                }
+            }
+            _ => { }
+        }
+        let kind = match expr.node {
+            hir::ExprTup(ref exprs) => {
+                PatternKind::Leaf {
+                    subpatterns: exprs.iter().enumerate().map(|(i, expr)| {
+                        FieldPattern {
+                            field: Field::new(i),
+                            pattern: self.lower_const_expr(expr, pat_id, span)
+                        }
+                    }).collect()
+                }
+            }
+
+            hir::ExprCall(ref callee, ref args) => {
+                let qpath = match callee.node {
+                    hir::ExprPath(ref qpath) => qpath,
+                    _ => bug!()
+                };
+                let def = self.tcx.tables().qpath_def(qpath, callee.id);
+                match def {
+                    Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
+                    _ => {
+                        let subpatterns = args.iter().enumerate().map(|(i, expr)| {
+                            FieldPattern {
+                                field: Field::new(i),
+                                pattern: self.lower_const_expr(expr, pat_id, span)
+                            }
+                        }).collect();
+                        self.lower_variant_or_leaf(def, subpatterns)
+                    }
+                }
+            }
+
+            hir::ExprStruct(ref qpath, ref fields, None) => {
+                let def = self.tcx.tables().qpath_def(qpath, expr.id);
+                let pat_ty = self.tcx.tables().node_id_to_type(expr.id);
+                let adt_def = match pat_ty.sty {
+                    ty::TyAdt(adt_def, _) => adt_def,
+                    _ => {
+                        span_bug!(
+                            expr.span,
+                            "struct expr without ADT type");
+                    }
+                };
+                let variant_def = adt_def.variant_of_def(def);
+
+                let subpatterns =
+                    fields.iter()
+                          .map(|field| {
+                              let index = variant_def.index_of_field_named(field.name.node);
+                              let index = index.unwrap_or_else(|| {
+                                  span_bug!(
+                                      expr.span,
+                                      "no field with name {:?}",
+                                      field.name);
+                              });
+                              FieldPattern {
+                                  field: Field::new(index),
+                                  pattern: self.lower_const_expr(&field.expr, pat_id, span),
+                              }
+                          })
+                          .collect();
+
+                self.lower_variant_or_leaf(def, subpatterns)
+            }
+
+            hir::ExprArray(ref exprs) => {
+                let pats = exprs.iter()
+                                .map(|expr| self.lower_const_expr(expr, pat_id, span))
+                                .collect();
+                PatternKind::Array {
+                    prefix: pats,
+                    slice: None,
+                    suffix: vec![]
+                }
+            }
+
+            hir::ExprPath(ref qpath) => {
+                return self.lower_path(qpath, expr.id, pat_id, span);
+            }
+
+            _ => self.lower_lit(expr)
+        };
+
+        Pattern {
+            span: span,
+            ty: pat_ty,
+            kind: Box::new(kind),
+        }
+    }
 }
 
 pub trait PatternFoldable<'tcx> : Sized {