diff --git a/doc/tutorial.md b/doc/tutorial.md index 40e276ae04a..f4264b0d5af 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -1305,7 +1305,7 @@ match crayons[0] { A vector can be destructured using pattern matching: ~~~~ -let numbers: [int, ..3] = [1, 2, 3]; +let numbers: &[int] = &[1, 2, 3]; let score = match numbers { [] => 0, [a] => a * 10, @@ -2195,7 +2195,7 @@ use std::float::consts::pi; # impl Shape for CircleStruct { fn area(&self) -> float { pi * square(self.radius) } } let concrete = @CircleStruct{center:Point{x:3f,y:4f},radius:5f}; -let mycircle: Circle = concrete as @Circle; +let mycircle: @Circle = concrete as @Circle; let nonsense = mycircle.radius() * mycircle.area(); ~~~ diff --git a/src/etc/emacs/rust-mode.el b/src/etc/emacs/rust-mode.el index 87c505e69d0..ecb223f896c 100644 --- a/src/etc/emacs/rust-mode.el +++ b/src/etc/emacs/rust-mode.el @@ -29,6 +29,11 @@ table)) +(defcustom rust-indent-offset default-tab-width + "*Indent Rust code by this number of spaces. + +The initializer is `DEFAULT-TAB-WIDTH'.") + (defun rust-paren-level () (nth 0 (syntax-ppss))) (defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss))) (defun rust-rewind-past-str-cmnt () (goto-char (nth 8 (syntax-ppss)))) @@ -49,10 +54,10 @@ (let ((level (rust-paren-level))) (cond ;; A function return type is 1 level indented - ((looking-at "->") (* default-tab-width (+ level 1))) + ((looking-at "->") (* rust-indent-offset (+ level 1))) ;; A closing brace is 1 level unindended - ((looking-at "}") (* default-tab-width (- level 1))) + ((looking-at "}") (* rust-indent-offset (- level 1))) ;; If we're in any other token-tree / sexp, then: ;; - [ or ( means line up with the opening token @@ -70,18 +75,18 @@ (goto-char pt) (back-to-indentation) (if (looking-at "\\") - (* default-tab-width (+ 1 level)) + (* rust-indent-offset (+ 1 level)) (progn (goto-char pt) (beginning-of-line) (rust-rewind-irrelevant) (end-of-line) (if (looking-back "[{};,]") - (* default-tab-width level) + (* rust-indent-offset level) (back-to-indentation) (if (looking-at "#") - (* default-tab-width level) - (* default-tab-width (+ 1 level)))))))))) + (* rust-indent-offset level) + (* rust-indent-offset (+ 1 level)))))))))) ;; Otherwise we're in a column-zero definition (t 0)))))) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index b640181515b..37f45142a11 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -255,6 +255,9 @@ pub fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful { } not_useful } + ty::ty_evec(_, ty::vstore_fixed(n)) => { + is_useful_specialized(cx, m, v, vec(n), n, left_ty) + } ty::ty_unboxed_vec(*) | ty::ty_evec(*) => { let max_len = do m.rev_iter().fold(0) |max_len, r| { match r[0].node { @@ -409,6 +412,29 @@ pub fn missing_ctor(cx: &MatchCheckCtxt, else if true_found { Some(val(const_bool(false))) } else { Some(val(const_bool(true))) } } + ty::ty_evec(_, ty::vstore_fixed(n)) => { + let mut missing = true; + let mut wrong = false; + for r in m.iter() { + match r[0].node { + pat_vec(ref before, ref slice, ref after) => { + let count = before.len() + after.len(); + if (count < n && slice.is_none()) || count > n { + wrong = true; + } + if count == n || (count < n && slice.is_some()) { + missing = false; + } + } + _ => {} + } + } + match (wrong, missing) { + (true, _) => Some(vec(n)), // should be compile-time error + (_, true) => Some(vec(n)), + _ => None + } + } ty::ty_unboxed_vec(*) | ty::ty_evec(*) => { // Find the lengths and slices of all vector patterns. diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 9ffeb99ac35..a4b88870b97 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -403,6 +403,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, // Ditto match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx, base))).sty { + ty_enum(id, _) | ty_struct(id, _) if id.crate != LOCAL_CRATE || !privileged_items.iter().any(|x| x == &(id.node)) => { diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 1a9c36313df..c98d859337c 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -145,6 +145,51 @@ * - `store_non_ref_bindings()` * - `insert_lllocals()` * + * + * ## Notes on vector pattern matching. + * + * Vector pattern matching is surprisingly tricky. The problem is that + * the structure of the vector isn't fully known, and slice matches + * can be done on subparts of it. + * + * The way that vector pattern matches are dealt with, then, is as + * follows. First, we make the actual condition associated with a + * vector pattern simply a vector length comparison. So the pattern + * [1, .. x] gets the condition "vec len >= 1", and the pattern + * [.. x] gets the condition "vec len >= 0". The problem here is that + * having the condition "vec len >= 1" hold clearly does not mean that + * only a pattern that has exactly that condition will match. This + * means that it may well be the case that a condition holds, but none + * of the patterns matching that condition match; to deal with this, + * when doing vector length matches, we have match failures proceed to + * the next condition to check. + * + * There are a couple more subtleties to deal with. While the "actual" + * condition associated with vector length tests is simply a test on + * the vector length, the actual vec_len Opt entry contains more + * information used to restrict which matches are associated with it. + * So that all matches in a submatch are matching against the same + * values from inside the vector, they are split up by how many + * elements they match at the front and at the back of the vector. In + * order to make sure that arms are properly checked in order, even + * with the overmatching conditions, each vec_len Opt entry is + * associated with a range of matches. + * Consider the following: + * + * match &[1, 2, 3] { + * [1, 1, .. _] => 0, + * [1, 2, 2, .. _] => 1, + * [1, 2, 3, .. _] => 2, + * [1, 2, .. _] => 3, + * _ => 4 + * } + * The proper arm to match is arm 2, but arms 0 and 3 both have the + * condition "len >= 2". If arm 3 was lumped in with arm 0, then the + * wrong branch would be taken. Instead, vec_len Opts are associated + * with a contiguous range of matches that have the same "shape". + * This is sort of ugly and requires a bunch of special handling of + * vec_len options. + * */ @@ -189,14 +234,19 @@ enum Lit { ConstLit(ast::def_id), // the def ID of the constant } +#[deriving(Eq)] +pub enum VecLenOpt { + vec_len_eq, + vec_len_ge(/* length of prefix */uint) +} + // An option identifying a branch (either a literal, a enum variant or a // range) enum Opt { lit(Lit), var(/* disr val */ uint, @adt::Repr), range(@ast::expr, @ast::expr), - vec_len_eq(uint), - vec_len_ge(uint, /* slice */uint) + vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint)) } fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { @@ -247,9 +297,9 @@ fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { } } (&var(a, _), &var(b, _)) => a == b, - (&vec_len_eq(a), &vec_len_eq(b)) => a == b, - (&vec_len_ge(a, _), &vec_len_ge(b, _)) => a == b, - _ => false + (&vec_len(a1, a2, _), &vec_len(b1, b2, _)) => + a1 == b1 && a2 == b2, + _ => false } } @@ -283,10 +333,10 @@ fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result { return range_result(rslt(bcx, consts::const_expr(ccx, l1)), rslt(bcx, consts::const_expr(ccx, l2))); } - vec_len_eq(n) => { + vec_len(n, vec_len_eq, _) => { return single_result(rslt(bcx, C_int(ccx, n as int))); } - vec_len_ge(n, _) => { + vec_len(n, vec_len_ge(_), _) => { return lower_bound(rslt(bcx, C_int(ccx, n as int))); } } @@ -471,10 +521,11 @@ fn enter_match<'r>(bcx: @mut Block, } fn enter_default<'r>(bcx: @mut Block, - dm: DefMap, - m: &[Match<'r>], - col: uint, - val: ValueRef) + dm: DefMap, + m: &[Match<'r>], + col: uint, + val: ValueRef, + chk: Option) -> ~[Match<'r>] { debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)", bcx.to_str(), @@ -483,13 +534,36 @@ fn enter_default<'r>(bcx: @mut Block, bcx.val_to_str(val)); let _indenter = indenter(); - do enter_match(bcx, dm, m, col, val) |p| { + // Collect all of the matches that can match against anything. + let matches = do enter_match(bcx, dm, m, col, val) |p| { match p.node { ast::pat_wild | ast::pat_tup(_) => Some(~[]), ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]), _ => None } - } + }; + + // Ok, now, this is pretty subtle. A "default" match is a match + // that needs to be considered if none of the actual checks on the + // value being considered succeed. The subtlety lies in that sometimes + // identifier/wildcard matches are *not* default matches. Consider: + // "match x { _ if something => foo, true => bar, false => baz }". + // There is a wildcard match, but it is *not* a default case. The boolean + // case on the value being considered is exhaustive. If the case is + // exhaustive, then there are no defaults. + // + // We detect whether the case is exhaustive in the following + // somewhat kludgy way: if the last wildcard/binding match has a + // guard, then by non-redundancy, we know that there aren't any + // non guarded matches, and thus by exhaustiveness, we know that + // we don't need any default cases. If the check *isn't* nonexhaustive + // (because chk is Some), then we need the defaults anyways. + let is_exhaustive = match matches.last_opt() { + Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true, + _ => false + }; + + if is_exhaustive { ~[] } else { matches } } // nmatsakis: what does enter_opt do? @@ -523,17 +597,19 @@ fn enter_opt<'r>(bcx: @mut Block, variant_size: uint, val: ValueRef) -> ~[Match<'r>] { - debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%s)", + debug!("enter_opt(bcx=%s, m=%s, opt=%?, col=%u, val=%s)", bcx.to_str(), m.repr(bcx.tcx()), + *opt, col, bcx.val_to_str(val)); let _indenter = indenter(); let tcx = bcx.tcx(); let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; + let mut i = 0; do enter_match(bcx, tcx.def_map, m, col, val) |p| { - match p.node { + let answer = match p.node { ast::pat_enum(*) | ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => { let const_def = tcx.def_map.get_copy(&p.id); @@ -599,32 +675,53 @@ fn enter_opt<'r>(bcx: @mut Block, } } ast::pat_vec(ref before, slice, ref after) => { + let (lo, hi) = match *opt { + vec_len(_, _, (lo, hi)) => (lo, hi), + _ => tcx.sess.span_bug(p.span, + "vec pattern but not vec opt") + }; + match slice { - Some(slice) => { + Some(slice) if i >= lo && i <= hi => { let n = before.len() + after.len(); - let i = before.len(); - if opt_eq(tcx, &vec_len_ge(n, i), opt) { + let this_opt = vec_len(n, vec_len_ge(before.len()), + (lo, hi)); + if opt_eq(tcx, &this_opt, opt) { Some(vec::append_one((*before).clone(), slice) + *after) } else { None } } - None => { + None if i >= lo && i <= hi => { let n = before.len(); - if opt_eq(tcx, &vec_len_eq(n), opt) { + if opt_eq(tcx, &vec_len(n, vec_len_eq, (lo,hi)), opt) { Some((*before).clone()) } else { None } } + _ => None } } _ => { assert_is_binding_or_wild(bcx, p); - Some(vec::from_elem(variant_size, dummy)) + // In most cases, a binding/wildcard match be + // considered to match against any Opt. However, when + // doing vector pattern matching, submatches are + // considered even if the eventual match might be from + // a different submatch. Thus, when a submatch fails + // when doing a vector match, we proceed to the next + // submatch. Thus, including a default match would + // cause the default match to fire spuriously. + match *opt { + vec_len(*) => None, + _ => Some(vec::from_elem(variant_size, dummy)) + } } - } + }; + i += 1; + answer } } @@ -805,9 +902,25 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { if set.iter().any(|l| opt_eq(tcx, l, &val)) {return;} set.push(val); } + // Vector comparisions are special in that since the actual + // conditions over-match, we need to be careful about them. This + // means that in order to properly handle things in order, we need + // to not always merge conditions. + fn add_veclen_to_set(set: &mut ~[Opt], i: uint, + len: uint, vlo: VecLenOpt) { + match set.last_opt() { + // If the last condition in the list matches the one we want + // to add, then extend its range. Otherwise, make a new + // vec_len with a range just covering the new entry. + Some(&vec_len(len2, vlo2, (start, end))) + if len == len2 && vlo == vlo2 => + set[set.len() - 1] = vec_len(len, vlo, (start, end+1)), + _ => set.push(vec_len(len, vlo, (i, i))) + } + } let mut found = ~[]; - for br in m.iter() { + for (i, br) in m.iter().enumerate() { let cur = br.pats[col]; match cur.node { ast::pat_lit(l) => { @@ -852,12 +965,12 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { add_to_set(ccx.tcx, &mut found, range(l1, l2)); } ast::pat_vec(ref before, slice, ref after) => { - let opt = match slice { - None => vec_len_eq(before.len()), - Some(_) => vec_len_ge(before.len() + after.len(), - before.len()) + let (len, vec_opt) = match slice { + None => (before.len(), vec_len_eq), + Some(_) => (before.len() + after.len(), + vec_len_ge(before.len())) }; - add_to_set(ccx.tcx, &mut found, opt); + add_veclen_to_set(&mut found, i, len, vec_opt); } _ => {} } @@ -1075,13 +1188,13 @@ fn pick_col(m: &[Match]) -> uint { } let mut scores = vec::from_elem(m[0].pats.len(), 0u); for br in m.iter() { - let mut i = 0u; - for p in br.pats.iter() { scores[i] += score(*p); i += 1u; } + for (i, p) in br.pats.iter().enumerate() { + scores[i] += score(*p); + } } let mut max_score = 0u; let mut best_col = 0u; - let mut i = 0u; - for score in scores.iter() { + for (i, score) in scores.iter().enumerate() { let score = *score; // Irrefutable columns always go first, they'd only be duplicated in @@ -1090,7 +1203,6 @@ fn pick_col(m: &[Match]) -> uint { // If no irrefutable ones are found, we pick the one with the biggest // branching factor. if score > max_score { max_score = score; best_col = i; } - i += 1u; } return best_col; } @@ -1460,7 +1572,7 @@ fn compile_submatch_continue(mut bcx: @mut Block, test_val = Load(bcx, val); kind = compare; }, - vec_len_eq(*) | vec_len_ge(*) => { + vec_len(*) => { let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); let unboxed = load_if_immediate(bcx, val, vt.vec_ty); let (_, len) = tvec::get_base_and_len( @@ -1487,16 +1599,19 @@ fn compile_submatch_continue(mut bcx: @mut Block, C_int(ccx, 0) // Placeholder for when not using a switch }; - let defaults = enter_default(else_cx, dm, m, col, val); + let defaults = enter_default(else_cx, dm, m, col, val, chk); let exhaustive = chk.is_none() && defaults.len() == 0u; let len = opts.len(); - let mut i = 0u; // Compile subtrees for each option - for opt in opts.iter() { - i += 1u; + for (i, opt) in opts.iter().enumerate() { + // In some cases in vector pattern matching, we need to override + // the failure case so that instead of failing, it proceeds to + // try more matching. branch_chk, then, is the proper failure case + // for the current conditional branch. + let mut branch_chk = chk; let mut opt_cx = else_cx; - if !exhaustive || i < len { + if !exhaustive || i+1 < len { opt_cx = sub_block(bcx, "match_case"); match kind { single => Br(bcx, opt_cx.llbb), @@ -1586,6 +1701,10 @@ fn compile_submatch_continue(mut bcx: @mut Block, } }; bcx = sub_block(after_cx, "compare_vec_len_next"); + + // If none of these subcases match, move on to the + // next condition. + branch_chk = Some::(|| bcx.llbb); CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb); } _ => () @@ -1604,17 +1723,13 @@ fn compile_submatch_continue(mut bcx: @mut Block, unpacked = argvals; opt_cx = new_bcx; } - vec_len_eq(n) | vec_len_ge(n, _) => { - let n = match *opt { - vec_len_ge(*) => n + 1u, - _ => n + vec_len(n, vt, _) => { + let (n, slice) = match vt { + vec_len_ge(i) => (n + 1u, Some(i)), + vec_len_eq => (n, None) }; - let slice = match *opt { - vec_len_ge(_, i) => Some(i), - _ => None - }; - let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice, - val, test_val); + let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, + slice, val, test_val); size = args.vals.len(); unpacked = args.vals.clone(); opt_cx = args.bcx; @@ -1623,7 +1738,7 @@ fn compile_submatch_continue(mut bcx: @mut Block, } let opt_ms = enter_opt(opt_cx, m, opt, col, size, val); let opt_vals = vec::append(unpacked, vals_left); - compile_submatch(opt_cx, opt_ms, opt_vals, chk); + compile_submatch(opt_cx, opt_ms, opt_vals, branch_chk); } // Compile the fall-through case, if any diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 0bfee145a3c..da1fb9abaee 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -156,6 +156,53 @@ impl TrieMap { remaining_max: self.length } } + + // If `upper` is true then returns upper_bound else returns lower_bound. + #[inline] + fn bound_iter<'a>(&'a self, key: uint, upper: bool) -> TrieMapIterator<'a, T> { + let mut node: &'a TrieNode = &self.root; + let mut idx = 0; + let mut it = TrieMapIterator { + stack: ~[], + remaining_min: 0, + remaining_max: self.length + }; + loop { + let children = &node.children; + let child_id = chunk(key, idx); + match children[child_id] { + Internal(ref n) => { + node = &**n; + it.stack.push(children.slice_from(child_id + 1).iter()); + } + External(stored, _) => { + if stored < key || (upper && stored == key) { + it.stack.push(children.slice_from(child_id + 1).iter()); + } else { + it.stack.push(children.slice_from(child_id).iter()); + } + return it; + } + Nothing => { + it.stack.push(children.slice_from(child_id + 1).iter()); + return it + } + } + idx += 1; + } + } + + /// Get an iterator pointing to the first key-value pair whose key is not less than `key`. + /// If all keys in the map are less than `key` an empty iterator is returned. + pub fn lower_bound_iter<'a>(&'a self, key: uint) -> TrieMapIterator<'a, T> { + self.bound_iter(key, false) + } + + /// Get an iterator pointing to the first key-value pair whose key is greater than `key`. + /// If all keys in the map are not greater than `key` an empty iterator is returned. + pub fn upper_bound_iter<'a>(&'a self, key: uint) -> TrieMapIterator<'a, T> { + self.bound_iter(key, true) + } } impl> FromIterator<(uint, T), Iter> for TrieMap { @@ -233,6 +280,18 @@ impl TrieSet { pub fn iter<'a>(&'a self) -> TrieSetIterator<'a> { TrieSetIterator{iter: self.map.iter()} } + + /// Get an iterator pointing to the first value that is not less than `val`. + /// If all values in the set are less than `val` an empty iterator is returned. + pub fn lower_bound_iter<'a>(&'a self, val: uint) -> TrieSetIterator<'a> { + TrieSetIterator{iter: self.map.lower_bound_iter(val)} + } + + /// Get an iterator pointing to the first value that key is greater than `val`. + /// If all values in the set are not greater than `val` an empty iterator is returned. + pub fn upper_bound_iter<'a>(&'a self, val: uint) -> TrieSetIterator<'a> { + TrieSetIterator{iter: self.map.upper_bound_iter(val)} + } } impl> FromIterator for TrieSet { @@ -645,6 +704,49 @@ mod test_map { } assert_eq!(i, last - first); } + + #[test] + fn test_bound_iter() { + let empty_map : TrieMap = TrieMap::new(); + assert_eq!(empty_map.lower_bound_iter(0).next(), None); + assert_eq!(empty_map.upper_bound_iter(0).next(), None); + + let last = 999u; + let step = 3u; + let value = 42u; + + let mut map : TrieMap = TrieMap::new(); + do uint::range_step(0u, last, step as int) |x| { + assert!(x % step == 0); + map.insert(x, value); + true + }; + + for i in range(0u, last - step) { + let mut lb = map.lower_bound_iter(i); + let mut ub = map.upper_bound_iter(i); + let next_key = i - i % step + step; + let next_pair = (next_key, &value); + if (i % step == 0) { + assert_eq!(lb.next(), Some((i, &value))); + } else { + assert_eq!(lb.next(), Some(next_pair)); + } + assert_eq!(ub.next(), Some(next_pair)); + } + + let mut lb = map.lower_bound_iter(last - step); + assert_eq!(lb.next(), Some((last - step, &value))); + let mut ub = map.upper_bound_iter(last - step); + assert_eq!(ub.next(), None); + + for i in range(last - step + 1, last) { + let mut lb = map.lower_bound_iter(i); + assert_eq!(lb.next(), None); + let mut ub = map.upper_bound_iter(i); + assert_eq!(ub.next(), None); + } + } } #[cfg(test)] diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1e696451701..dfaffa0c275 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -421,12 +421,12 @@ pub enum MapChain { // get the map from an env frame impl MapChain{ // Constructor. I don't think we need a zero-arg one. - fn new(init: ~HashMap) -> @mut MapChain { + pub fn new(init: ~HashMap) -> @mut MapChain { @mut BaseMapChain(init) } // add a new frame to the environment (functionally) - fn push_frame (@mut self) -> @mut MapChain { + pub fn push_frame (@mut self) -> @mut MapChain { @mut ConsMapChain(~HashMap::new() ,self) } @@ -436,7 +436,7 @@ impl MapChain{ // ugh: can't get this to compile with mut because of the // lack of flow sensitivity. - fn get_map<'a>(&'a self) -> &'a HashMap { + pub fn get_map<'a>(&'a self) -> &'a HashMap { match *self { BaseMapChain (~ref map) => map, ConsMapChain (~ref map,_) => map @@ -446,7 +446,7 @@ impl MapChain{ // traits just don't work anywhere...? //impl Map for MapChain { - fn contains_key (&self, key: &K) -> bool { + pub fn contains_key (&self, key: &K) -> bool { match *self { BaseMapChain (ref map) => map.contains_key(key), ConsMapChain (ref map,ref rest) => @@ -457,17 +457,17 @@ impl MapChain{ // should each_key and each_value operate on shadowed // names? I think not. // delaying implementing this.... - fn each_key (&self, _f: &fn (&K)->bool) { + pub fn each_key (&self, _f: &fn (&K)->bool) { fail!("unimplemented 2013-02-15T10:01"); } - fn each_value (&self, _f: &fn (&V) -> bool) { + pub fn each_value (&self, _f: &fn (&V) -> bool) { fail!("unimplemented 2013-02-15T10:02"); } // Returns a copy of the value that the name maps to. // Goes down the chain 'til it finds one (or bottom out). - fn find (&self, key: &K) -> Option<@V> { + pub fn find (&self, key: &K) -> Option<@V> { match self.get_map().find (key) { Some(ref v) => Some(**v), None => match *self { @@ -477,7 +477,7 @@ impl MapChain{ } } - fn find_in_topmost_frame(&self, key: &K) -> Option<@V> { + pub fn find_in_topmost_frame(&self, key: &K) -> Option<@V> { let map = match *self { BaseMapChain(ref map) => map, ConsMapChain(ref map,_) => map @@ -487,7 +487,7 @@ impl MapChain{ } // insert the binding into the top-level map - fn insert (&mut self, key: K, ext: @V) -> bool { + pub fn insert (&mut self, key: K, ext: @V) -> bool { // can't abstract over get_map because of flow sensitivity... match *self { BaseMapChain (~ref mut map) => map.insert(key, ext), @@ -499,7 +499,7 @@ impl MapChain{ // ... there are definitely some opportunities for abstraction // here that I'm ignoring. (e.g., manufacturing a predicate on // the maps in the chain, and using an abstract "find". - fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) { + pub fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) { match *self { BaseMapChain (~ref mut map) => { if satisfies_pred(map,&n,pred) { diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 5a1317034b2..918949113ad 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -17,6 +17,7 @@ use codemap; use parse::lexer::*; //resolve bug? use parse::ParseSess; use parse::parser::Parser; +use parse::attr::parser_attr; use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str}; use parse::token; @@ -430,6 +431,7 @@ pub fn parse_nt(p: &Parser, name: &str) -> nonterminal { + token::to_str(get_ident_interner(), p.token)) }, "path" => token::nt_path(p.parse_path_with_tps(false)), + "attr" => token::nt_attr(@p.parse_attribute(false)), "tt" => { *p.quote_depth += 1u; //but in theory, non-quoted tts might be useful let res = token::nt_tt(@p.parse_token_tree()); diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 5d79532c8c5..3a10206b513 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -36,7 +36,7 @@ pub fn from(t: ~[T]) -> OptVec { } impl OptVec { - fn push(&mut self, t: T) { + pub fn push(&mut self, t: T) { match *self { Vec(ref mut v) => { v.push(t); @@ -50,32 +50,32 @@ impl OptVec { *self = Vec(~[t]); } - fn map(&self, op: &fn(&T) -> U) -> OptVec { + pub fn map(&self, op: &fn(&T) -> U) -> OptVec { match *self { Empty => Empty, Vec(ref v) => Vec(v.map(op)) } } - fn map_move(self, op: &fn(T) -> U) -> OptVec { + pub fn map_move(self, op: &fn(T) -> U) -> OptVec { match self { Empty => Empty, Vec(v) => Vec(v.move_iter().map(op).collect()) } } - fn get<'a>(&'a self, i: uint) -> &'a T { + pub fn get<'a>(&'a self, i: uint) -> &'a T { match *self { Empty => fail!("Invalid index %u", i), Vec(ref v) => &v[i] } } - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.len() == 0 } - fn len(&self) -> uint { + pub fn len(&self) -> uint { match *self { Empty => 0, Vec(ref v) => v.len() @@ -83,7 +83,7 @@ impl OptVec { } #[inline] - fn iter<'r>(&'r self) -> OptVecIterator<'r, T> { + pub fn iter<'r>(&'r self) -> OptVecIterator<'r, T> { match *self { Empty => OptVecIterator{iter: None}, Vec(ref v) => OptVecIterator{iter: Some(v.iter())} @@ -91,11 +91,11 @@ impl OptVec { } #[inline] - fn map_to_vec(&self, op: &fn(&T) -> B) -> ~[B] { + pub fn map_to_vec(&self, op: &fn(&T) -> B) -> ~[B] { self.iter().map(op).collect() } - fn mapi_to_vec(&self, op: &fn(uint, &T) -> B) -> ~[B] { + pub fn mapi_to_vec(&self, op: &fn(uint, &T) -> B) -> ~[B] { let mut index = 0; self.map_to_vec(|a| { let i = index; @@ -113,7 +113,7 @@ pub fn take_vec(v: OptVec) -> ~[T] { } impl OptVec { - fn prepend(&self, t: T) -> OptVec { + pub fn prepend(&self, t: T) -> OptVec { let mut v0 = ~[t]; match *self { Empty => {} @@ -124,7 +124,7 @@ impl OptVec { } impl Eq for OptVec { - fn eq(&self, other: &OptVec) -> bool { + pub fn eq(&self, other: &OptVec) -> bool { // Note: cannot use #[deriving(Eq)] here because // (Empty, Vec(~[])) ought to be equal. match (self, other) { @@ -135,7 +135,7 @@ impl Eq for OptVec { } } - fn ne(&self, other: &OptVec) -> bool { + pub fn ne(&self, other: &OptVec) -> bool { !self.eq(other) } } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 8cce5f15e67..f2489d80e1e 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -9,21 +9,17 @@ // except according to those terms. use ast; -use codemap::spanned; +use codemap::{spanned, mk_sp}; use codemap::BytePos; use parse::common::*; //resolve bug? use parse::token; use parse::parser::Parser; +use parse::token::INTERPOLATED; // a parser that can parse attributes. pub trait parser_attr { fn parse_outer_attributes(&self) -> ~[ast::Attribute]; - fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute; - fn parse_attribute_naked( - &self, - style: ast::AttrStyle, - lo: BytePos - ) -> ast::Attribute; + fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute; fn parse_inner_attrs_and_next(&self) -> (~[ast::Attribute], ~[ast::Attribute]); fn parse_meta_item(&self) -> @ast::MetaItem; @@ -37,12 +33,17 @@ impl parser_attr for Parser { fn parse_outer_attributes(&self) -> ~[ast::Attribute] { let mut attrs: ~[ast::Attribute] = ~[]; loop { + debug!("parse_outer_attributes: self.token=%?", + self.token); match *self.token { + token::INTERPOLATED(token::nt_attr(*)) => { + attrs.push(self.parse_attribute(false)); + } token::POUND => { if self.look_ahead(1, |t| *t != token::LBRACKET) { break; } - attrs.push(self.parse_attribute(ast::AttrOuter)); + attrs.push(self.parse_attribute(false)); } token::DOC_COMMENT(s) => { let attr = ::attr::mk_sugared_doc_attr( @@ -62,23 +63,49 @@ impl parser_attr for Parser { return attrs; } - // matches attribute = # attribute_naked - fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute { - let lo = self.span.lo; - self.expect(&token::POUND); - return self.parse_attribute_naked(style, lo); + // matches attribute = # [ meta_item ] + // + // if permit_inner is true, then a trailing `;` indicates an inner + // attribute + fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute { + debug!("parse_attributes: permit_inner=%? self.token=%?", + permit_inner, self.token); + let (span, value) = match *self.token { + INTERPOLATED(token::nt_attr(attr)) => { + assert!(attr.node.style == ast::AttrOuter); + self.bump(); + (attr.span, attr.node.value) + } + token::POUND => { + let lo = self.span.lo; + self.bump(); + self.expect(&token::LBRACKET); + let meta_item = self.parse_meta_item(); + self.expect(&token::RBRACKET); + let hi = self.span.hi; + (mk_sp(lo, hi), meta_item) + } + _ => { + self.fatal(fmt!("expected `#` but found `%s`", + self.this_token_to_str())); + } + }; + let style = if permit_inner && *self.token == token::SEMI { + self.bump(); + ast::AttrInner + } else { + ast::AttrOuter + }; + return spanned { + span: span, + node: ast::Attribute_ { + style: style, + value: value, + is_sugared_doc: false + } + }; } - // matches attribute_naked = [ meta_item ] - fn parse_attribute_naked(&self, style: ast::AttrStyle, lo: BytePos) -> - ast::Attribute { - self.expect(&token::LBRACKET); - let meta_item = self.parse_meta_item(); - self.expect(&token::RBRACKET); - let hi = self.span.hi; - return spanned(lo, hi, ast::Attribute_ { style: style, - value: meta_item, is_sugared_doc: false }); } - // Parse attributes that appear after the opening of an item, each // terminated by a semicolon. In addition to a vector of inner attributes, // this function also returns a vector that may contain the first outer @@ -89,47 +116,37 @@ impl parser_attr for Parser { // matches inner_attrs* outer_attr? // you can make the 'next' field an Option, but the result is going to be // more useful as a vector. - fn parse_inner_attrs_and_next(&self) -> - (~[ast::Attribute], ~[ast::Attribute]) { + fn parse_inner_attrs_and_next(&self) + -> (~[ast::Attribute], ~[ast::Attribute]) { let mut inner_attrs: ~[ast::Attribute] = ~[]; let mut next_outer_attrs: ~[ast::Attribute] = ~[]; loop { - match *self.token { - token::POUND => { - if self.look_ahead(1, |t| *t != token::LBRACKET) { - // This is an extension - break; + let attr = match *self.token { + token::INTERPOLATED(token::nt_attr(*)) => { + self.parse_attribute(true) } - let attr = self.parse_attribute(ast::AttrInner); - if *self.token == token::SEMI { + token::POUND => { + if self.look_ahead(1, |t| *t != token::LBRACKET) { + // This is an extension + break; + } + self.parse_attribute(true) + } + token::DOC_COMMENT(s) => { self.bump(); - inner_attrs.push(attr); - } else { - // It's not really an inner attribute - let outer_attr = - spanned(attr.span.lo, attr.span.hi, - ast::Attribute_ { style: ast::AttrOuter, - value: attr.node.value, - is_sugared_doc: false }); - next_outer_attrs.push(outer_attr); + ::attr::mk_sugared_doc_attr(self.id_to_str(s), + self.span.lo, + self.span.hi) + } + _ => { break; } - } - token::DOC_COMMENT(s) => { - let attr = ::attr::mk_sugared_doc_attr( - self.id_to_str(s), - self.span.lo, - self.span.hi - ); - self.bump(); - if attr.node.style == ast::AttrInner { - inner_attrs.push(attr); - } else { - next_outer_attrs.push(attr); - break; - } - } - _ => break + }; + if attr.node.style == ast::AttrInner { + inner_attrs.push(attr); + } else { + next_outer_attrs.push(attr); + break; } } (inner_attrs, next_outer_attrs) diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 49deafeda40..bde568b2610 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -129,7 +129,11 @@ impl reader for StringReader { impl reader for TtReader { fn is_eof(@mut self) -> bool { self.cur_tok == token::EOF } - fn next_token(@mut self) -> TokenAndSpan { tt_next_token(self) } + fn next_token(@mut self) -> TokenAndSpan { + let r = tt_next_token(self); + debug!("TtReader: r=%?", r); + return r; + } fn fatal(@mut self, m: ~str) -> ! { self.sp_diag.span_fatal(self.cur_span, m); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d1916088a41..77c50a779c0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[macro_escape]; + use abi; use abi::AbiSet; use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil}; @@ -4460,7 +4462,17 @@ impl Parser { attrs: ~[Attribute], macros_allowed: bool) -> item_or_view_item { - maybe_whole!(iovi self, nt_item); + match *self.token { + INTERPOLATED(token::nt_item(item)) => { + self.bump(); + let new_attrs = vec::append(attrs, item.attrs); + return iovi_item(@ast::item { + attrs: new_attrs, + ..(*item).clone()}); + } + _ => {} + } + let lo = self.span.lo; let visibility = self.parse_non_priv_visibility(); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fd491c1e890..c554f111bf9 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -105,6 +105,7 @@ pub enum nonterminal { nt_expr(@ast::expr), nt_ty( ast::Ty), nt_ident(ast::ident, bool), + nt_attr(@ast::Attribute), // #[foo] nt_path( ast::Path), nt_tt( @ast::token_tree), //needs @ed to break a circularity nt_matchers(~[ast::matcher]) @@ -205,6 +206,7 @@ pub fn to_str(input: @ident_interner, t: &Token) -> ~str { INTERPOLATED(ref nt) => { match nt { &nt_expr(e) => ::print::pprust::expr_to_str(e, input), + &nt_attr(e) => ::print::pprust::attribute_to_str(e, input), _ => { ~"an interpolated " + match (*nt) { @@ -212,6 +214,7 @@ pub fn to_str(input: @ident_interner, t: &Token) -> ~str { nt_block(*) => ~"block", nt_stmt(*) => ~"statement", nt_pat(*) => ~"pattern", + nt_attr(*) => fail!("should have been handled"), nt_expr(*) => fail!("should have been handled above"), nt_ty(*) => ~"type", nt_ident(*) => ~"identifier", diff --git a/src/test/auxiliary/xc_private_method_lib.rs b/src/test/auxiliary/xc_private_method_lib.rs index 05325c3b935..8290f62bada 100644 --- a/src/test/auxiliary/xc_private_method_lib.rs +++ b/src/test/auxiliary/xc_private_method_lib.rs @@ -1,9 +1,33 @@ #[crate_type="lib"]; -pub struct Foo { +pub struct Struct { x: int } -impl Foo { - fn new() -> Foo { Foo { x: 1 } } +impl Struct { + fn static_meth_struct() -> Struct { + Struct { x: 1 } + } + + fn meth_struct(&self) -> int { + self.x + } +} + +pub enum Enum { + Variant1(int), + Variant2(int) +} + +impl Enum { + fn static_meth_enum() -> Enum { + Variant2(10) + } + + fn meth_enum(&self) -> int { + match *self { + Variant1(x) | + Variant2(x) => x + } + } } diff --git a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs index 39a0e585ad2..0f67d8a6d0c 100644 --- a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs @@ -6,7 +6,7 @@ struct Foo { } pub fn main() { - let x = [ + let x = ~[ Foo { string: ~"foo" }, Foo { string: ~"bar" }, Foo { string: ~"baz" } diff --git a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs index 7f98eba5996..ca20d68e4cd 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs @@ -1,5 +1,5 @@ fn a() -> &[int] { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let tail = match vec { [_, ..tail] => tail, //~ ERROR does not live long enough _ => fail!("a") @@ -8,7 +8,7 @@ fn a() -> &[int] { } fn b() -> &[int] { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let init = match vec { [..init, _] => init, //~ ERROR does not live long enough _ => fail!("b") @@ -17,7 +17,7 @@ fn b() -> &[int] { } fn c() -> &[int] { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let slice = match vec { [_, ..slice, _] => slice, //~ ERROR does not live long enough _ => fail!("c") diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs index 36ae5f88208..02ba1b9d2ff 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -1,24 +1,24 @@ fn a() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [~ref _a] => { - vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed + vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed } _ => fail!("foo") } } fn b() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [.._b] => { - vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed + vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed } } } fn c() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [_a, .._b] => { //~^ ERROR cannot move out @@ -35,7 +35,7 @@ fn c() { } fn d() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [.._a, _b] => { //~^ ERROR cannot move out @@ -46,7 +46,7 @@ fn d() { } fn e() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [_a, _b, _c] => {} _ => {} diff --git a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs index e3e12a4a416..87511c34172 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs @@ -1,5 +1,5 @@ fn a() -> &int { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let tail = match vec { [_a, ..tail] => &tail[0], //~ ERROR borrowed value does not live long enough _ => fail!("foo") diff --git a/src/test/compile-fail/macro-inner-attributes.rs b/src/test/compile-fail/macro-inner-attributes.rs new file mode 100644 index 00000000000..95000f4aa22 --- /dev/null +++ b/src/test/compile-fail/macro-inner-attributes.rs @@ -0,0 +1,21 @@ +macro_rules! test ( ($nm:ident, + $a:attr, + $i:item) => (mod $nm { $a; $i }); ) + +test!(a, + #[cfg(qux)], + pub fn bar() { }) + +test!(b, + #[cfg(not(qux))], + pub fn bar() { }) + +#[qux] +fn main() { + a::bar(); + //~^ ERROR use of undeclared module `a` + //~^^ ERROR unresolved name + //~^^^ ERROR unresolved name `a::bar` + b::bar(); +} + diff --git a/src/test/compile-fail/macro-outer-attributes.rs b/src/test/compile-fail/macro-outer-attributes.rs new file mode 100644 index 00000000000..23c3e80cd3b --- /dev/null +++ b/src/test/compile-fail/macro-outer-attributes.rs @@ -0,0 +1,19 @@ +macro_rules! test ( ($nm:ident, + $a:attr, + $i:item) => (mod $nm { $a $i }); ) + +test!(a, + #[cfg(qux)], + pub fn bar() { }) + +test!(b, + #[cfg(not(qux))], + pub fn bar() { }) + +// test1!(#[bar]) +#[qux] +fn main() { + a::bar(); //~ ERROR unresolved name `a::bar` + b::bar(); +} + diff --git a/src/test/compile-fail/match-vec-fixed.rs b/src/test/compile-fail/match-vec-fixed.rs new file mode 100644 index 00000000000..b3e139805a0 --- /dev/null +++ b/src/test/compile-fail/match-vec-fixed.rs @@ -0,0 +1,16 @@ +fn a() { + let v = [1, 2, 3]; + match v { + [_, _, _] => {} + [_, _, _] => {} //~ ERROR unreachable pattern + } + match v { + [_, 1, _] => {} + [_, 1, _] => {} //~ ERROR unreachable pattern + _ => {} + } +} + +fn main() { + a(); +} diff --git a/src/test/compile-fail/match-vec-unreachable.rs b/src/test/compile-fail/match-vec-unreachable.rs index 3930e7d2192..b557242af44 100644 --- a/src/test/compile-fail/match-vec-unreachable.rs +++ b/src/test/compile-fail/match-vec-unreachable.rs @@ -6,13 +6,13 @@ fn main() { _ => () } - match [~"foo", ~"bar", ~"baz"] { + match ~[~"foo", ~"bar", ~"baz"] { [a, _, _, .._] => { println(a); } [~"foo", ~"bar", ~"baz", ~"foo", ~"bar"] => { } //~ ERROR unreachable pattern _ => { } } - match ['a', 'b', 'c'] { + match ~['a', 'b', 'c'] { ['a', 'b', 'c', .._tail] => {} ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern _ => {} diff --git a/src/test/compile-fail/xc-private-method.rs b/src/test/compile-fail/xc-private-method.rs index e8777a0a9f2..8314755af3b 100644 --- a/src/test/compile-fail/xc-private-method.rs +++ b/src/test/compile-fail/xc-private-method.rs @@ -4,5 +4,13 @@ extern mod xc_private_method_lib; fn main() { - let _ = xc_private_method_lib::Foo::new(); //~ ERROR function `new` is private + // normal method on struct + let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); //~ ERROR method `meth_struct` is private + // static method on struct + let _ = xc_private_method_lib::Struct::static_meth_struct(); //~ ERROR function `static_meth_struct` is private + + // normal method on enum + let _ = xc_private_method_lib::Variant1(20).meth_enum(); //~ ERROR method `meth_enum` is private + // static method on enum + let _ = xc_private_method_lib::Enum::static_meth_enum(); //~ ERROR function `static_meth_enum` is private } diff --git a/src/test/run-pass/issue-3121.rs b/src/test/run-pass/issue-3121.rs index 522a68856b6..206dc383cb3 100644 --- a/src/test/run-pass/issue-3121.rs +++ b/src/test/run-pass/issue-3121.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test enum side { mayo, catsup, vinegar } enum order { hamburger, fries(side), shake } enum meal { to_go(order), for_here(order) } diff --git a/src/test/run-pass/vec-matching-autoslice.rs b/src/test/run-pass/vec-matching-autoslice.rs index d04deeac52e..13a8e324d43 100644 --- a/src/test/run-pass/vec-matching-autoslice.rs +++ b/src/test/run-pass/vec-matching-autoslice.rs @@ -1,22 +1,22 @@ pub fn main() { let x = @[1, 2, 3]; match x { - [2, .._] => ::std::util::unreachable(), + [2, .._] => fail!(), [1, ..tail] => { assert_eq!(tail, [2, 3]); } - [_] => ::std::util::unreachable(), - [] => ::std::util::unreachable() + [_] => fail!(), + [] => fail!() } let y = (~[(1, true), (2, false)], 0.5); match y { - ([_, _, _], 0.5) => ::std::util::unreachable(), + ([_, _, _], 0.5) => fail!(), ([(1, a), (b, false), ..tail], _) => { assert_eq!(a, true); assert_eq!(b, 2); assert!(tail.is_empty()); } - ([..tail], _) => ::std::util::unreachable() + ([..tail], _) => fail!() } } diff --git a/src/test/run-pass/vec-matching-fixed.rs b/src/test/run-pass/vec-matching-fixed.rs new file mode 100644 index 00000000000..234311dec33 --- /dev/null +++ b/src/test/run-pass/vec-matching-fixed.rs @@ -0,0 +1,28 @@ +fn a() { + let x = [1, 2, 3]; + match x { + [1, 2, 4] => ::std::util::unreachable(), + [0, 2, 3, .._] => ::std::util::unreachable(), + [0, .._, 3] => ::std::util::unreachable(), + [0, .._] => ::std::util::unreachable(), + [1, 2, 3] => (), + [_, _, _] => ::std::util::unreachable(), + } + match x { + [.._] => (), + } + match x { + [_, _, _, .._] => (), + } + match x { + [a, b, c] => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +pub fn main() { + a(); +} diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index 5e906fa2659..c09fb8d6bc7 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -1,19 +1,19 @@ fn a() { - let x = [1]; + let x = ~[1]; match x { - [_, _, _, _, _, .._] => ::std::util::unreachable(), - [.._, _, _, _, _] => ::std::util::unreachable(), - [_, .._, _, _] => ::std::util::unreachable(), - [_, _] => ::std::util::unreachable(), + [_, _, _, _, _, .._] => fail!(), + [.._, _, _, _, _] => fail!(), + [_, .._, _, _] => fail!(), + [_, _] => fail!(), [a] => { assert_eq!(a, 1); } - [] => ::std::util::unreachable() + [] => fail!() } } fn b() { - let x = [1, 2, 3]; + let x = ~[1, 2, 3]; match x { [a, b, ..c] => { assert_eq!(a, 1); @@ -48,7 +48,28 @@ fn b() { } } +fn c() { + let x = [1]; + match x { + [2, .. _] => fail!(), + [.. _] => () + } +} + +fn d() { + let x = [1, 2, 3]; + let branch = match x { + [1, 1, .. _] => 0, + [1, 2, 3, .. _] => 1, + [1, 2, .. _] => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + pub fn main() { a(); b(); + c(); + d(); } diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 27f4fc83351..6a60308f2e7 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -3,7 +3,7 @@ struct Foo { } pub fn main() { - let x = [ + let x = ~[ Foo { string: ~"foo" }, Foo { string: ~"bar" }, Foo { string: ~"baz" }