提交 fba11948 编写于 作者: J Jakub Wieczorek

Add support for patterns referencing non-trivial statics

This is accomplished by rewriting static expressions into equivalent patterns.
This way, patterns referencing static variables can both participate
in exhaustiveness analysis as well as be compiled down into the appropriate
branch of the decision trees that match expressions are codegened to.

Fixes #6533.
Fixes #13626.
Fixes #13731.
Fixes #14576.
Fixes #15393.
上级 7502b4cd
......@@ -68,42 +68,42 @@ pub mod back {
}
pub mod middle {
pub mod def;
pub mod trans;
pub mod ty;
pub mod ty_fold;
pub mod subst;
pub mod resolve;
pub mod resolve_lifetime;
pub mod typeck;
pub mod astencode;
pub mod borrowck;
pub mod cfg;
pub mod check_const;
pub mod check_loop;
pub mod check_match;
pub mod check_const;
pub mod check_static;
pub mod borrowck;
pub mod const_eval;
pub mod dataflow;
pub mod mem_categorization;
pub mod liveness;
pub mod kind;
pub mod dead;
pub mod def;
pub mod dependency_format;
pub mod effect;
pub mod entry;
pub mod expr_use_visitor;
pub mod freevars;
pub mod pat_util;
pub mod region;
pub mod const_eval;
pub mod astencode;
pub mod graph;
pub mod intrinsicck;
pub mod kind;
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;
pub mod pat_util;
pub mod privacy;
pub mod entry;
pub mod effect;
pub mod reachable;
pub mod graph;
pub mod cfg;
pub mod dead;
pub mod expr_use_visitor;
pub mod dependency_format;
pub mod weak_lang_items;
pub mod region;
pub mod resolve;
pub mod resolve_lifetime;
pub mod save;
pub mod intrinsicck;
pub mod stability;
pub mod subst;
pub mod trans;
pub mod ty;
pub mod ty_fold;
pub mod typeck;
pub mod weak_lang_items;
}
pub mod front {
......
......@@ -9,7 +9,7 @@
// except according to those terms.
use middle::const_eval::{compare_const_vals, const_bool, const_float, const_nil, const_val};
use middle::const_eval::{eval_const_expr, lookup_const_by_id};
use middle::const_eval::{const_expr_to_pat, eval_const_expr, lookup_const_by_id};
use middle::def::*;
use middle::pat_util::*;
use middle::ty::*;
......@@ -21,8 +21,9 @@
use syntax::ast::*;
use syntax::ast_util::{is_unguarded, walk_pat};
use syntax::codemap::{Span, Spanned, DUMMY_SP};
use syntax::owned_slice::OwnedSlice;
use syntax::fold::{Folder, noop_fold_pat};
use syntax::print::pprust::pat_to_string;
use syntax::parse::token;
use syntax::visit;
use syntax::visit::{Visitor, FnKind};
use util::ppaux::ty_to_string;
......@@ -76,6 +77,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
impl FromIterator<Vec<Gc<Pat>>> for Matrix {
fn from_iter<T: Iterator<Vec<Gc<Pat>>>>(mut iterator: T) -> Matrix {
Matrix(iterator.collect())
}
}
pub struct MatchCheckCtxt<'a> {
pub tcx: &'a ty::ctxt
}
......@@ -120,10 +127,8 @@ fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId,
}
pub fn check_crate(tcx: &ty::ctxt, krate: &Crate) {
let mut cx = MatchCheckCtxt { tcx: tcx, };
let mut cx = MatchCheckCtxt { tcx: tcx };
visit::walk_crate(&mut cx, krate, ());
tcx.sess.abort_if_errors();
}
......@@ -155,48 +160,49 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
// If the type *is* empty, it's vacuously exhaustive
return;
}
let m: Matrix = Matrix(arms
let mut static_inliner = StaticInliner { tcx: cx.tcx };
let matrix: Matrix = arms
.iter()
.filter(|&arm| is_unguarded(arm))
.flat_map(|arm| arm.pats.iter())
.map(|pat| vec!(pat.clone()))
.collect());
check_exhaustive(cx, ex.span, &m);
.map(|pat| vec![static_inliner.fold_pat(*pat)])
.collect();
check_exhaustive(cx, ex.span, &matrix);
},
_ => ()
}
}
fn is_expr_const_nan(tcx: &ty::ctxt, expr: &Expr) -> bool {
match eval_const_expr(tcx, expr) {
const_float(f) => f.is_nan(),
_ => false
}
}
// Check for unreachable patterns
fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
let mut seen = Matrix(vec!());
let mut static_inliner = StaticInliner { tcx: cx.tcx };
for arm in arms.iter() {
for pat in arm.pats.iter() {
let inlined = static_inliner.fold_pat(*pat);
// Check that we do not match against a static NaN (#6804)
let pat_matches_nan: |&Pat| -> bool = |p| {
let opt_def = cx.tcx.def_map.borrow().find_copy(&p.id);
match opt_def {
Some(DefStatic(did, false)) => {
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
match eval_const_expr(cx.tcx, &*const_expr) {
const_float(f) if f.is_nan() => true,
_ => false
}
walk_pat(&*inlined, |p| {
match p.node {
PatLit(expr) if is_expr_const_nan(cx.tcx, &*expr) => {
span_warn!(cx.tcx.sess, pat.span, E0003,
"unmatchable NaN in pattern, \
use the is_nan method in a guard instead");
}
_ => false
}
};
walk_pat(&**pat, |p| {
if pat_matches_nan(p) {
span_warn!(cx.tcx.sess, p.span, E0003,
"unmatchable NaN in pattern, use the is_nan method in a guard instead"
);
_ => ()
}
true
});
let v = vec!(*pat);
let v = vec![inlined];
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
NotUseful => span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"),
Useful => (),
......@@ -218,8 +224,8 @@ fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
}
}
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
match is_useful(cx, m, [wild()], ConstructWitness) {
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) {
match is_useful(cx, matrix, [wild()], ConstructWitness) {
UsefulWithWitness(pats) => {
let witness = match pats.as_slice() {
[witness] => witness,
......@@ -251,16 +257,26 @@ fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
}
}
fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
ty::with_path(tcx, id, |mut path| Path {
global: false,
segments: path.last().map(|elem| PathSegment {
identifier: Ident::new(elem.name()),
lifetimes: vec!(),
types: OwnedSlice::empty()
}).move_iter().collect(),
span: DUMMY_SP,
})
pub struct StaticInliner<'a> {
pub tcx: &'a ty::ctxt
}
impl<'a> Folder for StaticInliner<'a> {
fn fold_pat(&mut self, pat: Gc<Pat>) -> Gc<Pat> {
match pat.node {
PatIdent(..) | PatEnum(..) => {
let def = self.tcx.def_map.borrow().find_copy(&pat.id);
match def {
Some(DefStatic(did, _)) => {
let const_expr = lookup_const_by_id(self.tcx, did).unwrap();
const_expr_to_pat(self.tcx, const_expr)
},
_ => noop_fold_pat(pat, self)
}
}
_ => noop_fold_pat(pat, self)
}
}
}
/// Constructs a partial witness for a pattern given a list of
......@@ -283,9 +299,11 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => {
let (vid, is_structure) = match ctor {
&Variant(vid) => (vid,
ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()),
_ => (cid, true)
&Variant(vid) =>
(vid, ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()),
_ =>
(cid, ty::lookup_struct_fields(cx.tcx, cid).iter()
.any(|field| field.name != token::special_idents::unnamed_field.name))
};
if is_structure {
let fields = ty::lookup_struct_fields(cx.tcx, vid);
......@@ -459,8 +477,7 @@ fn is_useful(cx: &MatchCheckCtxt, matrix @ &Matrix(ref rows): &Matrix,
},
Some(constructor) => {
let matrix = Matrix(rows.iter().filter_map(|r|
default(cx, r.as_slice())).collect());
let matrix = rows.iter().filter_map(|r| default(cx, r.as_slice())).collect();
match is_useful(cx, &matrix, v.tail(), witness) {
UsefulWithWitness(pats) => {
let arity = constructor_arity(cx, &constructor, left_ty);
......@@ -506,25 +523,23 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: Gc<Pat>,
match pat.node {
PatIdent(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
Some(&DefStatic(did, false)) => {
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
},
Some(&DefStatic(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefStruct(_)) => vec!(Single),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!()
},
PatEnum(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
Some(&DefStatic(did, false)) => {
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
},
Some(&DefStatic(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
PatStruct(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
Some(&DefStatic(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
......@@ -583,7 +598,7 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) ->
}
fn range_covered_by_constructor(ctor: &Constructor,
from: &const_val,to: &const_val) -> Option<bool> {
from: &const_val, to: &const_val) -> Option<bool> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
......@@ -621,44 +636,22 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
&PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().find_copy(&pat_id);
match opt_def {
Some(DefStatic(..)) =>
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
Some(vec!())
} else {
None
},
Some(DefStatic(did, _)) => {
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
let e_v = eval_const_expr(cx.tcx, &*const_expr);
match range_covered_by_constructor(constructor, &e_v, &e_v) {
Some(true) => Some(vec!()),
Some(false) => None,
None => {
cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
None
}
}
}
_ => {
Some(Vec::from_elem(arity, wild()))
}
_ => Some(Vec::from_elem(arity, wild()))
}
}
&PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
match def {
DefStatic(did, _) => {
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
let e_v = eval_const_expr(cx.tcx, &*const_expr);
match range_covered_by_constructor(constructor, &e_v, &e_v) {
Some(true) => Some(vec!()),
Some(false) => None,
None => {
cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
None
}
}
}
DefStatic(..) =>
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
DefVariant(_, id, _) if *constructor != Variant(id) => None,
DefVariant(..) | DefFn(..) | DefStruct(..) => {
Some(match args {
......@@ -674,6 +667,8 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
// Is this a struct or an enum variant?
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
let class_id = match def {
DefStatic(..) =>
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
Some(variant_id)
} else {
......@@ -782,7 +777,8 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
LocalFor => "`for` loop"
};
match is_refutable(cx, loc.pat) {
let mut static_inliner = StaticInliner { tcx: cx.tcx };
match is_refutable(cx, static_inliner.fold_pat(loc.pat)) {
Some(pat) => {
span_err!(cx.tcx.sess, loc.pat.span, E0005,
"refutable pattern in {} binding: `{}` not covered",
......
......@@ -13,8 +13,8 @@
use metadata::csearch;
use middle::astencode;
use middle::def;
use middle::pat_util::def_to_path;
use middle::ty;
use middle::typeck::astconv;
use util::nodemap::{DefIdMap};
......@@ -26,7 +26,7 @@
use syntax::{ast, ast_map, ast_util};
use std::rc::Rc;
use std::gc::Gc;
use std::gc::{Gc, GC};
//
// This pass classifies expressions by their constant-ness.
......@@ -303,6 +303,57 @@ pub enum const_val {
const_nil
}
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: Gc<Expr>) -> Gc<Pat> {
let pat = match expr.node {
ExprTup(ref exprs) =>
PatTup(exprs.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect()),
ExprCall(callee, ref args) => {
let def = tcx.def_map.borrow().get_copy(&callee.id);
tcx.def_map.borrow_mut().find_or_insert(expr.id, def);
let path = match def {
def::DefStruct(def_id) => def_to_path(tcx, def_id),
def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did),
_ => unreachable!()
};
let pats = args.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect();
PatEnum(path, Some(pats))
}
ExprStruct(ref path, ref fields, None) => {
let field_pats = fields.iter().map(|field| FieldPat {
ident: field.ident.node,
pat: const_expr_to_pat(tcx, field.expr)
}).collect();
PatStruct(path.clone(), field_pats, false)
}
ExprVec(ref exprs) => {
let pats = exprs.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect();
PatVec(pats, None, vec![])
}
ExprPath(ref path) => {
let opt_def = tcx.def_map.borrow().find_copy(&expr.id);
match opt_def {
Some(def::DefStruct(..)) =>
PatStruct(path.clone(), vec![], false),
Some(def::DefVariant(..)) =>
PatEnum(path.clone(), None),
_ => {
match lookup_const(tcx, &*expr) {
Some(actual) => return const_expr_to_pat(tcx, actual),
_ => unreachable!()
}
}
}
}
_ => PatLit(expr)
};
box (GC) Pat { id: expr.id, node: pat, span: expr.span }
}
pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {
match eval_const_expr_partial(tcx, e) {
Ok(r) => r,
......
......@@ -10,12 +10,14 @@
use middle::def::*;
use middle::resolve;
use middle::ty;
use std::collections::HashMap;
use std::gc::{Gc, GC};
use syntax::ast::*;
use syntax::ast_util::{walk_pat};
use syntax::codemap::{Span, DUMMY_SP};
use syntax::owned_slice::OwnedSlice;
pub type PatIdMap = HashMap<Ident, NodeId>;
......@@ -116,3 +118,15 @@ pub fn simple_identifier<'a>(pat: &'a Pat) -> Option<&'a Ident> {
pub fn wild() -> Gc<Pat> {
box (GC) Pat { id: 0, node: PatWild, span: DUMMY_SP }
}
pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
ty::with_path(tcx, id, |mut path| Path {
global: false,
segments: path.last().map(|elem| PathSegment {
identifier: Ident::new(elem.name()),
lifetimes: vec!(),
types: OwnedSlice::empty()
}).move_iter().collect(),
span: DUMMY_SP,
})
}
......@@ -4398,7 +4398,7 @@ fn resolve_pattern(&mut self,
let ident = path1.node;
let renamed = mtwt::resolve(ident);
match self.resolve_bare_identifier_pattern(ident) {
match self.resolve_bare_identifier_pattern(ident, pattern.span) {
FoundStructOrEnumVariant(def, lp)
if mode == RefutableMode => {
debug!("(resolving pattern) resolving `{}` to \
......@@ -4562,7 +4562,7 @@ struct or enum variant",
});
}
fn resolve_bare_identifier_pattern(&mut self, name: Ident)
fn resolve_bare_identifier_pattern(&mut self, name: Ident, span: Span)
-> BareIdentifierPatternResolution {
let module = self.current_module.clone();
match self.resolve_item_in_lexical_scope(module,
......@@ -4589,6 +4589,11 @@ fn resolve_bare_identifier_pattern(&mut self, name: Ident)
def @ DefStatic(_, false) => {
return FoundConst(def, LastMod(AllPublic));
}
DefStatic(_, true) => {
self.resolve_error(span,
"mutable static variables cannot be referenced in a pattern");
return BareIdentifierPatternUnresolved;
}
_ => {
return BareIdentifierPatternUnresolved;
}
......
......@@ -195,6 +195,7 @@
use middle::const_eval;
use middle::def;
use middle::check_match;
use middle::check_match::StaticInliner;
use middle::lang_items::StrEqFnLangItem;
use middle::pat_util::*;
use middle::resolve::DefMap;
......@@ -225,14 +226,9 @@
use syntax::ast;
use syntax::ast::Ident;
use syntax::codemap::Span;
use syntax::fold::Folder;
use syntax::parse::token::InternedString;
// An option identifying a literal: either an expression or a DefId of a static expression.
enum Lit {
ExprLit(Gc<ast::Expr>),
ConstLit(ast::DefId), // the def ID of the constant
}
#[deriving(PartialEq)]
pub enum VecLenOpt {
vec_len_eq,
......@@ -242,24 +238,15 @@ pub enum VecLenOpt {
// An option identifying a branch (either a literal, an enum variant or a
// range)
enum Opt {
lit(Lit),
lit(Gc<ast::Expr>),
var(ty::Disr, Rc<adt::Repr>, ast::DefId),
range(Gc<ast::Expr>, Gc<ast::Expr>),
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
}
fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> Gc<ast::Expr> {
match *a {
ExprLit(existing_a_expr) => existing_a_expr,
ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap()
}
}
fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
match (a, b) {
(&lit(a), &lit(b)) => {
let a_expr = lit_to_expr(tcx, &a);
let b_expr = lit_to_expr(tcx, &b);
(&lit(a_expr), &lit(b_expr)) => {
match const_eval::compare_lit_exprs(tcx, &*a_expr, &*b_expr) {
Some(val1) => val1 == 0,
None => fail!("compare_list_exprs: type mismatch"),
......@@ -286,20 +273,13 @@ pub enum opt_result<'a> {
range_result(Result<'a>, Result<'a>),
}
fn trans_opt<'a>(bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
let _icx = push_ctxt("match::trans_opt");
let ccx = bcx.ccx();
let mut bcx = bcx;
match *o {
lit(ExprLit(ref lit_expr)) => {
let lit_datum = unpack_datum!(bcx, expr::trans(bcx, &**lit_expr));
let lit_datum = lit_datum.assert_rvalue(bcx); // literals are rvalues
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
return single_result(Result::new(bcx, lit_datum.val));
}
lit(l @ ConstLit(ref def_id)) => {
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_to_expr(bcx.tcx(), &l).id);
let (llval, _) = consts::get_const_val(bcx.ccx(), *def_id);
lit(lit_expr) => {
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id);
let (llval, _) = consts::const_expr(ccx, &*lit_expr, true);
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
return single_result(Result::new(bcx, lit_datum.val));
......@@ -546,13 +526,12 @@ fn enter_opt<'a, 'b>(
let _indenter = indenter();
let ctor = match opt {
&lit(x) => {
check_match::ConstantValue(const_eval::eval_const_expr(
bcx.tcx(), &*lit_to_expr(bcx.tcx(), &x)))
}
&range(ref lo, ref hi) => check_match::ConstantRange(
const_eval::eval_const_expr(bcx.tcx(), &**lo),
const_eval::eval_const_expr(bcx.tcx(), &**hi)
&lit(expr) => check_match::ConstantValue(
const_eval::eval_const_expr(bcx.tcx(), &*expr)
),
&range(lo, hi) => check_match::ConstantRange(
const_eval::eval_const_expr(bcx.tcx(), &*lo),
const_eval::eval_const_expr(bcx.tcx(), &*hi)
),
&vec_len(len, _, _) => check_match::Slice(len),
&var(_, _, def_id) => check_match::Variant(def_id)
......@@ -649,7 +628,7 @@ fn add_veclen_to_set(set: &mut Vec<Opt> , i: uint,
let cur = *br.pats.get(col);
match cur.node {
ast::PatLit(l) => {
add_to_set(ccx.tcx(), &mut found, lit(ExprLit(l)));
add_to_set(ccx.tcx(), &mut found, lit(l));
}
ast::PatIdent(..) => {
// This is either an enum variant or a variable binding.
......@@ -659,10 +638,6 @@ fn add_veclen_to_set(set: &mut Vec<Opt> , i: uint,
add_to_set(ccx.tcx(), &mut found,
variant_opt(bcx, cur.id));
}
Some(def::DefStatic(const_did, false)) => {
add_to_set(ccx.tcx(), &mut found,
lit(ConstLit(const_did)));
}
_ => {}
}
}
......@@ -676,10 +651,6 @@ fn add_veclen_to_set(set: &mut Vec<Opt> , i: uint,
add_to_set(ccx.tcx(), &mut found,
variant_opt(bcx, cur.id));
}
Some(def::DefStatic(const_did, false)) => {
add_to_set(ccx.tcx(), &mut found,
lit(ConstLit(const_did)));
}
_ => {}
}
}
......@@ -1447,10 +1418,11 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
bindings_map: create_bindings_map(bcx, *arm.pats.get(0))
}).collect();
let mut static_inliner = StaticInliner { tcx: scope_cx.tcx() };
let mut matches = Vec::new();
for arm_data in arm_datas.iter() {
matches.extend(arm_data.arm.pats.iter().map(|p| Match {
pats: vec!(*p),
matches.extend(arm_data.arm.pats.iter().map(|&p| Match {
pats: vec![static_inliner.fold_pat(p)],
data: arm_data,
bound_ptrs: Vec::new(),
}));
......@@ -1754,8 +1726,6 @@ fn bind_irrefutable_pat<'a>(
}
}
}
Some(def::DefStatic(_, false)) => {
}
_ => {
// Nothing to do here.
}
......
// 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.
struct NewBool(bool);
enum Direction {
North,
East,
South,
West
}
static TRUE_TRUE: (bool, bool) = (true, true);
fn nonexhaustive_1() {
match (true, false) {
//~^ ERROR non-exhaustive patterns: `(true, false)` not covered
TRUE_TRUE => (),
(false, false) => (),
(false, true) => ()
}
}
fn unreachable_1() {
match (true, false) {
TRUE_TRUE => (),
(false, false) => (),
(false, true) => (),
(true, false) => (),
(true, true) => ()
//~^ ERROR unreachable pattern
}
}
static NONE: Option<Direction> = None;
static EAST: Direction = East;
fn nonexhaustive_2() {
match Some(Some(North)) {
//~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered
Some(NONE) => (),
Some(Some(North)) => (),
Some(Some(EAST)) => (),
Some(Some(South)) => (),
None => ()
}
}
fn unreachable_2() {
match Some(Some(North)) {
Some(NONE) => (),
Some(Some(North)) => (),
Some(Some(EAST)) => (),
Some(Some(South)) => (),
Some(Some(West)) => (),
Some(Some(East)) => (),
//~^ ERROR unreachable pattern
None => ()
}
}
static NEW_FALSE: NewBool = NewBool(false);
struct Foo {
bar: Option<Direction>,
baz: NewBool
}
static STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
fn nonexhaustive_3() {
match (Foo { bar: Some(North), baz: NewBool(true) }) {
//~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }`
Foo { bar: None, baz: NewBool(true) } => (),
Foo { bar: _, baz: NEW_FALSE } => (),
Foo { bar: Some(West), baz: NewBool(true) } => (),
Foo { bar: Some(South), .. } => (),
Foo { bar: Some(EAST), .. } => ()
}
}
fn unreachable_3() {
match (Foo { bar: Some(EAST), baz: NewBool(true) }) {
Foo { bar: None, baz: NewBool(true) } => (),
Foo { bar: _, baz: NEW_FALSE } => (),
Foo { bar: Some(West), baz: NewBool(true) } => (),
Foo { bar: Some(South), .. } => (),
Foo { bar: Some(EAST), .. } => (),
Foo { bar: Some(North), baz: NewBool(true) } => (),
Foo { bar: Some(EAST), baz: NewBool(false) } => ()
//~^ ERROR unreachable pattern
}
}
fn main() {
nonexhaustive_1();
nonexhaustive_2();
nonexhaustive_3();
unreachable_1();
unreachable_2();
unreachable_3();
}
......@@ -20,7 +20,34 @@ fn main() {
// instead of spitting out a custom error about some identifier collisions
// (we should allow shadowing)
match 4i {
a => {}
_ => {} //~ ERROR: unreachable pattern
a => {} //~ ERROR mutable static variables cannot be referenced in a pattern
_ => {}
}
}
struct NewBool(bool);
enum Direction {
North,
East,
South,
West
}
static NEW_FALSE: NewBool = NewBool(false);
struct Foo {
bar: Option<Direction>,
baz: NewBool
}
static mut STATIC_MUT_FOO: Foo = Foo { bar: Some(West), baz: NEW_FALSE };
fn mutable_statics() {
match (Foo { bar: Some(North), baz: NewBool(true) }) {
Foo { bar: None, baz: NewBool(true) } => (),
STATIC_MUT_FOO => (),
//~^ ERROR mutable static variables cannot be referenced in a pattern
Foo { bar: Some(South), .. } => (),
Foo { bar: Some(EAST), .. } => (),
Foo { bar: Some(North), baz: NewBool(true) } => (),
Foo { bar: Some(EAST), baz: NewBool(false) } => ()
}
}
// 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(struct_variant)]
struct NewBool(bool);
enum Direction {
North,
East,
South,
West
}
struct Foo {
bar: Option<Direction>,
baz: NewBool
}
enum EnumWithStructVariants {
Variant1(bool),
Variant2 {
dir: Direction
}
}
static TRUE_TRUE: (bool, bool) = (true, true);
static NONE: Option<Direction> = None;
static EAST: Direction = East;
static NEW_FALSE: NewBool = NewBool(false);
static STATIC_FOO: Foo = Foo { bar: Some(South), baz: NEW_FALSE };
static VARIANT2_NORTH: EnumWithStructVariants = Variant2 { dir: North };
pub mod glfw {
pub struct InputState(uint);
pub static RELEASE : InputState = InputState(0);
pub static PRESS : InputState = InputState(1);
pub static REPEAT : InputState = InputState(2);
}
fn issue_6533() {
use glfw;
fn action_to_str(state: glfw::InputState) -> &'static str {
use glfw::{RELEASE, PRESS, REPEAT};
match state {
RELEASE => { "Released" }
PRESS => { "Pressed" }
REPEAT => { "Repeated" }
_ => { "Unknown" }
}
}
assert_eq!(action_to_str(glfw::RELEASE), "Released");
assert_eq!(action_to_str(glfw::PRESS), "Pressed");
assert_eq!(action_to_str(glfw::REPEAT), "Repeated");
}
fn issue_13626() {
static VAL: [u8, ..1] = [0];
match [1] {
VAL => unreachable!(),
_ => ()
}
}
fn issue_14576() {
type Foo = (i32, i32);
static ON: Foo = (1, 1);
static OFF: Foo = (0, 0);
match (1, 1) {
OFF => unreachable!(),
ON => (),
_ => unreachable!()
}
enum C { D = 3, E = 4 }
static F : C = D;
assert_eq!(match D { F => 1i, _ => 2, }, 1);
}
fn issue_13731() {
enum A { A(()) }
static B: A = A(());
match A(()) {
B => ()
}
}
fn issue_15393() {
#![allow(dead_code)]
struct Flags {
bits: uint
}
static FOO: Flags = Flags { bits: 0x01 };
static BAR: Flags = Flags { bits: 0x02 };
match (Flags { bits: 0x02 }) {
FOO => unreachable!(),
BAR => (),
_ => unreachable!()
}
}
fn main() {
assert_eq!(match (true, false) {
TRUE_TRUE => 1i,
(false, false) => 2,
(false, true) => 3,
(true, false) => 4
}, 4);
assert_eq!(match Some(Some(North)) {
Some(NONE) => 1i,
Some(Some(North)) => 2,
Some(Some(EAST)) => 3,
Some(Some(South)) => 4,
Some(Some(West)) => 5,
None => 6
}, 2);
assert_eq!(match (Foo { bar: Some(West), baz: NewBool(true) }) {
Foo { bar: None, baz: NewBool(true) } => 1i,
Foo { bar: NONE, baz: NEW_FALSE } => 2,
STATIC_FOO => 3,
Foo { bar: _, baz: NEW_FALSE } => 4,
Foo { bar: Some(West), baz: NewBool(true) } => 5,
Foo { bar: Some(South), baz: NewBool(true) } => 6,
Foo { bar: Some(EAST), .. } => 7,
Foo { bar: Some(North), baz: NewBool(true) } => 8
}, 5);
assert_eq!(match (Variant2 { dir: North }) {
Variant1(true) => 1i,
Variant1(false) => 2,
Variant2 { dir: West } => 3,
VARIANT2_NORTH => 4,
Variant2 { dir: South } => 5,
Variant2 { dir: East } => 6
}, 4);
issue_6533();
issue_13626();
issue_13731();
issue_14576();
issue_15393();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册