]> git.lizzy.rs Git - rust.git/commitdiff
Add support for destructuring vectors in match expressions
authorJakub Wieczorek <jakubw@jakubw.net>
Sat, 8 Dec 2012 20:22:43 +0000 (20:22 +0000)
committerGraydon Hoare <graydon@mozilla.com>
Tue, 18 Dec 2012 00:50:40 +0000 (16:50 -0800)
20 files changed:
src/librustc/middle/check_alt.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/trans/alt.rs
src/librustc/middle/typeck/check/alt.rs
src/libsyntax/ast.rs
src/libsyntax/ast_util.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/compile-fail/alt-vec-illegal-tail-loan.rs [new file with mode: 0644]
src/test/compile-fail/alt-vec-invalid-2.rs [new file with mode: 0644]
src/test/compile-fail/alt-vec-invalid.rs [new file with mode: 0644]
src/test/compile-fail/alt-vec-mismatch-2.rs [new file with mode: 0644]
src/test/compile-fail/alt-vec-mismatch.rs [new file with mode: 0644]
src/test/compile-fail/alt-vec-unreachable.rs [new file with mode: 0644]
src/test/compile-fail/let-destruct-refutable.rs
src/test/compile-fail/non-exhaustive-match.rs
src/test/run-pass/vec-matching.rs [new file with mode: 0644]
src/test/run-pass/vec-tail-matching.rs [new file with mode: 0644]

index 197a88d9ddee269a544fc6dcfaca743356220beb..fe33f8d6e572c417bac889a2c14ba80c79606c86 100644 (file)
@@ -22,6 +22,7 @@
 use syntax::codemap::span;
 use syntax::print::pprust::pat_to_str;
 use syntax::visit;
+use std::sort;
 
 struct AltCheckCtxt {
     tcx: ty::ctxt,
@@ -146,6 +147,12 @@ fn check_exhaustive(cx: @AltCheckCtxt, sp: span, pats: ~[@pat]) {
               None => fail ~"check_exhaustive: bad variant in ctor"
             }
           }
+          ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
+            match (*ctor) {
+              vec(n) => Some(fmt!("vectors of length %u", n)),
+              _ => None
+            }
+          }
           _ => None
         }
       }
@@ -166,6 +173,8 @@ enum ctor {
     variant(def_id),
     val(const_val),
     range(const_val, const_val),
+    vec(uint),
+    vec_with_tail(uint)
 }
 
 impl ctor : cmp::Eq {
@@ -179,7 +188,12 @@ impl ctor : cmp::Eq {
              range(ref cv0_other, ref cv1_other)) => {
                 (*cv0_self) == (*cv0_other) && (*cv1_self) == (*cv1_other)
             }
-            (single, _) | (variant(_), _) | (val(_), _) | (range(*), _) => {
+            (vec(n_self), vec(n_other)) => n_self == n_other,
+            (vec_with_tail(n_self), vec_with_tail(n_other)) => {
+                n_self == n_other
+            }
+            (single, _) | (variant(_), _) | (val(_), _) |
+            (range(*), _) | (vec(*), _) | (vec_with_tail(*), _) => {
                 false
             }
         }
@@ -236,6 +250,21 @@ fn is_useful(cx: @AltCheckCtxt, m: matrix, v: ~[@pat]) -> useful {
                 }
                 not_useful
               }
+              ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
+                let max_len = do m.foldr(0) |r, max_len| {
+                  match r[0].node {
+                    pat_vec(elems, _) => uint::max(elems.len(), max_len),
+                    _ => max_len
+                  }
+                };
+                for uint::range(0, max_len + 1) |n| {
+                  match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
+                    not_useful => (),
+                    ref u => return (*u)
+                  }
+                }
+                not_useful
+              }
               _ => {
                 let arity = ctor_arity(cx, single, left_ty);
                 is_useful_specialized(cx, m, v, single, arity, left_ty)
@@ -297,6 +326,12 @@ fn pat_ctor_id(cx: @AltCheckCtxt, p: @pat) -> Option<ctor> {
       pat_region(*) => {
         Some(single)
       }
+      pat_vec(elems, tail) => {
+        match tail {
+          Some(_) => Some(vec_with_tail(elems.len())),
+          None => Some(vec(elems.len()))
+        }
+      }
     }
 }
 
