Skip to content

Commit 19e10e3

Browse files
author
Jakub Wieczorek
committed
Improve code reuse in check_match::specialize()
1 parent b981add commit 19e10e3

File tree

1 file changed

+83
-128
lines changed

1 file changed

+83
-128
lines changed

src/librustc/middle/check_match.rs

+83-128
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use util::ppaux::ty_to_str;
2020
use std::cmp;
2121
use std::iter;
2222
use syntax::ast::*;
23-
use syntax::ast_util::{unguarded_pat, walk_pat};
23+
use syntax::ast_util::{is_unguarded, walk_pat};
2424
use syntax::codemap::{DUMMY_SP, Span};
2525
use syntax::parse::token;
2626
use syntax::visit;
@@ -79,26 +79,13 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
7979
// If the type *is* empty, it's vacuously exhaustive
8080
return;
8181
}
82-
match ty::get(pat_ty).sty {
83-
ty_enum(did, _) => {
84-
if (*enum_variants(cx.tcx, did)).is_empty() &&
85-
(*arms).is_empty() {
86-
87-
return;
88-
}
89-
}
90-
_ => { /* We assume only enum types can be uninhabited */ }
91-
}
92-
93-
let pats: Vec<@Pat> = arms.iter()
94-
.filter_map(unguarded_pat)
95-
.flat_map(|pats| pats.move_iter())
96-
.collect();
97-
if pats.is_empty() {
98-
cx.tcx.sess.span_err(ex.span, "non-exhaustive patterns");
99-
} else {
100-
check_exhaustive(cx, ex.span, pats);
101-
}
82+
let m: matrix = arms
83+
.iter()
84+
.filter(|&arm| is_unguarded(arm))
85+
.flat_map(|arm| arm.pats.iter())
86+
.map(|pat| vec!(pat.clone()))
87+
.collect();
88+
check_exhaustive(cx, ex.span, &m);
10289
}
10390
_ => ()
10491
}
@@ -152,9 +139,8 @@ fn raw_pat(p: @Pat) -> @Pat {
152139
}
153140
}
154141

