Add support for destructuring vectors in match expressions · rust-lang/rust@1968cb3 (original) (raw)
`@@ -22,6 +22,7 @@ use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat, walk_pat};
`
22
22
`use syntax::codemap::span;
`
23
23
`use syntax::print::pprust::pat_to_str;
`
24
24
`use syntax::visit;
`
``
25
`+
use std::sort;
`
25
26
``
26
27
`struct AltCheckCtxt {
`
27
28
`tcx: ty::ctxt,
`
`@@ -146,6 +147,12 @@ fn check_exhaustive(cx: @AltCheckCtxt, sp: span, pats: ~[@pat]) {
`
146
147
`None => fail ~"check_exhaustive: bad variant in ctor"
`
147
148
`}
`
148
149
`}
`
``
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
`+
}
`
149
156
` _ => None
`
150
157
`}
`
151
158
`}
`
`@@ -166,6 +173,8 @@ enum ctor {
`
166
173
` variant(def_id),
`
167
174
` val(const_val),
`
168
175
` range(const_val, const_val),
`
``
176
`+
vec(uint),
`
``
177
`+
vec_with_tail(uint)
`
169
178
`}
`
170
179
``
171
180
`impl ctor : cmp::Eq {
`
`@@ -179,7 +188,12 @@ impl ctor : cmp::Eq {
`
179
188
` range(ref cv0_other, ref cv1_other)) => {
`
180
189
`(*cv0_self) == (*cv0_other) && (*cv1_self) == (*cv1_other)
`
181
190
`}
`
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(*), _) => {
`
183
197
`false
`
184
198
`}
`
185
199
`}
`
`@@ -236,6 +250,21 @@ fn is_useful(cx: @AltCheckCtxt, m: matrix, v: ~[@pat]) -> useful {
`
236
250
`}
`
237
251
` not_useful
`
238
252
`}
`
``
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
`+
}
`
239
268
` _ => {
`
240
269
`let arity = ctor_arity(cx, single, left_ty);
`
241
270
`is_useful_specialized(cx, m, v, single, arity, left_ty)
`
`@@ -297,6 +326,12 @@ fn pat_ctor_id(cx: @AltCheckCtxt, p: @pat) -> Option {
`
297
326
` pat_region(*) => {
`
298
327
`Some(single)
`
299
328
`}
`
``
329
`+
pat_vec(elems, tail) => {
`
``
330
`+
match tail {
`
``
331
`+
Some(_) => Some(vec_with_tail(elems.len())),
`
``
332
`+
None => Some(vec(elems.len()))
`
``
333
`+
}
`
``
334
`+
}
`
300
335
`}
`
301
336
`}
`
302
337
``
`@@ -360,6 +395,56 @@ fn missing_ctor(cx: @AltCheckCtxt,
`
360
395
`else if true_found { Some(val(const_bool(false))) }
`
361
396
`else { Some(val(const_bool(true))) }
`
362
397
`}
`
``
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
`+
}
`
363
448
` _ => Some(single)
`
364
449
`}
`
365
450
`}
`
`@@ -378,6 +463,12 @@ fn ctor_arity(cx: @AltCheckCtxt, ctor: ctor, ty: ty::t) -> uint {
`
378
463
`}
`
379
464
`}
`
380
465
` 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
`+
}
`
381
472
` _ => 0u
`
382
473
`}
`
383
474
`}
`
`@@ -521,6 +612,32 @@ fn specialize(cx: @AltCheckCtxt, r: ~[@pat], ctor_id: ctor, arity: uint,
`
521
612
`compare_const_vals(c_hi, v_hi) <= 0;
`
522
613
`if match_ { Some(vec::tail(r)) } else { None }
`
523
614
`}
`
``
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
`+
}
`
524
641
`}
`
525
642
`}
`
526
643
``
`@@ -593,6 +710,7 @@ fn is_refutable(cx: @AltCheckCtxt, pat: &pat) -> bool {
`
593
710
` args.any(|a| is_refutable(cx, *a))
`
594
711
`}
`
595
712
` pat_enum(,) => { false }
`
``
713
`+
pat_vec(*) => { true }
`
596
714
`}
`
597
715
`}
`
598
716
``