@@ -360,6 +395,56 @@ fn missing_ctor(cx: @AltCheckCtxt,
         else if true_found { Some(val(const_bool(false))) }
         else { Some(val(const_bool(true))) }
       }
+      ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
+        let max_len = do m.foldr(0) |r, max_len| {
+          match r[0].node {
+            pat_vec(elems, _) => uint::max(elems.len(), max_len),
+            _ => max_len
+          }
+        };
+        let min_len_with_tail = do m.foldr(max_len + 1) |r, min_len| {
+          match r[0].node {
+            pat_vec(elems, tail) => {
+              if tail.is_some() && elems.len() < min_len {
+                elems.len()
+              } else {
+                min_len
+              }
+            }
+            _ => min_len
+          }
+        };
+        let vec_lens = do m.filter_map |r| {
+          match r[0].node {
+            pat_vec(elems, tail) => {
+              match tail {
+                None if elems.len() < min_len_with_tail => Some(elems.len()),
+                _ => None
+              }
+            }
+            _ => None
+          }
+        };
+        let mut sorted_vec_lens = do sort::merge_sort(vec_lens) |a, b| {
+          a < b
+        };
+        vec::dedup(&mut sorted_vec_lens);
+
+        let mut missing = None;
+        for uint::range(0, min_len_with_tail) |i| {
+          if i >= sorted_vec_lens.len() || i != sorted_vec_lens[i] {
+            missing = Some(i);
+            break;
+          }
+        };
+        if missing.is_none() && min_len_with_tail > max_len {
+          missing = Some(min_len_with_tail);
+        }
+        match missing {
+          Some(k) => Some(vec(k)),
+          None => None
+        }
+      }
       _ => Some(single)
     }
 }
@@ -378,6 +463,12 @@ fn ctor_arity(cx: @AltCheckCtxt, ctor: ctor, ty: ty::t) -> uint {
         }
       }
       ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
+      ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
+        match ctor {
+          vec(n) | vec_with_tail(n) => n,
+          _ => 0u
+        }
+      }
       _ => 0u
     }
 }
@@ -521,6 +612,32 @@ fn specialize(cx: @AltCheckCtxt, r: ~[@pat], ctor_id: ctor, arity: uint,
                     compare_const_vals(c_hi, v_hi) <= 0;
         if match_ { Some(vec::tail(r)) } else { None }
       }
+      pat_vec(elems, tail) => {
+        match ctor_id {
+          vec_with_tail(_) => {
+            if elems.len() >= arity {
+              Some(vec::append(elems.slice(0, arity), vec::tail(r)))
+            } else {
+              None
+            }
+          }
+          vec(_) => {
+            if elems.len() < arity && tail.is_some() {
+              Some(vec::append(
+                vec::append(elems, vec::from_elem(
+                    arity - elems.len(), wild())
+                ),
+                vec::tail(r)
+              ))
+            } else if elems.len() == arity {
+              Some(vec::append(elems, vec::tail(r)))
+            } else {
+              None
+            }
+          }
+          _ => None
+        }
+      }
     }
 }
 
@@ -593,6 +710,7 @@ fn is_refutable(cx: @AltCheckCtxt, pat: &pat) -> bool {
         args.any(|a| is_refutable(cx, *a))
       }
       pat_enum(_,_) => { false }
+      pat_vec(*) => { true }
     }
 }
 
index 0e9be0b6e681f67ac33be8bba7c2958642216a1d..8962a1494e50d70c03190b2b6884c5d0b84a39c0 100644 (file)
@@ -978,7 +978,9 @@ fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
             self.cat_pattern(subcmt, subpat, op);
           }
 
-          ast::pat_lit(_) | ast::pat_range(_, _) => { /*always ok*/ }
+          ast::pat_vec(*) | ast::pat_lit(_) | ast::pat_range(_, _) => {
+              /*always ok*/
+          }
         }
     }
 
