remove StaticInliner and NaN checking
NaN checking was a lint for a deprecated feature. It can go away.
This commit is contained in:
parent
37418b850f
commit
76fb7d90ec
@ -40,12 +40,10 @@ use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::iter::{FromIterator, IntoIterator, repeat};
|
||||
|
||||
pub fn lower_pat<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: &Pat)
|
||||
-> &'a Pattern<'tcx>
|
||||
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
|
||||
-> &'a Pattern<'tcx>
|
||||
{
|
||||
cx.pattern_arena.alloc(
|
||||
LiteralExpander.fold_pattern(&Pattern::from_hir(cx.tcx, pat))
|
||||
)
|
||||
cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
|
||||
}
|
||||
|
||||
struct LiteralExpander;
|
||||
|
@ -8,20 +8,19 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use _match::{MatchCheckCtxt, Matrix, lower_pat, is_useful};
|
||||
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 eval::report_const_eval_err;
|
||||
use eval::{eval_const_expr_partial, const_expr_to_pat, lookup_const_by_id};
|
||||
use eval::EvalHint::ExprTypeChecked;
|
||||
|
||||
use rustc::dep_graph::DepNode;
|
||||
|
||||
use rustc::hir::pat_util::{pat_bindings, pat_contains_bindings};
|
||||
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
|
||||
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
|
||||
use rustc::middle::expr_use_visitor as euv;
|
||||
@ -39,9 +38,7 @@ use rustc::hir::{self, Pat, PatKind};
|
||||
use rustc_back::slice;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Spanned;
|
||||
use syntax::ptr::P;
|
||||
use syntax::util::move_map::MoveMap;
|
||||
use syntax_pos::Span;
|
||||
|
||||
struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
|
||||
@ -80,9 +77,6 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> OuterVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx });
|
||||
tcx.sess.abort_if_errors();
|
||||
@ -112,8 +106,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
|
||||
fn visit_local(&mut self, loc: &hir::Local) {
|
||||
intravisit::walk_local(self, loc);
|
||||
|
||||
let pat = StaticInliner::new(self.tcx).fold_pat(loc.pat.clone());
|
||||
self.check_irrefutable(&pat, false);
|
||||
self.check_irrefutable(&loc.pat, false);
|
||||
|
||||
// Check legality of move bindings and `@` patterns.
|
||||
self.check_patterns(false, slice::ref_slice(&loc.pat));
|
||||
@ -138,6 +131,27 @@ 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");
|
||||
}
|
||||
PatternError::ConstEval(err) => {
|
||||
report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_match(
|
||||
&self,
|
||||
scrut: &hir::Expr,
|
||||
@ -154,32 +168,36 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
if let Some(ref guard) = arm.guard {
|
||||
check_for_mutation_in_guard(self, &guard);
|
||||
}
|
||||
}
|
||||
|
||||
let mut static_inliner = StaticInliner::new(self.tcx);
|
||||
let inlined_arms = arms.iter().map(|arm| {
|
||||
(arm.pats.iter().map(|pat| {
|
||||
static_inliner.fold_pat((*pat).clone())
|
||||
}).collect(), arm.guard.as_ref().map(|e| &**e))
|
||||
}).collect::<Vec<(Vec<P<Pat>>, Option<&hir::Expr>)>>();
|
||||
|
||||
// Bail out early if inlining failed.
|
||||
if static_inliner.failed {
|
||||
return;
|
||||
}
|
||||
|
||||
for pat in inlined_arms.iter().flat_map(|&(ref pats, _)| pats) {
|
||||
// Fourth, check if there are any references to NaN that we should warn about.
|
||||
check_for_static_nan(self, &pat);
|
||||
|
||||
// Fifth, check if for any of the patterns that match an enumerated type
|
||||
// are bindings with the same name as one of the variants of said type.
|
||||
check_for_bindings_named_the_same_as_variants(self, &pat);
|
||||
// Third, perform some lints.
|
||||
for pat in &arm.pats {
|
||||
check_for_bindings_named_the_same_as_variants(self, pat);
|
||||
}
|
||||
}
|
||||
|
||||
MatchCheckCtxt::create_and_enter(self.tcx, |ref cx| {
|
||||
let mut have_errors = false;
|
||||
|
||||
let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
|
||||
arm.pats.iter().map(|pat| {
|
||||
let mut patcx = PatternContext::new(self.tcx);
|
||||
let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
|
||||
if !patcx.errors.is_empty() {
|
||||
self.report_inlining_errors(patcx, pat.span);
|
||||
have_errors = true;
|
||||
}
|
||||
(pattern, &**pat)
|
||||
}).collect(),
|
||||
arm.guard.as_ref().map(|e| &**e)
|
||||
)).collect();
|
||||
|
||||
// Bail out early if inlining failed.
|
||||
if have_errors {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fourth, check for unreachable arms.
|
||||
check_arms(cx, &inlined_arms[..], source);
|
||||
check_arms(cx, &inlined_arms, source);
|
||||
|
||||
// Finally, check if the whole match expression is exhaustive.
|
||||
// Check for empty enum, because is_useful only works on inhabited types.
|
||||
@ -204,7 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
.iter()
|
||||
.filter(|&&(_, guard)| guard.is_none())
|
||||
.flat_map(|arm| &arm.0)
|
||||
.map(|pat| vec![lower_pat(cx, &pat)])
|
||||
.map(|pat| vec![pat.0])
|
||||
.collect();
|
||||
check_exhaustive(cx, scrut.span, &matrix, source);
|
||||
})
|
||||
@ -218,8 +236,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
};
|
||||
|
||||
MatchCheckCtxt::create_and_enter(self.tcx, |ref cx| {
|
||||
let mut patcx = PatternContext::new(self.tcx);
|
||||
let pats : Matrix = vec![vec![
|
||||
lower_pat(cx, pat)
|
||||
expand_pattern(cx, patcx.lower_pattern(pat))
|
||||
]].into_iter().collect();
|
||||
|
||||
let witness = match is_useful(cx, &pats, &[cx.wild_pattern], ConstructWitness) {
|
||||
@ -269,27 +288,6 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
|
||||
});
|
||||
}
|
||||
|
||||
// Check that we do not match against a static NaN (#6804)
|
||||
fn check_for_static_nan(cx: &MatchVisitor, pat: &Pat) {
|
||||
pat.walk(|p| {
|
||||
if let PatKind::Lit(ref expr) = p.node {
|
||||
match eval_const_expr_partial(cx.tcx, &expr, ExprTypeChecked, None) {
|
||||
Ok(ConstVal::Float(f)) if f.is_nan() => {
|
||||
span_warn!(cx.tcx.sess, p.span, E0003,
|
||||
"unmatchable NaN in pattern, \
|
||||
use the is_nan method in a guard instead");
|
||||
}
|
||||
Ok(_) => {}
|
||||
|
||||
Err(err) => {
|
||||
report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
/// Checks for common cases of "catchall" patterns that may not be intended as such.
|
||||
fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool {
|
||||
match pat.node {
|
||||
@ -304,15 +302,16 @@ fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool {
|
||||
}
|
||||
|
||||
// Check for unreachable patterns
|
||||
fn check_arms(cx: &MatchCheckCtxt,
|
||||
arms: &[(Vec<P<Pat>>, Option<&hir::Expr>)],
|
||||
source: hir::MatchSource) {
|
||||
fn check_arms<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
arms: &[(Vec<(&Pattern<'tcx>, &'a hir::Pat)>, Option<&hir::Expr>)],
|
||||
source: hir::MatchSource)
|
||||
{
|
||||
let mut seen = Matrix::empty();
|
||||
let mut catchall = None;
|
||||
let mut printed_if_let_err = false;
|
||||
for &(ref pats, guard) in arms {
|
||||
for pat in pats {
|
||||
let v = vec![lower_pat(cx, &pat)];
|
||||
for &(pat, hir_pat) in pats {
|
||||
let v = vec![pat];
|
||||
|
||||
match is_useful(cx, &seen, &v[..], LeaveOutWitness) {
|
||||
NotUseful => {
|
||||
@ -325,7 +324,7 @@ fn check_arms(cx: &MatchCheckCtxt,
|
||||
// find the first arm pattern so we can use its span
|
||||
let &(ref first_arm_pats, _) = &arms[0];
|
||||
let first_pat = &first_arm_pats[0];
|
||||
let span = first_pat.span;
|
||||
let span = first_pat.0.span;
|
||||
struct_span_err!(cx.tcx.sess, span, E0162,
|
||||
"irrefutable if-let pattern")
|
||||
.span_label(span, &format!("irrefutable pattern"))
|
||||
@ -338,7 +337,7 @@ fn check_arms(cx: &MatchCheckCtxt,
|
||||
// find the first arm pattern so we can use its span
|
||||
let &(ref first_arm_pats, _) = &arms[0];
|
||||
let first_pat = &first_arm_pats[0];
|
||||
let span = first_pat.span;
|
||||
let span = first_pat.0.span;
|
||||
struct_span_err!(cx.tcx.sess, span, E0165,
|
||||
"irrefutable while-let pattern")
|
||||
.span_label(span, &format!("irrefutable pattern"))
|
||||
@ -374,7 +373,7 @@ fn check_arms(cx: &MatchCheckCtxt,
|
||||
}
|
||||
if guard.is_none() {
|
||||
seen.push(v);
|
||||
if catchall.is_none() && pat_is_catchall(&cx.tcx.def_map.borrow(), pat) {
|
||||
if catchall.is_none() && pat_is_catchall(&cx.tcx.def_map.borrow(), hir_pat) {
|
||||
catchall = Some(pat.span);
|
||||
}
|
||||
}
|
||||
@ -448,97 +447,6 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct StaticInliner<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
failed: bool
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
|
||||
pub fn new<'b>(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> StaticInliner<'b, 'tcx> {
|
||||
StaticInliner {
|
||||
tcx: tcx,
|
||||
failed: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
|
||||
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
|
||||
match pat.node {
|
||||
PatKind::Path(..) => {
|
||||
match self.tcx.expect_def(pat.id) {
|
||||
Def::AssociatedConst(did) | Def::Const(did) => {
|
||||
let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
|
||||
if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) {
|
||||
match const_expr_to_pat(self.tcx, const_expr, pat.id, pat.span) {
|
||||
Ok(new_pat) => return new_pat,
|
||||
Err(def_id) => {
|
||||
self.failed = true;
|
||||
self.tcx.sess.span_err(
|
||||
pat.span,
|
||||
&format!("constants of the type `{}` \
|
||||
cannot be used in patterns",
|
||||
self.tcx.item_path_str(def_id)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.failed = true;
|
||||
span_err!(self.tcx.sess, pat.span, E0158,
|
||||
"statics cannot be referenced in patterns");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
pat.map(|Pat { id, node, span }| {
|
||||
let node = match node {
|
||||
PatKind::Binding(binding_mode, pth1, sub) => {
|
||||
PatKind::Binding(binding_mode, pth1, sub.map(|x| self.fold_pat(x)))
|
||||
}
|
||||
PatKind::TupleStruct(pth, pats, ddpos) => {
|
||||
PatKind::TupleStruct(pth, pats.move_map(|x| self.fold_pat(x)), ddpos)
|
||||
}
|
||||
PatKind::Struct(pth, fields, etc) => {
|
||||
let fs = fields.move_map(|f| {
|
||||
Spanned {
|
||||
span: f.span,
|
||||
node: hir::FieldPat {
|
||||
name: f.node.name,
|
||||
pat: self.fold_pat(f.node.pat),
|
||||
is_shorthand: f.node.is_shorthand,
|
||||
},
|
||||
}
|
||||
});
|
||||
PatKind::Struct(pth, fs, etc)
|
||||
}
|
||||
PatKind::Tuple(elts, ddpos) => {
|
||||
PatKind::Tuple(elts.move_map(|x| self.fold_pat(x)), ddpos)
|
||||
}
|
||||
PatKind::Box(inner) => PatKind::Box(self.fold_pat(inner)),
|
||||
PatKind::Ref(inner, mutbl) => PatKind::Ref(self.fold_pat(inner), mutbl),
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
PatKind::Slice(before.move_map(|x| self.fold_pat(x)),
|
||||
slice.map(|x| self.fold_pat(x)),
|
||||
after.move_map(|x| self.fold_pat(x)))
|
||||
}
|
||||
PatKind::Wild |
|
||||
PatKind::Lit(_) |
|
||||
PatKind::Range(..) |
|
||||
PatKind::Path(..) => node
|
||||
};
|
||||
Pat {
|
||||
id: id,
|
||||
node: node,
|
||||
span: span
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Legality of move bindings checking
|
||||
fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||
has_guard: bool,
|
||||
|
@ -71,7 +71,7 @@ fn foo(x: Option<String>) {
|
||||
"##,*/
|
||||
|
||||
|
||||
E0003: r##"
|
||||
/*E0003: r##"
|
||||
Not-a-Number (NaN) values cannot be compared for equality and hence can never
|
||||
match the input to a match expression. So, the following will not compile:
|
||||
|
||||
@ -100,7 +100,7 @@ match number {
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
*/
|
||||
|
||||
E0004: r##"
|
||||
This error indicates that the compiler cannot guarantee a matching pattern for
|
||||
|
@ -392,7 +392,7 @@ pub fn note_const_eval_err<'a, 'tcx>(
|
||||
|
||||
pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
e: &Expr) -> ConstVal {
|
||||
match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
|
||||
match eval_const_expr_checked(tcx, e) {
|
||||
Ok(r) => r,
|
||||
// non-const path still needs to be a fatal error, because enums are funky
|
||||
Err(s) => {
|
||||
@ -407,15 +407,21 @@ pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_const_expr_checked<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
e: &Expr) -> EvalResult
|
||||
{
|
||||
eval_const_expr_partial(tcx, e, ExprTypeChecked, None)
|
||||
}
|
||||
|
||||
pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConstEvalErr {
|
||||
pub span: Span,
|
||||
pub kind: ErrKind,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ErrKind {
|
||||
CannotCast,
|
||||
CannotCastTo(&'static str),
|
||||
|
@ -15,6 +15,7 @@ use rustc::mir::repr::{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_id::DefId;
|
||||
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
@ -23,6 +24,13 @@ use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PatternError {
|
||||
StaticInPattern(Span),
|
||||
BadConstInPattern(Span, DefId),
|
||||
ConstEval(eval::ConstEvalErr),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum BindingMode<'tcx> {
|
||||
ByValue,
|
||||
@ -97,78 +105,112 @@ pub enum PatternKind<'tcx> {
|
||||
},
|
||||
}
|
||||
|
||||
pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
pub errors: Vec<PatternError>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>, pat: &hir::Pat) -> Self {
|
||||
let mut ty = tcx.node_id_to_type(pat.id);
|
||||
let mut pcx = PatternContext::new(tcx);
|
||||
let result = pcx.lower_pattern(pat);
|
||||
if !pcx.errors.is_empty() {
|
||||
span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
|
||||
PatternContext { tcx: tcx, errors: vec![] }
|
||||
}
|
||||
|
||||
pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
|
||||
let mut ty = self.tcx.node_id_to_type(pat.id);
|
||||
|
||||
let kind = match pat.node {
|
||||
PatKind::Wild => PatternKind::Wild,
|
||||
|
||||
PatKind::Lit(ref value) => {
|
||||
let value = eval::eval_const_expr(tcx.global_tcx(), value);
|
||||
PatternKind::Constant { value: 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::Range(ref lo, ref hi) => {
|
||||
let lo = eval::eval_const_expr(tcx.global_tcx(), lo);
|
||||
let hi = eval::eval_const_expr(tcx.global_tcx(), hi);
|
||||
PatternKind::Range { lo: lo, hi: 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
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Path(..) => {
|
||||
match tcx.expect_def(pat.id) {
|
||||
match self.tcx.expect_def(pat.id) {
|
||||
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
|
||||
let tcx = tcx.global_tcx();
|
||||
let substs = Some(tcx.node_id_item_substs(pat.id).substs);
|
||||
let tcx = self.tcx.global_tcx();
|
||||
let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
|
||||
match eval::lookup_const_by_id(tcx, def_id, substs) {
|
||||
Some((const_expr, _const_ty)) => {
|
||||
match eval::const_expr_to_pat(tcx,
|
||||
const_expr,
|
||||
pat.id,
|
||||
pat.span) {
|
||||
Ok(pat) =>
|
||||
return Pattern::from_hir(tcx, &pat),
|
||||
Err(_) =>
|
||||
span_bug!(
|
||||
pat.span, "illegal constant"),
|
||||
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 => {
|
||||
span_bug!(
|
||||
pat.span,
|
||||
"cannot eval constant: {:?}",
|
||||
def_id)
|
||||
self.errors.push(PatternError::StaticInPattern(pat.span));
|
||||
PatternKind::Wild
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
PatternKind::from_variant_or_leaf(tcx, pat, vec![])
|
||||
}
|
||||
_ => self.lower_variant_or_leaf(pat, vec![])
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Ref(ref subpattern, _) |
|
||||
PatKind::Box(ref subpattern) => {
|
||||
PatternKind::Deref { subpattern: Self::from_hir(tcx, subpattern) }
|
||||
PatternKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
||||
}
|
||||
|
||||
PatKind::Slice(ref prefix, ref slice, ref suffix) => {
|
||||
let ty = tcx.node_id_to_type(pat.id);
|
||||
let ty = self.tcx.node_id_to_type(pat.id);
|
||||
match ty.sty {
|
||||
ty::TyRef(_, mt) =>
|
||||
PatternKind::Deref {
|
||||
subpattern: Pattern {
|
||||
ty: mt.ty,
|
||||
span: pat.span,
|
||||
kind: Box::new(PatternKind::from_slice_or_array(
|
||||
tcx, pat.span, mt.ty, prefix, slice, suffix))
|
||||
kind: Box::new(self.slice_or_array_pattern(
|
||||
pat.span, mt.ty, prefix, slice, suffix))
|
||||
},
|
||||
},
|
||||
|
||||
ty::TySlice(..) |
|
||||
ty::TyArray(..) =>
|
||||
PatternKind::from_slice_or_array(
|
||||
tcx, pat.span, ty, prefix, slice, suffix),
|
||||
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
|
||||
|
||||
ref sty =>
|
||||
span_bug!(
|
||||
@ -179,14 +221,14 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
}
|
||||
|
||||
PatKind::Tuple(ref subpatterns, ddpos) => {
|
||||
match tcx.node_id_to_type(pat.id).sty {
|
||||
match self.tcx.node_id_to_type(pat.id).sty {
|
||||
ty::TyTuple(ref tys) => {
|
||||
let subpatterns =
|
||||
subpatterns.iter()
|
||||
.enumerate_and_adjust(tys.len(), ddpos)
|
||||
.map(|(i, subpattern)| FieldPattern {
|
||||
field: Field::new(i),
|
||||
pattern: Self::from_hir(tcx, subpattern),
|
||||
pattern: self.lower_pattern(subpattern)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -198,9 +240,9 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
}
|
||||
|
||||
PatKind::Binding(bm, ref ident, ref sub) => {
|
||||
let def_id = tcx.expect_def(pat.id).def_id();
|
||||
let id = tcx.map.as_local_node_id(def_id).unwrap();
|
||||
let var_ty = tcx.node_id_to_type(pat.id);
|
||||
let def_id = self.tcx.expect_def(pat.id).def_id();
|
||||
let id = self.tcx.map.as_local_node_id(def_id).unwrap();
|
||||
let var_ty = self.tcx.node_id_to_type(pat.id);
|
||||
let region = match var_ty.sty {
|
||||
ty::TyRef(r, _) => Some(r),
|
||||
_ => None,
|
||||
@ -232,31 +274,31 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
name: ident.node,
|
||||
var: id,
|
||||
ty: var_ty,
|
||||
subpattern: Self::from_opt_pattern(tcx, sub),
|
||||
subpattern: self.lower_opt_pattern(sub),
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::TupleStruct(_, ref subpatterns, ddpos) => {
|
||||
let pat_ty = tcx.node_id_to_type(pat.id);
|
||||
let pat_ty = self.tcx.node_id_to_type(pat.id);
|
||||
let adt_def = match pat_ty.sty {
|
||||
ty::TyAdt(adt_def, _) => adt_def,
|
||||
_ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
|
||||
};
|
||||
let variant_def = adt_def.variant_of_def(tcx.expect_def(pat.id));
|
||||
let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id));
|
||||
|
||||
let subpatterns =
|
||||
subpatterns.iter()
|
||||
.enumerate_and_adjust(variant_def.fields.len(), ddpos)
|
||||
.map(|(i, field)| FieldPattern {
|
||||
field: Field::new(i),
|
||||
pattern: Self::from_hir(tcx, field),
|
||||
pattern: self.lower_pattern(field),
|
||||
})
|
||||
.collect();
|
||||
PatternKind::from_variant_or_leaf(tcx, pat, subpatterns)
|
||||
self.lower_variant_or_leaf(pat, subpatterns)
|
||||
}
|
||||
|
||||
PatKind::Struct(_, ref fields, _) => {
|
||||
let pat_ty = tcx.node_id_to_type(pat.id);
|
||||
let pat_ty = self.tcx.node_id_to_type(pat.id);
|
||||
let adt_def = match pat_ty.sty {
|
||||
ty::TyAdt(adt_def, _) => adt_def,
|
||||
_ => {
|
||||
@ -265,7 +307,7 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
"struct pattern not applied to an ADT");
|
||||
}
|
||||
};
|
||||
let variant_def = adt_def.variant_of_def(tcx.expect_def(pat.id));
|
||||
let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id));
|
||||
|
||||
let subpatterns =
|
||||
fields.iter()
|
||||
@ -279,12 +321,12 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
});
|
||||
FieldPattern {
|
||||
field: Field::new(index),
|
||||
pattern: Self::from_hir(tcx, &field.node.pat),
|
||||
pattern: self.lower_pattern(&field.node.pat),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
PatternKind::from_variant_or_leaf(tcx, pat, subpatterns)
|
||||
self.lower_variant_or_leaf(pat, subpatterns)
|
||||
}
|
||||
};
|
||||
|
||||
@ -295,33 +337,31 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn from_patterns(tcx: TyCtxt<'a, 'gcx, 'tcx>, pats: &[P<hir::Pat>]) -> Vec<Self> {
|
||||
pats.iter().map(|p| Self::from_hir(tcx, p)).collect()
|
||||
fn lower_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
|
||||
pats.iter().map(|p| self.lower_pattern(p)).collect()
|
||||
}
|
||||
|
||||
fn from_opt_pattern(tcx: TyCtxt<'a, 'gcx, 'tcx>, pat: &Option<P<hir::Pat>>) -> Option<Self>
|
||||
fn lower_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
|
||||
{
|
||||
pat.as_ref().map(|p| Self::from_hir(tcx, p))
|
||||
pat.as_ref().map(|p| self.lower_pattern(p))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> PatternKind<'tcx> {
|
||||
fn from_slice_or_array(
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
fn slice_or_array_pattern(
|
||||
&mut self,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
prefix: &[P<hir::Pat>],
|
||||
slice: &Option<P<hir::Pat>>,
|
||||
suffix: &[P<hir::Pat>])
|
||||
-> Self
|
||||
-> PatternKind<'tcx>
|
||||
{
|
||||
match ty.sty {
|
||||
ty::TySlice(..) => {
|
||||
// matching a slice or fixed-length array
|
||||
PatternKind::Slice {
|
||||
prefix: Pattern::from_patterns(tcx, prefix),
|
||||
slice: Pattern::from_opt_pattern(tcx, slice),
|
||||
suffix: Pattern::from_patterns(tcx, suffix),
|
||||
prefix: self.lower_patterns(prefix),
|
||||
slice: self.lower_opt_pattern(slice),
|
||||
suffix: self.lower_patterns(suffix),
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,28 +369,28 @@ impl<'a, 'gcx, 'tcx> PatternKind<'tcx> {
|
||||
// fixed-length array
|
||||
assert!(len >= prefix.len() + suffix.len());
|
||||
PatternKind::Array {
|
||||
prefix: Pattern::from_patterns(tcx, prefix),
|
||||
slice: Pattern::from_opt_pattern(tcx, slice),
|
||||
suffix: Pattern::from_patterns(tcx, suffix),
|
||||
prefix: self.lower_patterns(prefix),
|
||||
slice: self.lower_opt_pattern(slice),
|
||||
suffix: self.lower_patterns(suffix),
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
span_bug!(span, "unexpanded macro or bad constant etc");
|
||||
span_bug!(span, "bad slice pattern type {:?}", ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn from_variant_or_leaf(
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
fn lower_variant_or_leaf(
|
||||
&mut self,
|
||||
pat: &hir::Pat,
|
||||
subpatterns: Vec<FieldPattern<'tcx>>)
|
||||
-> Self
|
||||
-> PatternKind<'tcx>
|
||||
{
|
||||
match tcx.expect_def(pat.id) {
|
||||
match self.tcx.expect_def(pat.id) {
|
||||
Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
|
||||
let enum_id = tcx.parent_def_id(variant_id).unwrap();
|
||||
let adt_def = tcx.lookup_adt_def(enum_id);
|
||||
let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
|
||||
let adt_def = self.tcx.lookup_adt_def(enum_id);
|
||||
if adt_def.variants.len() > 1 {
|
||||
PatternKind::Variant {
|
||||
adt_def: adt_def,
|
||||
|
@ -21,10 +21,6 @@ const NEG_128: i8 = -128;
|
||||
const NEG_NEG_128: i8 = -NEG_128;
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| attempt to negate with overflow
|
||||
//~| ERROR constant evaluation error
|
||||
//~| attempt to negate with overflow
|
||||
//~| ERROR constant evaluation error
|
||||
//~| attempt to negate with overflow
|
||||
|
||||
fn main() {
|
||||
match -128i8 {
|
||||
|
@ -19,9 +19,7 @@ use Cake::*;
|
||||
const BOO: (Cake, Cake) = (Marmor, BlackForest);
|
||||
//~^ ERROR: constant evaluation error [E0080]
|
||||
//~| unimplemented constant expression: enum variants
|
||||
//~^^^ ERROR: constant evaluation error [E0080]
|
||||
//~| unimplemented constant expression: enum variants
|
||||
const FOO: Cake = BOO.1; //~ NOTE for expression here
|
||||
const FOO: Cake = BOO.1;
|
||||
|
||||
const fn foo() -> Cake {
|
||||
Marmor
|
||||
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(slice_patterns)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Matching against NaN should result in a warning
|
||||
|
||||
use std::f64::NAN;
|
||||
|
||||
#[rustc_error]
|
||||
fn main() { //~ ERROR compilation successful
|
||||
let x = NAN;
|
||||
match x {
|
||||
NAN => {},
|
||||
_ => {},
|
||||
};
|
||||
//~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead
|
||||
//~| WARNING floating point constants cannot be used
|
||||
//~| WARNING this was previously accepted
|
||||
match [x, 1.0] {
|
||||
[NAN, _] => {},
|
||||
_ => {},
|
||||
};
|
||||
//~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead
|
||||
//~| WARNING floating point constants cannot be used
|
||||
//~| WARNING this was previously accepted
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user