Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for destructuring vectors in match expressions #4143

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 108 additions & 1 deletion src/librustc/middle/check_alt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
}
Expand All @@ -166,6 +173,7 @@ enum ctor {
variant(def_id),
val(const_val),
range(const_val, const_val),
vec(uint)
}

impl ctor : cmp::Eq {
Expand All @@ -179,7 +187,9 @@ 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,
(single, _) | (variant(_), _) | (val(_), _) |
(range(*), _) | (vec(*), _) => {
false
}
}
Expand Down Expand Up @@ -236,6 +246,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)
Expand Down Expand Up @@ -297,6 +322,12 @@ fn pat_ctor_id(cx: @AltCheckCtxt, p: @pat) -> Option<ctor> {
pat_region(*) => {
Some(single)
}
pat_vec(elems, tail) => {
match tail {
Some(_) => None,
None => Some(vec(elems.len()))
}
}
}
}

Expand Down Expand Up @@ -360,6 +391,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(*) => {

// Find the lengths and tails of all vector patterns.
let vec_pat_lens = do m.filter_map |r| {
match r[0].node {
pat_vec(elems, tail) => {
Some((elems.len(), tail.is_some()))
}
_ => None
}
};

// Sort them by length such that for patterns of the same length,
// those with a destructured tail come first.
let mut sorted_vec_lens = sort::merge_sort(vec_pat_lens,
|&(len1, tail1), &(len2, tail2)| {
if len1 == len2 {
tail1 > tail2
} else {
len1 <= len2
}
}
);
vec::dedup(&mut sorted_vec_lens);

let mut found_tail = false;
let mut next = 0;
let mut missing = None;
for sorted_vec_lens.each |&(length, tail)| {
if length != next {
missing = Some(next);
break;
}
if tail {
found_tail = true;
break;
}
next += 1;
}

// We found patterns of all lengths within <0, next), yet there was no
// pattern with a tail - therefore, we report vec(next) as missing.
if !found_tail {
missing = Some(next);
}
match missing {
Some(k) => Some(vec(k)),
None => None
}
}
_ => Some(single)
}
}
Expand All @@ -378,6 +459,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) => n,
_ => 0u
}
}
_ => 0u
}
}
Expand Down Expand Up @@ -521,6 +608,25 @@ 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(_) => {
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
}
}
}
}

Expand Down Expand Up @@ -593,6 +699,7 @@ fn is_refutable(cx: @AltCheckCtxt, pat: &pat) -> bool {
args.any(|a| is_refutable(cx, *a))
}
pat_enum(_,_) => { false }
pat_vec(*) => { true }
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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*/
}
}
}

Expand Down
Loading