diff options
| -rw-r--r-- | src/librustc_const_eval/check_match.rs | 7 | ||||
| -rw-r--r-- | src/librustc_const_eval/eval.rs | 130 | ||||
| -rw-r--r-- | src/librustc_const_eval/pattern.rs | 231 |
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 { |