index 7885a8ea0b60111fba93dbfb1d3bd2d07d673011..922dc2363a05397ce6feba0f5dc976f0c7d8a372 100644 (file)
@@ -179,7 +179,9 @@ enum Lit {
 enum Opt {
     lit(Lit),
     var(/* disr val */int, /* variant dids */{enm: def_id, var: def_id}),
-    range(@ast::expr, @ast::expr)
+    range(@ast::expr, @ast::expr),
+    vec_len_eq(uint),
+    vec_len_ge(uint)
 }
 
 fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
@@ -223,12 +225,15 @@ fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
         const_eval::compare_lit_exprs(tcx, a2, b2) == 0
       }
       (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
     }
 }
 
 enum opt_result {
     single_result(Result),
+    lower_bound(Result),
     range_result(Result, Result),
 }
 fn trans_opt(bcx: block, o: &Opt) -> opt_result {
@@ -256,6 +261,12 @@ fn trans_opt(bcx: 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) => {
+            return single_result(rslt(bcx, C_int(ccx, n as int)));
+        }
+        vec_len_ge(n) => {
+            return lower_bound(rslt(bcx, C_int(ccx, n as int)));
+        }
     }
 }
 
@@ -545,6 +556,24 @@ fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint,
                     None
                 }
             }
+            ast::pat_vec(elems, tail) => {
+                match tail {
+                    Some(_) => {
+                        if opt_eq(tcx, &vec_len_ge(elems.len()), opt) {
+                            Some(vec::append_one(elems, tail.get()))
+                        } else {
+                            None
+                        }
+                    }
+                    None => {
+                        if opt_eq(tcx, &vec_len_eq(elems.len()), opt) {
+                            Some(copy elems)
+                        } else {
+                            None
+                        }
+                    }
+                }
+            }
             _ => {
                 assert_is_binding_or_wild(bcx, p);
                 Some(vec::from_elem(variant_size, dummy))
@@ -755,6 +784,13 @@ fn add_to_set(tcx: ty::ctxt, set: &DVec<Opt>, val: Opt) {
             ast::pat_range(l1, l2) => {
                 add_to_set(ccx.tcx, &found, range(l1, l2));
             }
+            ast::pat_vec(elems, tail) => {
+                let opt = match tail {
+                    None => vec_len_eq(elems.len()),
+                    Some(_) => vec_len_ge(elems.len())
+                };
+                add_to_set(ccx.tcx, &found, opt);
+            }
             _ => {}
         }
     }
@@ -790,6 +826,41 @@ fn extract_variant_args(bcx: block, pat_id: ast::node_id,
     return {vals: args, bcx: bcx};
 }
 
