remove StaticInliner and NaN checking

NaN checking was a lint for a deprecated feature. It can go away.
This commit is contained in:
Ariel Ben-Yehuda 2016-10-03 21:39:21 +03:00
parent 37418b850f
commit 76fb7d90ec
8 changed files with 185 additions and 275 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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),

View File

@ -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,

View File

@ -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 {

View File

@ -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

View File

@ -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
}