From 1968cb315af9d128ee4457738fddd1eba275277f Mon Sep 17 00:00:00 2001 From: Jakub Wieczorek Date: Sat, 8 Dec 2012 20:22:43 +0000 Subject: [PATCH] Add support for destructuring vectors in match expressions --- src/librustc/middle/check_alt.rs | 120 +++++++++++++- src/librustc/middle/mem_categorization.rs | 4 +- src/librustc/middle/trans/alt.rs | 149 +++++++++++++++++- src/librustc/middle/typeck/check/alt.rs | 29 ++++ src/libsyntax/ast.rs | 1 + src/libsyntax/ast_util.rs | 8 + src/libsyntax/fold.rs | 6 +- src/libsyntax/parse/parser.rs | 40 +++++ src/libsyntax/print/pprust.rs | 10 ++ src/libsyntax/visit.rs | 10 +- .../compile-fail/alt-vec-illegal-tail-loan.rs | 15 ++ src/test/compile-fail/alt-vec-invalid-2.rs | 6 + src/test/compile-fail/alt-vec-invalid.rs | 7 + src/test/compile-fail/alt-vec-mismatch-2.rs | 5 + src/test/compile-fail/alt-vec-mismatch.rs | 6 + src/test/compile-fail/alt-vec-unreachable.rs | 20 +++ .../compile-fail/let-destruct-refutable.rs | 3 + src/test/compile-fail/non-exhaustive-match.rs | 24 +++ src/test/run-pass/vec-matching.rs | 33 ++++ src/test/run-pass/vec-tail-matching.rs | 35 ++++ 20 files changed, 521 insertions(+), 10 deletions(-) create mode 100644 src/test/compile-fail/alt-vec-illegal-tail-loan.rs create mode 100644 src/test/compile-fail/alt-vec-invalid-2.rs create mode 100644 src/test/compile-fail/alt-vec-invalid.rs create mode 100644 src/test/compile-fail/alt-vec-mismatch-2.rs create mode 100644 src/test/compile-fail/alt-vec-mismatch.rs create mode 100644 src/test/compile-fail/alt-vec-unreachable.rs create mode 100644 src/test/run-pass/vec-matching.rs create mode 100644 src/test/run-pass/vec-tail-matching.rs diff --git a/src/librustc/middle/check_alt.rs b/src/librustc/middle/check_alt.rs index 197a88d9ddee2..fe33f8d6e572c 100644 --- a/src/librustc/middle/check_alt.rs +++ b/src/librustc/middle/check_alt.rs @@ -22,6 +22,7 @@ use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat, walk_pat}; 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 { 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 } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0e9be0b6e681f..8962a1494e50d 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -978,7 +978,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 7885a8ea0b601..922dc2363a053 100644 --- a/src/librustc/middle/trans/alt.rs +++ b/src/librustc/middle/trans/alt.rs @@ -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 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); + } _ => {} } } @@ -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 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 { @@ -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; } diff --git a/src/librustc/middle/typeck/check/alt.rs b/src/librustc/middle/typeck/check/alt.rs index 9432ca186f94e..68e4c1a4b92cd 100644 --- a/src/librustc/middle/typeck/check/alt.rs +++ b/src/librustc/middle/typeck/check/alt.rs @@ -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 => () + } + } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 444f90c7f0458..351b299547196 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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] diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index ef7bd1d892859..294a66166fae8 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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(_, _) => { } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 93845f3dbb859..0b1ff4f56eced 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 47f65ed2f8d37..50ed0df28a054 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1794,6 +1794,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; @@ -1929,6 +1962,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); + } copy 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 e977327e919b4..3b995addd62b3 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1641,6 +1641,16 @@ fn print_pat(s: ps, &&pat: @ast::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); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 7b406564114b8..9a47edfeb05a6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -251,7 +251,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..9e8fb84951d30 --- /dev/null +++ b/src/test/compile-fail/alt-vec-mismatch-2.rs @@ -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 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 512c00b8a457f..9bd9db2077993 100644 --- a/src/test/compile-fail/let-destruct-refutable.rs +++ b/src/test/compile-fail/let-destruct-refutable.rs @@ -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]; } diff --git a/src/test/compile-fail/non-exhaustive-match.rs b/src/test/compile-fail/non-exhaustive-match.rs index 52dd2b5ade945..9719dd744b713 100644 --- a/src/test/compile-fail/non-exhaustive-match.rs +++ b/src/test/compile-fail/non-exhaustive-match.rs @@ -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 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..e2b68a11776e1 --- /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(); + } + } +}