+fn extract_vec_elems(bcx: block, pat_id: ast::node_id,
+                     elem_count: uint, tail: bool, val: ValueRef)
+    -> {vals: ~[ValueRef], bcx: block}
+{
+    let _icx = bcx.insn_ctxt("alt::extract_vec_elems");
+    let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
+    let unboxed = load_if_immediate(bcx, val, vt.vec_ty);
+    let (base, len) = tvec::get_base_and_len(bcx, unboxed, vt.vec_ty);
+
+    let mut elems = do vec::from_fn(elem_count) |i| {
+        GEPi(bcx, base, ~[i])
+    };
+    if tail {
+        let tail_offset = Mul(bcx, vt.llunit_size,
+            C_int(bcx.ccx(), elem_count as int)
+        );
+        let tail_begin = tvec::pointer_add(bcx, base, tail_offset);
+        let tail_len = Sub(bcx, len, tail_offset);
+        let tail_ty = ty::mk_evec(bcx.tcx(),
+            {ty: vt.unit_ty, mutbl: ast::m_imm},
+            ty::vstore_slice(ty::re_static)
+        );
+        let scratch = scratch_datum(bcx, tail_ty, false);
+        Store(bcx, tail_begin,
+            GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])
+        );
+        Store(bcx, tail_len,
+            GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])
+        );
+        elems.push(scratch.val);
+        scratch.add_clean(bcx);
+    }
+    return {vals: elems, bcx: bcx};
+}
+
 // NB: This function does not collect fields from struct-like enum variants.
 fn collect_record_or_struct_fields(bcx: block, m: &[@Match], col: uint) ->
                                    ~[ast::ident] {
@@ -918,7 +989,7 @@ fn score(p: @ast::pat) -> uint {
     return best_col;
 }
 
-enum branch_kind { no_branch, single, switch, compare, }
+enum branch_kind { no_branch, single, switch, compare, compare_vec_len, }
 
 impl branch_kind : cmp::Eq {
     pure fn eq(&self, other: &branch_kind) -> bool {
@@ -1268,6 +1339,15 @@ fn compile_submatch(bcx: block,
             range(_, _) => {
                 test_val = Load(bcx, val);
                 kind = compare;
+            },
+            vec_len_eq(_) | vec_len_ge(_) => {
+                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(
+                    bcx, unboxed, vt.vec_ty
+                );
+                test_val = SDiv(bcx, len, vt.llunit_size);
+                kind = compare_vec_len;
             }
         }
     }
@@ -1323,6 +1403,12 @@ fn compile_submatch(bcx: block,
                                   Result {bcx, val}) => {
                                   compare_values(bcx, test_val, val, t)
                               }
+                              lower_bound(
+                                  Result {bcx, val}) => {
+                                  compare_scalar_types(
+                                          bcx, test_val, val,
+                                          t, ast::ge)
+                              }
                               range_result(
                                   Result {val: vbegin, _},
                                   Result {bcx, val: vend}) => {
@@ -1342,9 +1428,47 @@ fn compile_submatch(bcx: block,
                   bcx = sub_block(after_cx, ~"compare_next");
                   CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
               }
-                _ => ()
+              compare_vec_len => {
+                  let Result {bcx: after_cx, val: matches} = {
+                      do with_scope_result(bcx, None,
+                                           ~"compare_vec_len_scope") |bcx| {
+                          match trans_opt(bcx, opt) {
+                              single_result(
+                                  Result {bcx, val}) => {
+                                  let value = compare_scalar_values(
+                                      bcx, test_val, val,
+                                      signed_int, ast::eq);
+                                  rslt(bcx, value)
+                              }
+                              lower_bound(
+                                  Result {bcx, val: val}) => {
+                                  let value = compare_scalar_values(
+                                      bcx, test_val, val,
+                                      signed_int, ast::ge);
+                                  rslt(bcx, value)
+                              }
+                              range_result(
+                                  Result {val: vbegin, _},
+                                  Result {bcx, val: vend}) => {
+                                  let llge =
+                                      compare_scalar_values(
+                                          bcx, test_val,
+                                          vbegin, signed_int, ast::ge);
+                                  let llle =
+                                      compare_scalar_values(
+                                          bcx, test_val, vend,
+                                          signed_int, ast::le);
+                                  rslt(bcx, And(bcx, llge, llle))
+                              }
+                          }
+                      }
+                  };
+                  bcx = sub_block(after_cx, ~"compare_vec_len_next");
+                  CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
+              }
+              _ => ()
             }
-        } else if kind == compare {
+        } else if kind == compare || kind == compare_vec_len {
             Br(bcx, else_cx.llbb);
         }
 
@@ -1357,6 +1481,16 @@ fn compile_submatch(bcx: block,
                 unpacked = args.vals;
                 opt_cx = args.bcx;
             }
+            vec_len_eq(n) | vec_len_ge(n) => {
+                let tail = match *opt {
+                    vec_len_ge(_) => true,
+                    _ => false
+                };
+                let args = extract_vec_elems(opt_cx, pat_id, n, tail, val);
+                size = args.vals.len();
+                unpacked = args.vals;
+                opt_cx = args.bcx;
+            }
             lit(_) | range(_, _) => ()
         }
         let opt_ms = enter_opt(opt_cx, m, opt, col, size, val);
@@ -1366,7 +1500,9 @@ fn compile_submatch(bcx: block,
 
     // Compile the fall-through case, if any
     if !exhaustive {
-        if kind == compare { Br(bcx, else_cx.llbb); }
+        if kind == compare || kind == compare_vec_len {
+            Br(bcx, else_cx.llbb);
+        }
         if kind != single {
             compile_submatch(else_cx, defaults, vals_left, chk);
         }
@@ -1640,7 +1776,8 @@ fn bind_irrefutable_pat(bcx: block,
                                        true,
                                        binding_mode);
         }
-        ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => ()
+        ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) |
+        ast::pat_vec(*) => ()
     }
     return bcx;
 }
index 9432ca186f94ed2242e8e3d75a1ab30ffcc7ded2..68e4c1a4b92cdea58fa1513bb8229fc4a0940e18 100644 (file)
@@ -525,7 +525,36 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
           }
         }
       }
