diff --git a/src/librustc/middle/check_alt.rs b/src/librustc/middle/check_alt.rs index e7716ad984eb3..ff1c426580766 100644 --- a/src/librustc/middle/check_alt.rs +++ b/src/librustc/middle/check_alt.rs @@ -10,6 +10,7 @@ use syntax::visit; use middle::ty; use middle::ty::*; use std::map::HashMap; +use std::sort; fn check_crate(tcx: ty::ctxt, crate: @crate) { visit::visit_crate(*crate, (), visit::mk_vt(@{ @@ -103,6 +104,12 @@ fn check_exhaustive(tcx: ty::ctxt, 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 } } @@ -123,6 +130,8 @@ enum ctor { variant(def_id), val(const_val), range(const_val, const_val), + vec(uint), + vec_with_tail(uint) } impl ctor : cmp::Eq { @@ -134,7 +143,12 @@ impl ctor : cmp::Eq { (range(cv0_self, cv1_self), range(cv0_other, 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 } } @@ -189,6 +203,21 @@ fn is_useful(tcx: ty::ctxt, 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(tcx, m, v, vec(n), n, left_ty) { + not_useful => (), + u => return u + } + } + not_useful + } _ => { let arity = ctor_arity(tcx, single, left_ty); is_useful_specialized(tcx, m, v, single, arity, left_ty) @@ -250,6 +279,12 @@ fn pat_ctor_id(tcx: ty::ctxt, p: @pat) -> Option { pat_region(*) => { Some(single) } + pat_vec(elems, tail) => { + match tail { + Some(_) => Some(vec_with_tail(elems.len())), + None => Some(vec(elems.len())) + } + } } } @@ -310,6 +345,56 @@ fn missing_ctor(tcx: ty::ctxt, m: matrix, left_ty: ty::t) -> Option { 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) } } @@ -328,6 +413,12 @@ fn ctor_arity(tcx: ty::ctxt, ctor: ctor, ty: ty::t) -> uint { } } ty::ty_class(cid, _) => ty::lookup_class_fields(tcx, cid).len(), + ty::ty_unboxed_vec(*) | ty::ty_evec(*) => { + match ctor { + vec(n) | vec_with_tail(n) => n, + _ => 0u + } + } _ => 0u } } @@ -469,6 +560,32 @@ fn specialize(tcx: ty::ctxt, 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 + } + } } } @@ -534,6 +651,7 @@ fn is_refutable(tcx: ty::ctxt, pat: &pat) -> bool { args.any(|a| is_refutable(tcx, *a)) } pat_enum(_,_) => { false } + pat_vec(*) => { true } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index fd5735e78deff..ee3bc0ab47fc5 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -972,7 +972,9 @@ impl &mem_categorization_ctxt { 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*/ + } } } diff --git a/src/librustc/middle/trans/alt.rs b/src/librustc/middle/trans/alt.rs index 03501521129b7..9ee93333debd9 100644 --- a/src/librustc/middle/trans/alt.rs +++ b/src/librustc/middle/trans/alt.rs @@ -167,7 +167,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 { @@ -211,12 +213,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 { @@ -244,6 +249,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))); + } } } @@ -531,6 +542,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)) @@ -741,6 +770,13 @@ fn get_options(ccx: @crate_ctxt, m: &[@Match], col: uint) -> ~[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); + } _ => {} } } @@ -776,6 +812,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] { @@ -904,7 +975,7 @@ fn pick_col(m: &[@Match]) -> 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 { @@ -1244,6 +1315,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; } } } @@ -1299,6 +1379,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}) => { @@ -1318,9 +1404,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); } @@ -1333,6 +1457,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); @@ -1342,7 +1476,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); } @@ -1607,7 +1743,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; } diff --git a/src/librustc/middle/typeck/check/alt.rs b/src/librustc/middle/typeck/check/alt.rs index 6131fb531249b..2acb3703b5d4f 100644 --- a/src/librustc/middle/typeck/check/alt.rs +++ b/src/librustc/middle/typeck/check/alt.rs @@ -576,7 +576,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 => () + } + } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1ffe741d255fd..714a3c1e9f137 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -372,6 +372,7 @@ enum pat_ { pat_region(@pat), // borrowed pointer pattern pat_lit(@expr), pat_range(@expr, @expr), + pat_vec(~[@pat], Option<@pat>) } #[auto_serialize] diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index e4e29d1fb4550..7472fe33d1c37 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -583,6 +583,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(_, _) => { } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9a1f3e7f04e80..267a6bfd46fa2 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -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)) + ) }; } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d8fd58b3d5081..970483ff4ec87 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1851,6 +1851,39 @@ impl Parser { }; } + 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; @@ -1988,6 +2021,13 @@ impl Parser { 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); + } tok => { if !is_ident_or_path(tok) || self.is_keyword(~"true") diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 5ad3c051c5977..311294e0e77e5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1589,6 +1589,16 @@ fn print_pat(s: ps, &&pat: @ast::pat) { word(s.s, ~".."); print_expr(s, end); } + ast::pat_vec(elts, tail) => { + word(s.s, ~"["); + commasep(s, inconsistent, elts, print_pat); + do option::iter(&tail) |tail| { + if vec::len(elts) != 0u { word_space(s, ~","); } + word(s.s, ~".."); + print_pat(s, *tail); + } + word(s.s, ~"]"); + } } (s.ann.post)(ann_node); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index fbb1bc9117211..6926bb900e1ae 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -241,7 +241,15 @@ fn visit_pat(p: @pat, e: E, v: vt) { (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 index 0000000000000..69bc910669de9 --- /dev/null +++ b/src/test/compile-fail/alt-vec-illegal-tail-loan.rs @@ -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 index 0000000000000..4174120b291c6 --- /dev/null +++ b/src/test/compile-fail/alt-vec-invalid-2.rs @@ -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 index 0000000000000..b35731c2e4acd --- /dev/null +++ b/src/test/compile-fail/alt-vec-invalid.rs @@ -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 index 0000000000000..fe3a305eeb5b9 --- /dev/null +++ b/src/test/compile-fail/alt-vec-mismatch-2.rs @@ -0,0 +1,6 @@ +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 index 0000000000000..ef4d92ea4913b --- /dev/null +++ b/src/test/compile-fail/alt-vec-mismatch.rs @@ -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 index 0000000000000..2719d84b2dd25 --- /dev/null +++ b/src/test/compile-fail/alt-vec-unreachable.rs @@ -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 + _ => {} + } +} diff --git a/src/test/compile-fail/let-destruct-refutable.rs b/src/test/compile-fail/let-destruct-refutable.rs index 1d80654781f4e..849ef6ba632ff 100644 --- a/src/test/compile-fail/let-destruct-refutable.rs +++ b/src/test/compile-fail/let-destruct-refutable.rs @@ -1,8 +1,11 @@ // error-pattern:refutable pattern +// error-pattern:refutable pattern 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]; } diff --git a/src/test/compile-fail/non-exhaustive-match.rs b/src/test/compile-fail/non-exhaustive-match.rs index 0e9615c7bd9a3..2cddf9a198bc2 100644 --- a/src/test/compile-fail/non-exhaustive-match.rs +++ b/src/test/compile-fail/non-exhaustive-match.rs @@ -25,4 +25,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 index 0000000000000..a3840c9f561f8 --- /dev/null +++ b/src/test/run-pass/vec-matching.rs @@ -0,0 +1,33 @@ +fn foldl( + 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 index 0000000000000..7a7010f079d04 --- /dev/null +++ b/src/test/run-pass/vec-tail-matching.rs @@ -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(); + } + } +}