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

Vector destructuring #4091

Closed
wants to merge 13 commits into from
120 changes: 119 additions & 1 deletion src/librustc/middle/check_alt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(@{
Expand Down Expand Up @@ -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
}
}
Expand All @@ -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 {
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -250,6 +279,12 @@ fn pat_ctor_id(tcx: ty::ctxt, p: @pat) -> Option<ctor> {
pat_region(*) => {
Some(single)
}
pat_vec(elems, tail) => {
match tail {
Some(_) => Some(vec_with_tail(elems.len())),
None => Some(vec(elems.len()))
}
}
}
}

Expand Down Expand Up @@ -310,6 +345,56 @@ fn missing_ctor(tcx: ty::ctxt, m: matrix, left_ty: ty::t) -> Option<ctor> {
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)
}
}
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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
}
}
}
}

Expand Down Expand Up @@ -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 }
}
}

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 @@ -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*/
}
}
}

Expand Down
Loading