Skip to content

Commit 1968cb3

Browse files
Jakub Wieczorekgraydon
Jakub Wieczorek
authored andcommitted
Add support for destructuring vectors in match expressions
1 parent 5bf7ba0 commit 1968cb3

20 files changed

+521
-10
lines changed

src/librustc/middle/check_alt.rs

+119-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat, walk_pat};
2222
use syntax::codemap::span;
2323
use syntax::print::pprust::pat_to_str;
2424
use syntax::visit;
25+
use std::sort;
2526

2627
struct AltCheckCtxt {
2728
tcx: ty::ctxt,
@@ -146,6 +147,12 @@ fn check_exhaustive(cx: @AltCheckCtxt, sp: span, pats: ~[@pat]) {
146147
None => fail ~"check_exhaustive: bad variant in ctor"
147148
}
148149
}
150+
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
151+
match (*ctor) {
152+
vec(n) => Some(fmt!("vectors of length %u", n)),
153+
_ => None
154+
}
155+
}
149156
_ => None
150157
}
151158
}
@@ -166,6 +173,8 @@ enum ctor {
166173
variant(def_id),
167174
val(const_val),
168175
range(const_val, const_val),
176+
vec(uint),
177+
vec_with_tail(uint)
169178
}
170179

171180
impl ctor : cmp::Eq {
@@ -179,7 +188,12 @@ impl ctor : cmp::Eq {
179188
range(ref cv0_other, ref cv1_other)) => {
180189
(*cv0_self) == (*cv0_other) && (*cv1_self) == (*cv1_other)
181190
}
182-
(single, _) | (variant(_), _) | (val(_), _) | (range(*), _) => {
191+
(vec(n_self), vec(n_other)) => n_self == n_other,
192+
(vec_with_tail(n_self), vec_with_tail(n_other)) => {
193+
n_self == n_other
194+
}
195+
(single, _) | (variant(_), _) | (val(_), _) |
196+
(range(*), _) | (vec(*), _) | (vec_with_tail(*), _) => {
183197
false
184198
}
185199
}
@@ -236,6 +250,21 @@ fn is_useful(cx: @AltCheckCtxt, m: matrix, v: ~[@pat]) -> useful {
236250
}
237251
not_useful
238252
}
253+
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
254+
let max_len = do m.foldr(0) |r, max_len| {
255+
match r[0].node {
256+
pat_vec(elems, _) => uint::max(elems.len(), max_len),
257+
_ => max_len
258+
}
259+
};
260+
for uint::range(0, max_len + 1) |n| {
261+
match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
262+
not_useful => (),
263+
ref u => return (*u)
264+
}
265+
}
266+
not_useful
267+
}
239268
_ => {
240269
let arity = ctor_arity(cx, single, left_ty);
241270
is_useful_specialized(cx, m, v, single, arity, left_ty)
@@ -297,6 +326,12 @@ fn pat_ctor_id(cx: @AltCheckCtxt, p: @pat) -> Option<ctor> {
297326
pat_region(*) => {
298327
Some(single)
299328
}
329+
pat_vec(elems, tail) => {
330+
match tail {
331+
Some(_) => Some(vec_with_tail(elems.len())),
332+
None => Some(vec(elems.len()))
333+
}
334+
}
300335
}
301336
}
302337

@@ -360,6 +395,56 @@ fn missing_ctor(cx: @AltCheckCtxt,
360395
else if true_found { Some(val(const_bool(false))) }
361396
else { Some(val(const_bool(true))) }
362397
}
398+
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
399+
let max_len = do m.foldr(0) |r, max_len| {
400+
match r[0].node {
401+
pat_vec(elems, _) => uint::max(elems.len(), max_len),
402+
_ => max_len
403+
}
404+
};
405+
let min_len_with_tail = do m.foldr(max_len + 1) |r, min_len| {
406+
match r[0].node {
407+
pat_vec(elems, tail) => {
408+
if tail.is_some() && elems.len() < min_len {
409+
elems.len()
410+
} else {
411+
min_len
412+
}
413+
}
414+
_ => min_len
415+
}
416+
};
417+
let vec_lens = do m.filter_map |r| {
418+
match r[0].node {
419+
pat_vec(elems, tail) => {
420+
match tail {
421+
None if elems.len() < min_len_with_tail => Some(elems.len()),
422+
_ => None
423+
}
424+
}
425+
_ => None
426+
}
427+
};
428+
let mut sorted_vec_lens = do sort::merge_sort(vec_lens) |a, b| {
429+
a < b
430+
};
431+
vec::dedup(&mut sorted_vec_lens);
432+
433+
let mut missing = None;
434+
for uint::range(0, min_len_with_tail) |i| {
435+
if i >= sorted_vec_lens.len() || i != sorted_vec_lens[i] {
436+
missing = Some(i);
437+
break;
438+
}
439+
};
440+
if missing.is_none() && min_len_with_tail > max_len {
441+
missing = Some(min_len_with_tail);
442+
}
443+
match missing {
444+
Some(k) => Some(vec(k)),
445+
None => None
446+
}
447+
}
363448
_ => Some(single)
364449
}
365450
}
@@ -378,6 +463,12 @@ fn ctor_arity(cx: @AltCheckCtxt, ctor: ctor, ty: ty::t) -> uint {
378463
}
379464
}
380465
ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
466+
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
467+
match ctor {
468+
vec(n) | vec_with_tail(n) => n,
469+
_ => 0u
470+
}
471+
}
381472
_ => 0u
382473
}
383474
}
@@ -521,6 +612,32 @@ fn specialize(cx: @AltCheckCtxt, r: ~[@pat], ctor_id: ctor, arity: uint,
521612
compare_const_vals(c_hi, v_hi) <= 0;
522613
if match_ { Some(vec::tail(r)) } else { None }
523614
}
615+
pat_vec(elems, tail) => {
616+
match ctor_id {
617+
vec_with_tail(_) => {
618+
if elems.len() >= arity {
619+
Some(vec::append(elems.slice(0, arity), vec::tail(r)))
620+
} else {
621+
None
622+
}
623+
}
624+
vec(_) => {
625+
if elems.len() < arity && tail.is_some() {
626+
Some(vec::append(
627+
vec::append(elems, vec::from_elem(
628+
arity - elems.len(), wild())
629+
),
630+
vec::tail(r)
631+
))
632+
} else if elems.len() == arity {
633+
Some(vec::append(elems, vec::tail(r)))
634+
} else {
635+
None
636+
}
637+
}
638+
_ => None
639+
}
640+
}
524641
}
525642
}
526643

@@ -593,6 +710,7 @@ fn is_refutable(cx: @AltCheckCtxt, pat: &pat) -> bool {
593710
args.any(|a| is_refutable(cx, *a))
594711
}
595712
pat_enum(_,_) => { false }
713+
pat_vec(*) => { true }
596714
}
597715
}
598716

src/librustc/middle/mem_categorization.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,9 @@ impl &mem_categorization_ctxt {
978978
self.cat_pattern(subcmt, subpat, op);
979979
}
980980

981-
ast::pat_lit(_) | ast::pat_range(_, _) => { /*always ok*/ }
981+
ast::pat_vec(*) | ast::pat_lit(_) | ast::pat_range(_, _) => {
982+
/*always ok*/
983+
}
982984
}
983985
}
984986

0 commit comments

Comments
 (0)