+      ast::pat_vec(elts, tail) => {
+        let elt_type = match structure_of(fcx, pat.span, expected) {
+          ty::ty_evec(mt, _) | ty::ty_unboxed_vec(mt) => mt,
+          _ => {
+            tcx.sess.span_fatal(
+                pat.span,
+                fmt!("mismatched type: expected `%s` but found vector",
+                     fcx.infcx().ty_to_str(expected))
+            );
+          }
+        };
+        for elts.each |elt| {
+            check_pat(pcx, *elt, elt_type.ty);
+        }
+        fcx.write_ty(pat.id, expected);
 
+        match tail {
+            Some(tail_pat) => {
+                let region_var = fcx.infcx().next_region_var_with_lb(
+                    pat.span, pcx.block_region
+                );
+                let slice_ty = ty::mk_evec(tcx,
+                    {ty: elt_type.ty, mutbl: elt_type.mutbl},
+                    ty::vstore_slice(region_var)
+                );
+                check_pat(pcx, tail_pat, slice_ty);
+            }
+            None => ()
+        }
+      }
     }
 }
 
index 444f90c7f0458d756122d9f8c722fb1fb24f006c..351b2995471963efce63d42c0079417849f7ce87 100644 (file)
@@ -389,6 +389,7 @@ enum pat_ {
     pat_region(@pat), // borrowed pointer pattern
     pat_lit(@expr),
     pat_range(@expr, @expr),
+    pat_vec(~[@pat], Option<@pat>)
 }
 
 #[auto_serialize]
index ef7bd1d892859f940aac6b26edf6432ede4320cb..294a66166fae8a0088a12b4f68f8de7badb5fc7c 100644 (file)
@@ -593,6 +593,14 @@ fn walk_pat(pat: @pat, it: fn(@pat)) {
         pat_box(s) | pat_uniq(s) | pat_region(s) => {
             walk_pat(s, it)
         }
+        pat_vec(elts, tail) => {
+            for elts.each |p| {
+                walk_pat(*p, it)
+            }
+            do option::iter(&tail) |tail| {
+                walk_pat(*tail, it)
+            }
+        }
         pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, _, _) |
         pat_enum(_, _) => {
         }
index 93845f3dbb859cc34315ca563dd205c6e3e0892a..0b1ff4f56eced3b12853e91681443ed53113c5c3 100644 (file)
@@ -356,7 +356,11 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
           pat_region(inner) => pat_region(fld.fold_pat(inner)),
           pat_range(e1, e2) => {
             pat_range(fld.fold_expr(e1), fld.fold_expr(e2))
-          }
+          },
+          pat_vec(elts, tail) => pat_vec(
+            vec::map(elts, |x| fld.fold_pat(*x)),
+            option::map(&tail, |tail| fld.fold_pat(*tail))
+          )
         };
 }
 
index 47f65ed2f8d37ed2ba217cd78edaf2b2483a006a..50ed0df28a054b5ea69d4435ab9a3098723565b4 100644 (file)
@@ -1794,6 +1794,39 @@ fn parse_pats() -> ~[@pat] {
         };
     }
 
+    fn parse_pat_vec_elements(refutable: bool) -> (~[@pat], Option<@pat>) {
+        let mut elements = ~[];
+        let mut tail = None;
+        let mut first = true;
+
+        while self.token != token::RBRACKET {
+            if first { first = false; }
+            else { self.expect(token::COMMA); }
+
+            let mut is_tail = false;
+            if self.token == token::DOTDOT {
+                self.bump();
+                is_tail = true;
+            }
+
+            let subpat = self.parse_pat(refutable);
+            if is_tail {
+                match subpat {
+                    @{ node: pat_wild, _ } => (),
+                    @{ node: pat_ident(_, _, _), _ } => (),
+                    @{ span, _ } => self.span_fatal(
+                        span, ~"expected an identifier or `_`"
+                    )
+                }
+                tail = Some(subpat);
+                break;
+            }
+
+            elements.push(subpat);
+        }
+        return (elements, tail);
+    }
+
     fn parse_pat_fields(refutable: bool) -> (~[ast::field_pat], bool) {
         let mut fields = ~[];
         let mut etc = false;
@@ -1929,6 +1962,13 @@ fn parse_pat(refutable: bool) -> @pat {
                 pat = pat_tup(fields);
             }
           }
