mirror of
https://github.com/rust-lang/rust
synced 2024-10-06 08:40:35 +00:00
rustc_const_eval: convert constants to Pattern instead of hir::Pat.
This commit is contained in:
parent
c001b0940c
commit
c6e130e89b
|
@ -116,13 +116,6 @@ fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
|
|||
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");
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
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::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,
|
||||
|
|
|
@ -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 @@
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum PatternError {
|
||||
StaticInPattern(Span),
|
||||
BadConstInPattern(Span, DefId),
|
||||
ConstEval(eval::ConstEvalErr),
|
||||
}
|
||||
|
||||
|
@ -286,64 +285,20 @@ pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'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 @@ fn lower_variant_or_leaf(
|
|||
_ => 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 {
|
||||
|
|
Loading…
Reference in a new issue