145
145
* - `store_non_ref_bindings()`
146
146
* - `insert_lllocals()`
147
147
*
148
+ *
149
+ * ## Notes on vector pattern matching.
150
+ *
151
+ * Vector pattern matching is surprisingly tricky. The problem is that
152
+ * the structure of the vector isn't fully known, and slice matches
153
+ * can be done on subparts of it.
154
+ *
155
+ * The way that vector pattern matches are dealt with, then, is as
156
+ * follows. First, we make the actual condition associated with a
157
+ * vector pattern simply a vector length comparison. So the pattern
158
+ * [1, .. x] gets the condition "vec len >= 1", and the pattern
159
+ * [.. x] gets the condition "vec len >= 0". The problem here is that
160
+ * having the condition "vec len >= 1" hold clearly does not mean that
161
+ * only a pattern that has exactly that condition will match. This
162
+ * means that it may well be the case that a condition holds, but none
163
+ * of the patterns matching that condition match; to deal with this,
164
+ * when doing vector length matches, we have match failures proceed to
165
+ * the next condition to check.
166
+ *
167
+ * There are a couple more subtleties to deal with. While the "actual"
168
+ * condition associated with vector length tests is simply a test on
169
+ * the vector length, the actual vec_len Opt entry contains more
170
+ * information used to restrict which matches are associated with it.
171
+ * So that all matches in a submatch are matching against the same
172
+ * values from inside the vector, they are split up by how many
173
+ * elements they match at the front and at the back of the vector. In
174
+ * order to make sure that arms are properly checked in order, even
175
+ * with the overmatching conditions, each vec_len Opt entry is
176
+ * associated with a range of matches.
177
+ * Consider the following:
178
+ *
179
+ * match &[1, 2, 3] {
180
+ * [1, 1, .. _] => 0,
181
+ * [1, 2, 2, .. _] => 1,
182
+ * [1, 2, 3, .. _] => 2,
183
+ * [1, 2, .. _] => 3,
184
+ * _ => 4
185
+ * }
186
+ * The proper arm to match is arm 2, but arms 0 and 3 both have the
187
+ * condition "len >= 2". If arm 3 was lumped in with arm 0, then the
188
+ * wrong branch would be taken. Instead, vec_len Opts are associated
189
+ * with a contiguous range of matches that have the same "shape".
190
+ * This is sort of ugly and requires a bunch of special handling of
191
+ * vec_len options.
192
+ *
148
193
*/
149
194
150
195
@@ -189,14 +234,19 @@ enum Lit {
189
234
ConstLit ( ast:: def_id ) , // the def ID of the constant
190
235
}
191
236
237
+ #[ deriving( Eq ) ]
238
+ pub enum VecLenOpt {
239
+ vec_len_eq,
240
+ vec_len_ge( /* length of prefix */ uint )
241
+ }
242
+
192
243
// An option identifying a branch (either a literal, a enum variant or a
193
244
// range)
194
245
enum Opt {
195
246
lit( Lit ) ,
196
247
var( /* disr val */ uint , @adt:: Repr ) ,
197
248
range( @ast:: expr , @ast:: expr ) ,
198
- vec_len_eq( uint ) ,
199
- vec_len_ge( uint , /* slice */ uint )
249
+ vec_len( /* length */ uint , VecLenOpt , /*range of matches*/ ( uint , uint ) )
200
250
}
201
251
202
252
fn opt_eq ( tcx : ty:: ctxt , a : & Opt , b : & Opt ) -> bool {
@@ -247,9 +297,9 @@ fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
247
297
}
248
298
}
249
299
( & var( a, _) , & var( b, _) ) => a == b,
250
- ( & vec_len_eq ( a ) , & vec_len_eq ( b ) ) => a == b ,
251
- ( & vec_len_ge ( a , _ ) , & vec_len_ge ( b , _ ) ) => a == b ,
252
- _ => false
300
+ ( & vec_len ( a1 , a2 , _ ) , & vec_len ( b1 , b2 , _ ) ) =>
301
+ a1 == b1 && a2 == b2 ,
302
+ _ => false
253
303
}
254
304
}
255
305
@@ -283,10 +333,10 @@ fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result {
283
333
return range_result ( rslt ( bcx, consts:: const_expr ( ccx, l1) ) ,
284
334
rslt ( bcx, consts:: const_expr ( ccx, l2) ) ) ;
285
335
}
286
- vec_len_eq ( n ) => {
336
+ vec_len ( n , vec_len_eq , _ ) => {
287
337
return single_result ( rslt ( bcx, C_int ( ccx, n as int ) ) ) ;
288
338
}
289
- vec_len_ge ( n , _) => {
339
+ vec_len ( n , vec_len_ge ( _ ) , _) => {
290
340
return lower_bound ( rslt ( bcx, C_int ( ccx, n as int ) ) ) ;
291
341
}
292
342
}
@@ -471,10 +521,11 @@ fn enter_match<'r>(bcx: @mut Block,
471
521
}
472
522
473
523
fn enter_default < ' r > ( bcx : @mut Block ,
474
- dm : DefMap ,
475
- m : & [ Match < ' r > ] ,
476
- col : uint ,
477
- val : ValueRef )
524
+ dm : DefMap ,
525
+ m : & [ Match < ' r > ] ,
526
+ col : uint ,
527
+ val : ValueRef ,
528
+ chk : Option < mk_fail > )
478
529
-> ~[ Match < ' r > ] {
479
530
debug ! ( "enter_default(bcx=%s, m=%s, col=%u, val=%s)" ,
480
531
bcx. to_str( ) ,
@@ -483,13 +534,36 @@ fn enter_default<'r>(bcx: @mut Block,
483
534
bcx. val_to_str( val) ) ;
484
535
let _indenter = indenter ( ) ;
485
536
486
- do enter_match ( bcx, dm, m, col, val) |p| {
537
+ // Collect all of the matches that can match against anything.
538
+ let matches = do enter_match ( bcx, dm, m, col, val) |p| {
487
539
match p. node {
488
540
ast:: pat_wild | ast:: pat_tup( _) => Some ( ~[ ] ) ,
489
541
ast:: pat_ident( _, _, None ) if pat_is_binding ( dm, p) => Some ( ~[ ] ) ,
490
542
_ => None
491
543
}
492
- }
544
+ } ;
545
+
546
+ // Ok, now, this is pretty subtle. A "default" match is a match
547
+ // that needs to be considered if none of the actual checks on the
548
+ // value being considered succeed. The subtlety lies in that sometimes
549
+ // identifier/wildcard matches are *not* default matches. Consider:
550
+ // "match x { _ if something => foo, true => bar, false => baz }".
551
+ // There is a wildcard match, but it is *not* a default case. The boolean
552
+ // case on the value being considered is exhaustive. If the case is
553
+ // exhaustive, then there are no defaults.
554
+ //
555
+ // We detect whether the case is exhaustive in the following
556
+ // somewhat kludgy way: if the last wildcard/binding match has a
557
+ // guard, then by non-redundancy, we know that there aren't any
558
+ // non guarded matches, and thus by exhaustiveness, we know that
559
+ // we don't need any default cases. If the check *isn't* nonexhaustive
560
+ // (because chk is Some), then we need the defaults anyways.
561
+ let is_exhaustive = match matches. last_opt ( ) {
562
+ Some ( m) if m. data . arm . guard . is_some ( ) && chk. is_none ( ) => true ,
563
+ _ => false
564
+ } ;
565
+
566
+ if is_exhaustive { ~[ ] } else { matches }
493
567
}
494
568
495
569
// <pcwalton> nmatsakis: what does enter_opt do?
@@ -523,17 +597,19 @@ fn enter_opt<'r>(bcx: @mut Block,
523
597
variant_size : uint ,
524
598
val : ValueRef )
525
599
-> ~[ Match < ' r > ] {
526
- debug ! ( "enter_opt(bcx=%s, m=%s, col=%u, val=%s)" ,
600
+ debug ! ( "enter_opt(bcx=%s, m=%s, opt=%?, col=%u, val=%s)" ,
527
601
bcx. to_str( ) ,
528
602
m. repr( bcx. tcx( ) ) ,
603
+ * opt,
529
604
col,
530
605
bcx. val_to_str( val) ) ;
531
606
let _indenter = indenter ( ) ;
532
607
533
608
let tcx = bcx. tcx ( ) ;
534
609
let dummy = @ast:: pat { id : 0 , node : ast:: pat_wild, span : dummy_sp ( ) } ;
610
+ let mut i = 0 ;
535
611
do enter_match ( bcx, tcx. def_map , m, col, val) |p| {
536
- match p. node {
612
+ let answer = match p. node {
537
613
ast:: pat_enum( * ) |
538
614
ast:: pat_ident( _, _, None ) if pat_is_const ( tcx. def_map , p) => {
539
615
let const_def = tcx. def_map . get_copy ( & p. id ) ;
@@ -599,32 +675,53 @@ fn enter_opt<'r>(bcx: @mut Block,
599
675
}
600
676
}
601
677
ast:: pat_vec( ref before, slice, ref after) => {
678
+ let ( lo, hi) = match * opt {
679
+ vec_len( _, _, ( lo, hi) ) => ( lo, hi) ,
680
+ _ => tcx. sess . span_bug ( p. span ,
681
+ "vec pattern but not vec opt" )
682
+ } ;
683
+
602
684
match slice {
603
- Some ( slice) => {
685
+ Some ( slice) if i >= lo && i <= hi => {
604
686
let n = before. len ( ) + after. len ( ) ;
605
- let i = before. len ( ) ;
606
- if opt_eq ( tcx, & vec_len_ge ( n, i) , opt) {
687
+ let this_opt = vec_len ( n, vec_len_ge ( before. len ( ) ) ,
688
+ ( lo, hi) ) ;
689
+ if opt_eq ( tcx, & this_opt, opt) {
607
690
Some ( vec:: append_one ( ( * before) . clone ( ) , slice) +
608
691
* after)
609
692
} else {
610
693
None
611
694
}
612
695
}
613
- None => {
696
+ None if i >= lo && i <= hi => {
614
697
let n = before. len ( ) ;
615
- if opt_eq ( tcx, & vec_len_eq ( n ) , opt) {
698
+ if opt_eq ( tcx, & vec_len ( n , vec_len_eq , ( lo , hi ) ) , opt) {
616
699
Some ( ( * before) . clone ( ) )
617
700
} else {
618
701
None
619
702
}
620
703
}
704
+ _ => None
621
705
}
622
706
}
623
707
_ => {
624
708
assert_is_binding_or_wild ( bcx, p) ;
625
- Some ( vec:: from_elem ( variant_size, dummy) )
709
+ // In most cases, a binding/wildcard match be
710
+ // considered to match against any Opt. However, when
711
+ // doing vector pattern matching, submatches are
712
+ // considered even if the eventual match might be from
713
+ // a different submatch. Thus, when a submatch fails
714
+ // when doing a vector match, we proceed to the next
715
+ // submatch. Thus, including a default match would
716
+ // cause the default match to fire spuriously.
717
+ match * opt {
718
+ vec_len( * ) => None ,
719
+ _ => Some ( vec:: from_elem ( variant_size, dummy) )
720
+ }
626
721
}
627
- }
722
+ } ;
723
+ i += 1 ;
724
+ answer
628
725
}
629
726
}
630
727
@@ -805,9 +902,25 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
805
902
if set. iter ( ) . any ( |l| opt_eq ( tcx, l, & val) ) { return ; }
806
903
set. push ( val) ;
807
904
}
905
+ // Vector comparisions are special in that since the actual
906
+ // conditions over-match, we need to be careful about them. This
907
+ // means that in order to properly handle things in order, we need
908
+ // to not always merge conditions.
909
+ fn add_veclen_to_set ( set : & mut ~[ Opt ] , i : uint ,
910
+ len : uint , vlo : VecLenOpt ) {
911
+ match set. last_opt ( ) {
912
+ // If the last condition in the list matches the one we want
913
+ // to add, then extend its range. Otherwise, make a new
914
+ // vec_len with a range just covering the new entry.
915
+ Some ( & vec_len( len2, vlo2, ( start, end) ) )
916
+ if len == len2 && vlo == vlo2 =>
917
+ set[ set. len ( ) - 1 ] = vec_len ( len, vlo, ( start, end+1 ) ) ,
918
+ _ => set. push ( vec_len ( len, vlo, ( i, i) ) )
919
+ }
920
+ }
808
921
809
922
let mut found = ~[ ] ;
810
- for br in m. iter ( ) {
923
+ for ( i , br ) in m. iter ( ) . enumerate ( ) {
811
924
let cur = br. pats [ col] ;
812
925
match cur. node {
813
926
ast:: pat_lit( l) => {
@@ -852,12 +965,12 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
852
965
add_to_set ( ccx. tcx , & mut found, range ( l1, l2) ) ;
853
966
}
854
967
ast:: pat_vec( ref before, slice, ref after) => {
855
- let opt = match slice {
856
- None => vec_len_eq ( before. len ( ) ) ,
857
- Some ( _) => vec_len_ge ( before. len ( ) + after. len ( ) ,
858
- before. len ( ) )
968
+ let ( len , vec_opt ) = match slice {
969
+ None => ( before. len ( ) , vec_len_eq ) ,
970
+ Some ( _) => ( before. len ( ) + after. len ( ) ,
971
+ vec_len_ge ( before. len ( ) ) )
859
972
} ;
860
- add_to_set ( ccx . tcx , & mut found, opt ) ;
973
+ add_veclen_to_set ( & mut found, i , len , vec_opt ) ;
861
974
}
862
975
_ => { }
863
976
}
@@ -1075,13 +1188,13 @@ fn pick_col(m: &[Match]) -> uint {
1075
1188
}
1076
1189
let mut scores = vec:: from_elem ( m[ 0 ] . pats . len ( ) , 0 u) ;
1077
1190
for br in m. iter ( ) {
1078
- let mut i = 0 u;
1079
- for p in br. pats . iter ( ) { scores[ i] += score ( * p) ; i += 1 u; }
1191
+ for ( i, p) in br. pats . iter ( ) . enumerate ( ) {
1192
+ scores[ i] += score ( * p) ;
1193
+ }
1080
1194
}
1081
1195
let mut max_score = 0 u;
1082
1196
let mut best_col = 0 u;
1083
- let mut i = 0 u;
1084
- for score in scores. iter ( ) {
1197
+ for ( i, score) in scores. iter ( ) . enumerate ( ) {
1085
1198
let score = * score;
1086
1199
1087
1200
// Irrefutable columns always go first, they'd only be duplicated in
@@ -1090,7 +1203,6 @@ fn pick_col(m: &[Match]) -> uint {
1090
1203
// If no irrefutable ones are found, we pick the one with the biggest
1091
1204
// branching factor.
1092
1205
if score > max_score { max_score = score; best_col = i; }
1093
- i += 1 u;
1094
1206
}
1095
1207
return best_col;
1096
1208
}
@@ -1460,7 +1572,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1460
1572
test_val = Load ( bcx, val) ;
1461
1573
kind = compare;
1462
1574
} ,
1463
- vec_len_eq ( * ) | vec_len_ge ( * ) => {
1575
+ vec_len ( * ) => {
1464
1576
let vt = tvec:: vec_types ( bcx, node_id_type ( bcx, pat_id) ) ;
1465
1577
let unboxed = load_if_immediate ( bcx, val, vt. vec_ty ) ;
1466
1578
let ( _, len) = tvec:: get_base_and_len (
@@ -1487,16 +1599,19 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1487
1599
C_int ( ccx, 0 ) // Placeholder for when not using a switch
1488
1600
} ;
1489
1601
1490
- let defaults = enter_default ( else_cx, dm, m, col, val) ;
1602
+ let defaults = enter_default ( else_cx, dm, m, col, val, chk ) ;
1491
1603
let exhaustive = chk. is_none ( ) && defaults. len ( ) == 0 u;
1492
1604
let len = opts. len ( ) ;
1493
- let mut i = 0 u;
1494
1605
1495
1606
// Compile subtrees for each option
1496
- for opt in opts. iter ( ) {
1497
- i += 1 u;
1607
+ for ( i, opt) in opts. iter ( ) . enumerate ( ) {
1608
+ // In some cases in vector pattern matching, we need to override
1609
+ // the failure case so that instead of failing, it proceeds to
1610
+ // try more matching. branch_chk, then, is the proper failure case
1611
+ // for the current conditional branch.
1612
+ let mut branch_chk = chk;
1498
1613
let mut opt_cx = else_cx;
1499
- if !exhaustive || i < len {
1614
+ if !exhaustive || i+ 1 < len {
1500
1615
opt_cx = sub_block ( bcx, "match_case" ) ;
1501
1616
match kind {
1502
1617
single => Br ( bcx, opt_cx. llbb ) ,
@@ -1586,6 +1701,10 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1586
1701
}
1587
1702
} ;
1588
1703
bcx = sub_block ( after_cx, "compare_vec_len_next" ) ;
1704
+
1705
+ // If none of these subcases match, move on to the
1706
+ // next condition.
1707
+ branch_chk = Some :: < mk_fail > ( || bcx. llbb ) ;
1589
1708
CondBr ( after_cx, matches, opt_cx. llbb , bcx. llbb ) ;
1590
1709
}
1591
1710
_ => ( )
@@ -1604,17 +1723,13 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1604
1723
unpacked = argvals;
1605
1724
opt_cx = new_bcx;
1606
1725
}
1607
- vec_len_eq( n) | vec_len_ge( n, _) => {
1608
- let n = match * opt {
1609
- vec_len_ge( * ) => n + 1 u,
1610
- _ => n
1611
- } ;
1612
- let slice = match * opt {
1613
- vec_len_ge( _, i) => Some ( i) ,
1614
- _ => None
1726
+ vec_len( n, vt, _) => {
1727
+ let ( n, slice) = match vt {
1728
+ vec_len_ge( i) => ( n + 1 u, Some ( i) ) ,
1729
+ vec_len_eq => ( n, None )
1615
1730
} ;
1616
- let args = extract_vec_elems ( opt_cx, pat_span, pat_id, n, slice ,
1617
- val, test_val) ;
1731
+ let args = extract_vec_elems ( opt_cx, pat_span, pat_id, n,
1732
+ slice , val, test_val) ;
1618
1733
size = args. vals . len ( ) ;
1619
1734
unpacked = args. vals . clone ( ) ;
1620
1735
opt_cx = args. bcx ;
@@ -1623,7 +1738,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1623
1738
}
1624
1739
let opt_ms = enter_opt ( opt_cx, m, opt, col, size, val) ;
1625
1740
let opt_vals = vec:: append ( unpacked, vals_left) ;
1626
- compile_submatch ( opt_cx, opt_ms, opt_vals, chk ) ;
1741
+ compile_submatch ( opt_cx, opt_ms, opt_vals, branch_chk ) ;
1627
1742
}
1628
1743
1629
1744
// Compile the fall-through case, if any
0 commit comments