+          token::LBRACKET => {
+            self.bump();
+            let (elements, tail) = self.parse_pat_vec_elements(refutable);
+            hi = self.span.hi;
+            self.expect(token::RBRACKET);
+            pat = ast::pat_vec(elements, tail);
+          }
           copy tok => {
             if !is_ident_or_path(tok)
                 || self.is_keyword(~"true")
index e977327e919b45e561230f08b35aebbceafcdc8d..3b995addd62b3451a1d89b09d750a71bf40ac09f 100644 (file)
@@ -1641,6 +1641,16 @@ fn print_field(s: ps, f: ast::field_pat, refutable: bool) {
         word(s.s, ~"..");
         print_expr(s, end);
       }
+      ast::pat_vec(elts, tail) => {
+        word(s.s, ~"[");
+        commasep(s, inconsistent, elts, |s, p| print_pat(s, p, refutable));
+        do option::iter(&tail) |tail| {
+            if vec::len(elts) != 0u { word_space(s, ~","); }
+            word(s.s, ~"..");
+            print_pat(s, *tail, refutable);
+        }
+        word(s.s, ~"]");
+      }
     }
     (s.ann.post)(ann_node);
 }
index 7b406564114b8c7622e4f8d30d9b2b1d7973b994..9a47edfeb05a6707bb8fa4138c88dc1d67231ac2 100644 (file)
@@ -251,7 +251,15 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
         (v.visit_expr)(e1, e, v);
         (v.visit_expr)(e2, e, v);
       }
-      pat_wild => ()
+      pat_wild => (),
+      pat_vec(elts, tail) => {
+        for elts.each |elt| {
+          (v.visit_pat)(*elt, e, v);
+        }
+        do option::iter(&tail) |tail| {
+          (v.visit_pat)(*tail, e, v);
+        }
+      }
     }
 }
 
