diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 26bc845a15aa9..c936ec1c752e9 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -748,14 +748,10 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) { LocalFor => "`for` loop" }; - let mut spans = vec![]; - find_refutable(cx, loc.pat, &mut spans); - - for span in spans.iter() { - cx.tcx.sess.span_err(*span, - format!("refutable pattern in {} binding", name).as_slice()); + if is_refutable(cx, loc.pat) { + cx.tcx.sess.span_err(loc.pat.span, + format!("refutable pattern in {} binding", name).as_slice()); } - // Check legality of move bindings. check_legality_of_move_bindings(cx, false, [ loc.pat ]); } @@ -767,67 +763,18 @@ fn check_fn(cx: &mut MatchCheckCtxt, sp: Span) { visit::walk_fn(cx, kind, decl, body, sp, ()); for input in decl.inputs.iter() { - let mut spans = vec![]; - find_refutable(cx, input.pat, &mut spans); - - for span in spans.iter() { - cx.tcx.sess.span_err(*span, - "refutable pattern in function argument"); - } - } -} - -fn find_refutable(cx: &MatchCheckCtxt, pat: &Pat, spans: &mut Vec) { - macro_rules! this_pattern { - () => { - { - spans.push(pat.span); - return - } - } - } - let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id); - match opt_def { - Some(DefVariant(enum_id, _, _)) => { - if ty::enum_variants(cx.tcx, enum_id).len() != 1u { - this_pattern!() - } + if is_refutable(cx, input.pat) { + cx.tcx.sess.span_err(input.pat.span, "refutable pattern in function argument"); } - Some(DefStatic(..)) => this_pattern!(), - _ => () } +} - match pat.node { - PatBox(sub) | PatRegion(sub) | PatIdent(_, _, Some(sub)) => { - find_refutable(cx, sub, spans) - } - PatWild | PatWildMulti | PatIdent(_, _, None) => {} - PatLit(lit) => { - match lit.node { - ExprLit(lit) => { - match lit.node { - LitNil => {} // `()` - _ => this_pattern!(), - } - } - _ => this_pattern!(), - } - } - PatRange(_, _) => { this_pattern!() } - PatStruct(_, ref fields, _) => { - for f in fields.iter() { - find_refutable(cx, f.pat, spans); - } - } - PatTup(ref elts) | PatEnum(_, Some(ref elts))=> { - for elt in elts.iter() { - find_refutable(cx, *elt, spans) - } - } - PatEnum(_,_) => {} - PatVec(..) => { this_pattern!() } - PatMac(_) => cx.tcx.sess.bug("unexpanded macro"), - } +fn is_refutable(cx: &MatchCheckCtxt, pat: @Pat) -> bool { + let pats = vec!(vec!(pat)); + match is_useful(cx, &pats, [wild()]) { + not_useful => false, + _ => true + } } // Legality of move bindings checking diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index ddd41072c8d69..de4ebde241c1b 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1006,8 +1006,7 @@ fn extract_vec_elems<'a>( pat_id: ast::NodeId, elem_count: uint, slice: Option, - val: ValueRef, - count: ValueRef) + val: ValueRef) -> ExtractedBlock<'a> { let _icx = push_ctxt("match::extract_vec_elems"); let vec_datum = match_datum(bcx, val, pat_id); @@ -1021,7 +1020,7 @@ fn extract_vec_elems<'a>( Some(n) if i < n => GEPi(bcx, base, [i]), Some(n) if i > n => { InBoundsGEP(bcx, base, [ - Sub(bcx, count, + Sub(bcx, len, C_int(bcx.ccx(), (elem_count - i) as int))]) } _ => unsafe { llvm::LLVMGetUndef(vt.llunit_ty.to_ref()) } @@ -1775,7 +1774,7 @@ fn compile_submatch_continue<'a, 'b>( vec_len_eq => (n, None) }; let args = extract_vec_elems(opt_cx, pat_id, n, - slice, val, test_val); + slice, val); size = args.vals.len(); unpacked = args.vals.clone(); opt_cx = args.bcx; @@ -2278,9 +2277,21 @@ fn bind_irrefutable_pat<'a>( let loaded_val = Load(bcx, val); bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode, cleanup_scope); } - ast::PatVec(..) => { - bcx.sess().span_bug(pat.span, - "vector patterns are never irrefutable!"); + ast::PatVec(ref before, ref slice, ref after) => { + let extracted = extract_vec_elems( + bcx, pat.id, before.len() + 1u + after.len(), + slice.map(|_| before.len()), val + ); + bcx = before + .iter().map(|v| Some(*v)) + .chain(Some(*slice).move_iter()) + .chain(after.iter().map(|v| Some(*v))) + .zip(extracted.vals.iter()) + .fold(bcx, |bcx, (inner, elem)| { + inner.map_or(bcx, |inner| { + bind_irrefutable_pat(bcx, inner, *elem, binding_mode, cleanup_scope) + }) + }); } ast::PatMac(..) => { bcx.sess().span_bug(pat.span, "unexpanded macro"); diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 54b673b0b982f..67b15dc181e05 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -635,7 +635,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { fcx.infcx().next_region_var( infer::PatternRegion(pat.span)); - let check_err = || { + let check_err = |found: String| { for &elt in before.iter() { check_pat(pcx, elt, ty::mk_err()); } @@ -656,15 +656,16 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { }) }, Some(expected), - "a vector pattern".to_string(), + found, None); fcx.write_error(pat.id); }; - let (elt_type, region_var, mutbl) = match *structure_of(fcx, + let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx, pat.span, expected) { - ty::ty_vec(mt, Some(_)) => (mt.ty, default_region_var, ast::MutImmutable), + ty::ty_vec(mt, Some(fixed)) => + (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)), ty::ty_uniq(t) => match ty::get(t).sty { ty::ty_vec(mt, None) => { fcx.type_error_message(pat.span, @@ -674,25 +675,49 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { }, expected, None); - (mt.ty, default_region_var, ast::MutImmutable) + (mt.ty, default_region_var, ast::MutImmutable, None) } _ => { - check_err(); + check_err("a vector pattern".to_string()); return; } }, ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty { - ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl), + ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None), _ => { - check_err(); + check_err("a vector pattern".to_string()); return; } }, _ => { - check_err(); + check_err("a vector pattern".to_string()); return; } }; + + match fixed { + Some(count) => { + let unreachable = match slice { + Some(_) if before.len() + after.len() > count => + Some(format!( + "a fixed vector pattern of size at least {:}", + before.len() + after.len() + )), + None if before.len() + after.len() != count => + Some(format!( + "a fixed vector pattern of size {:}", + before.len() + after.len() + )), + _ => None + }; + for found in unreachable.move_iter() { + check_err(found); + return; + } + } + _ => () + } + for elt in before.iter() { check_pat(pcx, *elt, elt_type); } diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs new file mode 100644 index 0000000000000..2b769b9e499ea --- /dev/null +++ b/src/test/compile-fail/issue-13482.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = [1,2]; + let y = match x { + [] => None, +//~^ ERROR expected `[, .. 2]` but found a fixed vector pattern of size 0 + [a,_] => Some(a) + }; +} diff --git a/src/test/compile-fail/precise-refutable-pattern-errors.rs b/src/test/compile-fail/precise-refutable-pattern-errors.rs deleted file mode 100644 index efa2dbad83fda..0000000000000 --- a/src/test/compile-fail/precise-refutable-pattern-errors.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -fn func( - ( - 1, //~ ERROR refutable pattern in function argument - ( - Some( //~ ERROR refutable pattern in function argument - 1), // nested, so no warning. - 2..3 //~ ERROR refutable pattern in function argument - ) - ): (int, (Option, int)) - ) {} - -fn main() { - let ( - 1, //~ ERROR refutable pattern in local binding - ( - Some( //~ ERROR refutable pattern in local binding - 1), // nested, so no warning. - 2..3 //~ ERROR refutable pattern in local binding - ) - ) = (1, (None, 2)); -} diff --git a/src/test/compile-fail/refutable-pattern-errors.rs b/src/test/compile-fail/refutable-pattern-errors.rs new file mode 100644 index 0000000000000..38b9b888e06bf --- /dev/null +++ b/src/test/compile-fail/refutable-pattern-errors.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +fn func((1, (Some(1), 2..3)): (int, (Option, int))) { } +//~^ ERROR refutable pattern in function argument + +fn main() { + let (1, (Some(1), 2..3)) = (1, (None, 2)); + //~^ ERROR refutable pattern in local binding +} diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs new file mode 100644 index 0000000000000..06d22149b81d3 --- /dev/null +++ b/src/test/run-pass/issue-7784.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo + Clone>([x, y, z]: [T, ..3]) -> (T, T, T) { + (x.clone(), x.clone() + y.clone(), x + y + z) +} +fn bar(a: &'static str, b: &'static str) -> [&'static str, ..4] { + [a, b, b, a] +} + +fn main() { + assert_eq!(foo([1, 2, 3]), (1, 3, 6)); + + let [a, b, c, d] = bar("foo", "bar"); + assert_eq!(a, "foo"); + assert_eq!(b, "bar"); + assert_eq!(c, "bar"); + assert_eq!(d, "foo"); + + let [a, _, _, d] = bar("baz", "foo"); + assert_eq!(a, "baz"); + assert_eq!(d, "baz"); +} \ No newline at end of file