Skip to content

Vector destructuring #4091

New issue

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

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

Already on GitHub? # to your account

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