155-
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, pats: Vec<@Pat> ) {
156-
assert!((!pats.is_empty()));
157-
let ext = match is_useful(cx, &pats.iter().map(|p| vec!(*p)).collect(), [wild()]) {
142+
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &matrix) {
143+
let ext = match is_useful(cx, m, [wild()]) {
158144
not_useful => {
159145
// This is good, wildcard pattern isn't reachable
160146
return;
@@ -587,23 +573,20 @@ fn specialize(cx: &MatchCheckCtxt,
587573
arity: uint,
588574
left_ty: ty::t)
589575
-> Option<Vec<@Pat> > {
590-
// Sad, but I can't get rid of this easily
591-
let r0 = (*raw_pat(r[0])).clone();
592-
match r0 {
593-
Pat{id: pat_id, node: n, span: pat_span} =>
594-
match n {
595-
PatWild => {
596-
Some(Vec::from_elem(arity, wild()).append(r.tail()))
576+
let &Pat{id: ref pat_id, node: ref n, span: ref pat_span} = &(*raw_pat(r[0]));
577+
let head: Option<Vec<@Pat>> = match n {
578+
&PatWild => {
579+
Some(Vec::from_elem(arity, wild()))
597580
}
598-
PatWildMulti => {
599-
Some(Vec::from_elem(arity, wild_multi()).append(r.tail()))
581+
&PatWildMulti => {
582+
Some(Vec::from_elem(arity, wild_multi()))
600583
}
601-
PatIdent(_, _, _) => {
602-
let opt_def = cx.tcx.def_map.borrow().find_copy(&pat_id);
584+
&PatIdent(_, _, _) => {
585+
let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
603586
match opt_def {
604587
Some(DefVariant(_, id, _)) => {
605588
if variant(id) == *ctor_id {
606-
Some(Vec::from_slice(r.tail()))
589+
Some(vec!())
607590
} else {
608591
None
609592
}
@@ -617,7 +600,7 @@ fn specialize(cx: &MatchCheckCtxt,
617600
match compare_const_vals(&e_v, v) {
618601
Some(val1) => (val1 == 0),
619602
None => {
620-
cx.tcx.sess.span_err(pat_span,
603+
cx.tcx.sess.span_err(*pat_span,
621604
"mismatched types between arms");
622605
false
623606
}
@@ -631,7 +614,7 @@ fn specialize(cx: &MatchCheckCtxt,
631614
(val1 >= 0 && val2 <= 0)
632615
}
633616
_ => {
634-
cx.tcx.sess.span_err(pat_span,
617+
cx.tcx.sess.span_err(*pat_span,
635618
"mismatched types between ranges");
636619
false
637620
}
@@ -641,18 +624,18 @@ fn specialize(cx: &MatchCheckCtxt,
641624
_ => fail!("type error")
642625
};
643626
if match_ {
644-
Some(Vec::from_slice(r.tail()))
627+
Some(vec!())
645628
} else {
646629
None
647630
}
648631
}
649632
_ => {
650-
Some(Vec::from_elem(arity, wild()).append(r.tail()))
633+
Some(Vec::from_elem(arity, wild()))
651634
}
652635
}
653636
}
654-
PatEnum(_, args) => {
655-
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
637+
&PatEnum(_, ref args) => {
638+
let def = cx.tcx.def_map.borrow().get_copy(pat_id);
656639
match def {
657640
DefStatic(did, _) => {
658641
let const_expr =
@@ -663,7 +646,7 @@ fn specialize(cx: &MatchCheckCtxt,
663646
match compare_const_vals(&e_v, v) {
664647
Some(val1) => (val1 == 0),
665648
None => {
666-
cx.tcx.sess.span_err(pat_span,
649+
cx.tcx.sess.span_err(*pat_span,
667650
"mismatched types between arms");
668651
false
669652
}
@@ -674,7 +657,7 @@ fn specialize(cx: &MatchCheckCtxt,
674657
match (m1, m2) {
675658
(Some(val1), Some(val2)) => (val1 >= 0 && val2 <= 0),
676659
_ => {
677-
cx.tcx.sess.span_err(pat_span,
660+
cx.tcx.sess.span_err(*pat_span,
678661
"mismatched types between ranges");
679662
false
680663
}
@@ -684,97 +667,72 @@ fn specialize(cx: &MatchCheckCtxt,
684667
_ => fail!("type error")
685668
};
686669
if match_ {
687-
Some(Vec::from_slice(r.tail()))
670+
Some(vec!())
688671
} else {
689672
None
690673
}
691674
}
692-
DefVariant(_, id, _) if variant(id) == *ctor_id => {
693-
let args = match args {
694-
Some(args) => args.iter().map(|x| *x).collect(),
695-
None => Vec::from_elem(arity, wild())
696-
};
697-
Some(args.append(r.tail()))
698-
}
699-
DefVariant(_, _, _) => None,
700-
701-
DefFn(..) |
702-
DefStruct(..) => {
703-
let new_args;
704-
match args {
705-
Some(args) => {
706-
new_args = args.iter().map(|x| *x).collect()
707-
}
708-
None => new_args = Vec::from_elem(arity, wild())
709-
}
710-
Some(new_args.append(r.tail()))
675+
DefVariant(_, id, _) if variant(id) != *ctor_id => None,
676+
DefVariant(..) | DefFn(..) | DefStruct(..) => {
677+
Some(match args {
678+
&Some(ref args) => args.clone(),
679+
&None => Vec::from_elem(arity, wild())
680+
})
711681
}
712682
_ => None
713683
}
714684
}
715-
PatStruct(_, ref pattern_fields, _) => {
685+
&PatStruct(_, ref pattern_fields, _) => {
716686
// Is this a struct or an enum variant?
717-
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
718-
match def {
687+
let def = cx.tcx.def_map.borrow().get_copy(pat_id);
688+
let class_id = match def {
719689
DefVariant(_, variant_id, _) => {
720-
if variant(variant_id) == *ctor_id {
721-
let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
722-
let args = struct_fields.iter().map(|sf| {
723-
match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
724-
Some(f) => f.pat,
725-
_ => wild()
726-
}
727-
}).collect::<Vec<_>>();
728-
Some(args.append(r.tail()))
729-
} else {
730-
None
731-
}
690+
if variant(variant_id) == *ctor_id {
691+
Some(variant_id)
692+
} else {
693+
None
694+
}
732695
}
733696
_ => {
734-
// Grab the class data that we care about.
735-
let class_fields;
736-
let class_id;
737697
match ty::get(left_ty).sty {
738-
ty::ty_struct(cid, _) => {
739-
class_id = cid;
740-
class_fields =
741-
ty::lookup_struct_fields(cx.tcx,
742-
class_id);
743-
}
698+
ty::ty_struct(cid, _) => Some(cid),
744699
_ => {
745700
cx.tcx.sess.span_bug(
746-
pat_span,
701+
*pat_span,
747702
format!("struct pattern resolved to {}, \
748703
not a struct",
749704
ty_to_str(cx.tcx,
750705
left_ty)).as_slice());
751706
}
752707
}
753-
let args = class_fields.iter().map(|class_field| {
754-
match pattern_fields.iter().find(|f|
755-
f.ident.name == class_field.name) {
756-
Some(f) => f.pat,
757-
_ => wild()
758-
}
759-
}).collect::<Vec<_>>();
760-
Some(args.append(r.tail()))
761708
}
762-
}
709+
};
710+
class_id.map(|variant_id| {
711+
let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
712+
let args = struct_fields.iter().map(|sf| {
713+
match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
714+
Some(f) => f.pat,
715+
_ => wild()
716+
}
717+
}).collect();
718+
args
719+
})
720+
763721
}
764-
PatTup(args) => {
765-
Some(args.iter().map(|x| *x).collect::<Vec<_>>().append(r.tail()))
722+
&PatTup(ref args) => {
723+
Some(args.iter().map(|x| *x).collect())
766724
}
767-
PatBox(a) | PatRegion(a) => {
768-
Some((vec!(a)).append(r.tail()))
725+
&PatBox(ref inner) | &PatRegion(ref inner) => {
726+
Some(vec!(inner.clone()))
769727
}
770-
PatLit(expr) => {
771-
let e_v = eval_const_expr(cx.tcx, expr);
728+
&PatLit(ref expr) => {
729+
let e_v = eval_const_expr(cx.tcx, *expr);
772730
let match_ = match *ctor_id {
773731
val(ref v) => {
774732
match compare_const_vals(&e_v, v) {
775733
Some(val1) => val1 == 0,
776734
None => {
777-
cx.tcx.sess.span_err(pat_span,
735+
cx.tcx.sess.span_err(*pat_span,
778736
"mismatched types between arms");
779737
false
780738
}
@@ -786,7 +744,7 @@ fn specialize(cx: &MatchCheckCtxt,
786744
match (m1, m2) {
787745
(Some(val1), Some(val2)) => (val1 >= 0 && val2 <= 0),
788746
_ => {
789-
cx.tcx.sess.span_err(pat_span,
747+
cx.tcx.sess.span_err(*pat_span,
790748
"mismatched types between ranges");
791749
false
792750
}
@@ -796,52 +754,49 @@ fn specialize(cx: &MatchCheckCtxt,
796754
_ => fail!("type error")
797755
};
798756
if match_ {
799-
Some(Vec::from_slice(r.tail()))
757+
Some(vec!())
800758
} else {
801759
None
802760
}
803761
}
804-
PatRange(lo, hi) => {
762+
&PatRange(lo, hi) => {
805763
let (c_lo, c_hi) = match *ctor_id {
806-
val(ref v) => ((*v).clone(), (*v).clone()),
807-
range(ref lo, ref hi) => ((*lo).clone(), (*hi).clone()),
808-
single => return Some(Vec::from_slice(r.tail())),
764+
val(ref v) => (v, v),
765+
range(ref lo, ref hi) => (lo, hi),
766+
single => return Some(vec!()),
809767
_ => fail!("type error")
810768
};
811769
let v_lo = eval_const_expr(cx.tcx, lo);
812770
let v_hi = eval_const_expr(cx.tcx, hi);
813771

814-
let m1 = compare_const_vals(&c_lo, &v_lo);
815-
let m2 = compare_const_vals(&c_hi, &v_hi);
772+
let m1 = compare_const_vals(c_lo, &v_lo);
773+
let m2 = compare_const_vals(c_hi, &v_hi);
816774
match (m1, m2) {
817775
(Some(val1), Some(val2)) if val1 >= 0 && val2 <= 0 => {
818-
Some(Vec::from_slice(r.tail()))
776+
Some(vec!())
819777
},
820778
(Some(_), Some(_)) => None,
821779
_ => {
822-
cx.tcx.sess.span_err(pat_span,
780+
cx.tcx.sess.span_err(*pat_span,
823781
"mismatched types between ranges");
824782
None
825783
}
826784
}
827785
}
828-
PatVec(before, slice, after) => {
786+
&PatVec(ref before, ref slice, ref after) => {
829787
match *ctor_id {
830788
vec(_) => {
831789
let num_elements = before.len() + after.len();
832790
if num_elements < arity && slice.is_some() {
833791
let mut result = Vec::new();
834-
let wilds = Vec::from_elem(arity - num_elements, wild());
835-
result.push_all_move(before);
836-
result.push_all_move(wilds);
837-
result.push_all_move(after);
838-
result.push_all(r.tail());
792+
result.push_all(before.as_slice());
793+
result.grow_fn(arity - num_elements, |_| wild());
794+
result.push_all(after.as_slice());
839795
Some(result)
840796
} else if num_elements == arity {
841797
let mut result = Vec::new();
842-
result.push_all_move(before);
843-
result.push_all_move(after);
844-
result.push_all(r.tail());
798+
result.push_all(before.as_slice());
799+
result.push_all(after.as_slice());
845800
Some(result)
846801
} else {
847802
None
@@ -850,12 +805,12 @@ fn specialize(cx: &MatchCheckCtxt,
850805
_ => None
851806
}
852807
}
853-
PatMac(_) => {
854-
cx.tcx.sess.span_err(pat_span, "unexpanded macro");
808+
&PatMac(_) => {
809+
cx.tcx.sess.span_err(*pat_span, "unexpanded macro");
855810
None
856811
}
857-
}
858-
}
812+
};
813+
head.map(|head| head.append(r.tail()))
859814
}
860815

861816
fn default(cx: &MatchCheckCtxt, r: &[@Pat]) -> Option<Vec<@Pat> > {

0 commit comments

Comments
 (0)