diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 92d1c176a1b92..2a7f7e8c54dd1 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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 { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 066837afac94a..67208e3337286 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -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 std::iter::range_inclusive; 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 @@ impl fmt::Show for Matrix { } } +impl FromIterator>> for Matrix { + fn from_iter>>>(mut iterator: T) -> Matrix { + Matrix(iterator.collect()) + } +} + pub struct MatchCheckCtxt<'a> { pub tcx: &'a ty::ctxt } @@ -120,10 +127,8 @@ impl<'a> Visitor<()> for MatchCheckCtxt<'a> { } 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) -> Gc { } } -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 { } } -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) -> Gc { + 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, 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 { + from: &const_val, to: &const_val) -> Option { 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], &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], // 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", diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 7567e73b01de9..4d256549a6465 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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::visit; 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) -> Gc { + 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, diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 2d53d742ee44b..faaffc7525786 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -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; @@ -116,3 +118,15 @@ pub fn simple_identifier<'a>(pat: &'a Pat) -> Option<&'a Ident> { pub fn wild() -> Gc { 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, + }) +} diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index f1e6db1cab173..cd736197a24cd 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4398,7 +4398,7 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { }); } - 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 @@ impl<'a> Resolver<'a> { 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; } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 75224883cf37f..aeb171c068a85 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -195,6 +195,7 @@ use llvm::{ValueRef, BasicBlockRef}; 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 std::gc::{Gc}; 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), - 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), var(ty::Disr, Rc, ast::DefId), range(Gc, Gc), vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint)) } -fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> Gc { - 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 get_options(bcx: &Block, m: &[Match], col: uint) -> Vec { 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 get_options(bcx: &Block, m: &[Match], col: uint) -> Vec { 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 get_options(bcx: &Block, m: &[Match], col: uint) -> Vec { 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. } diff --git a/src/test/compile-fail/match-arm-statics.rs b/src/test/compile-fail/match-arm-statics.rs new file mode 100644 index 0000000000000..69cb626b75a46 --- /dev/null +++ b/src/test/compile-fail/match-arm-statics.rs @@ -0,0 +1,108 @@ +// 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 or the MIT license +// , 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 = 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, + 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(); +} diff --git a/src/test/compile-fail/static-mut-not-pat.rs b/src/test/compile-fail/static-mut-not-pat.rs index c410e85655258..b3e93daccab8d 100644 --- a/src/test/compile-fail/static-mut-not-pat.rs +++ b/src/test/compile-fail/static-mut-not-pat.rs @@ -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, + 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) } => () } } diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs new file mode 100644 index 0000000000000..a8f6d9c391744 --- /dev/null +++ b/src/test/run-pass/match-arm-statics.rs @@ -0,0 +1,156 @@ +// 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 or the MIT license +// , 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, + baz: NewBool +} +enum EnumWithStructVariants { + Variant1(bool), + Variant2 { + dir: Direction + } +} + +static TRUE_TRUE: (bool, bool) = (true, true); +static NONE: Option = 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(); +}