diff --git a/src/test/compile-fail/alt-vec-illegal-tail-loan.rs b/src/test/compile-fail/alt-vec-illegal-tail-loan.rs
new file mode 100644 (file)
index 0000000..69bc910
--- /dev/null
@@ -0,0 +1,15 @@
+fn a() -> &[int] {
+    let vec = [1, 2, 3, 4];
+    let tail = match vec {
+        [a, ..tail] => tail, //~ ERROR illegal borrow
+        _ => fail ~"foo"
+    };
+    move tail
+}
+
+fn main() {
+    let tail = a();
+    for tail.each |n| {
+        io::println(fmt!("%d", *n));
+    }
+}
diff --git a/src/test/compile-fail/alt-vec-invalid-2.rs b/src/test/compile-fail/alt-vec-invalid-2.rs
new file mode 100644 (file)
index 0000000..4174120
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    match ~[] {
+        [_, ..tail, _] => {}, //~ ERROR: expected `]` but found `,`
+        _ => ()
+    }
+}
diff --git a/src/test/compile-fail/alt-vec-invalid.rs b/src/test/compile-fail/alt-vec-invalid.rs
new file mode 100644 (file)
index 0000000..b35731c
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let a = ~[];
+    match a {
+        [1, ..tail, ..tail] => {}, //~ ERROR: expected `]` but found `,`
+        _ => ()
+    }
+}
diff --git a/src/test/compile-fail/alt-vec-mismatch-2.rs b/src/test/compile-fail/alt-vec-mismatch-2.rs
new file mode 100644 (file)
index 0000000..9e8fb84
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    match () {
+        [()] => { } //~ ERROR mismatched type: expected `()` but found vector
+    }
+}
diff --git a/src/test/compile-fail/alt-vec-mismatch.rs b/src/test/compile-fail/alt-vec-mismatch.rs
new file mode 100644 (file)
index 0000000..ef4d92e
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    match ~"foo" {
+        ['f', 'o', .._] => { } //~ ERROR mismatched type: expected `~str` but found vector
+        _ => { }
+    }
+}
diff --git a/src/test/compile-fail/alt-vec-unreachable.rs b/src/test/compile-fail/alt-vec-unreachable.rs
new file mode 100644 (file)
index 0000000..2719d84
--- /dev/null
@@ -0,0 +1,20 @@
+fn main() {
+    let x: ~[(int, int)] = ~[];
+    match x {
+        [a, (2, 3), _] => (),
+        [(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern
+        _ => ()
+    }
+
+    match [~"foo", ~"bar", ~"baz"] {
+        [a, _, _, .._] => { io::println(a); }
+        [~"foo", ~"bar", ~"baz", ~"foo", ~"bar"] => { } //~ ERROR unreachable pattern
+        _ => { }
+    }
+
+    match ['a', 'b', 'c'] {
+        ['a', 'b', 'c', .._tail] => {}
+        ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+}
index 512c00b8a457f859e28e3caee17d8858e81be8df..9bd9db207799317462030f083e7daacebf159a48 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// error-pattern:refutable pattern
 // error-pattern:refutable pattern
 
 enum xx { xx(int), yy, }
@@ -15,4 +16,6 @@ enum xx { xx(int), yy, }
 fn main() {
     let @{x: xx(x), y: y} = @{x: xx(10), y: 20};
     assert (x + y == 30);
+
+    let [a, b] = ~[1, 2];
 }
index 52dd2b5ade9456105c215d493fd19259a35785bc..9719dd744b7139d91e13861ab8f7b43d269555aa 100644 (file)
@@ -35,4 +35,28 @@ fn main() {
       (_, a) => {}
       (b, b) => {}
     }
+    match ~[Some(42), None, Some(21)] { //~ ERROR non-exhaustive patterns: vectors of length 0 not covered
+        [Some(*), None, ..tail] => {}
+        [Some(*), Some(*), ..tail] => {}
+        [None] => {}
+    }
+    match ~[1] {
+        [_, ..tail] => (),
+        [] => ()
+    }
+    match ~[0.5] { //~ ERROR non-exhaustive patterns: vectors of length 4 not covered
+        [0.1, 0.2, 0.3] => (),
+        [0.1, 0.2] => (),
+        [0.1] => (),
+        [] => ()
+    }
+    match ~[Some(42), None, Some(21)] {
+        [Some(*), None, ..tail] => {}
+        [Some(*), Some(*), ..tail] => {}
+        [None, None, ..tail] => {}
+        [None, Some(*), ..tail] => {}
+        [Some(_)] => {}
+        [None] => {}
+        [] => {}
+    }
 }
diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs
new file mode 100644 (file)
index 0000000..a3840c9
--- /dev/null
@@ -0,0 +1,33 @@
+fn foldl<T, U: Copy>(
+    values: &[T],
+    initial: U,
+    function: &fn(partial: U, element: &T) -> U
+) -> U {
+    match values {
+        [head, ..tail] =>
+            foldl(tail, function(initial, &head), function),
+        _ => copy initial
+    }
+}
+
+fn main() {
+    let x = [1, 2, 3, 4, 5];
+    match x {
+        [a, b, c, d, e, f] => {
+            core::util::unreachable();
+        }
+        [a, b, c, d, e] => {
+            assert a == 1;
+            assert b == 2;
+            assert c == 3;
+            assert d == 4;
+            assert e == 5;
+        }
+        _ => {
+            core::util::unreachable();
+        }
+    }
+
+    let product = foldl(x, 1, |a, b| a * *b);
+    assert product == 120;
+}
diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs
new file mode 100644 (file)
index 0000000..e2b68a1
--- /dev/null
@@ -0,0 +1,35 @@
+struct Foo {
+    string: ~str
+}
+
+fn main() {
+    let x = [
+        Foo { string: ~"foo" },
+        Foo { string: ~"bar" },
+        Foo { string: ~"baz" }
+    ];
+    match x {
+        [first, ..tail] => {
+            assert first.string == ~"foo";
+            assert tail.len() == 2;
+            assert tail[0].string == ~"bar";
+            assert tail[1].string == ~"baz";
+
+            match tail {
+                [Foo { _ }, _, Foo { _ }, ..tail] => {
+                    core::util::unreachable();
+                }
+                [Foo { string: a }, Foo { string: b }] => {
+                    assert a == ~"bar";
+                    assert b == ~"baz";
+                }
+                _ => {
+                    core::util::unreachable();
+                }
+            }
+        }
+        _ => {
+            core::util::unreachable();
+        }
+    }
+}