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
}
@@ -523,17 +573,19 @@ fn enter_opt<'r>(bcx: @mut Block,
523
573
variant_size : uint ,
524
574
val : ValueRef )
525
575
-> ~[ Match < ' r > ] {
526
- debug ! ( "enter_opt(bcx=%s, m=%s, col=%u, val=%s)" ,
576
+ debug ! ( "enter_opt(bcx=%s, m=%s, opt=%?, col=%u, val=%s)" ,
527
577
bcx. to_str( ) ,
528
578
m. repr( bcx. tcx( ) ) ,
579
+ * opt,
529
580
col,
530
581
bcx. val_to_str( val) ) ;
531
582
let _indenter = indenter ( ) ;
532
583
533
584
let tcx = bcx. tcx ( ) ;
534
585
let dummy = @ast:: pat { id : 0 , node : ast:: pat_wild, span : dummy_sp ( ) } ;
586
+ let mut i = 0 ;
535
587
do enter_match ( bcx, tcx. def_map , m, col, val) |p| {
536
- match p. node {
588
+ let answer = match p. node {
537
589
ast:: pat_enum( * ) |
538
590
ast:: pat_ident( _, _, None ) if pat_is_const ( tcx. def_map , p) => {
539
591
let const_def = tcx. def_map . get_copy ( & p. id ) ;
@@ -599,32 +651,53 @@ fn enter_opt<'r>(bcx: @mut Block,
599
651
}
600
652
}
601
653
ast:: pat_vec( ref before, slice, ref after) => {
654
+ let ( lo, hi) = match * opt {
655
+ vec_len( _, _, ( lo, hi) ) => ( lo, hi) ,
656
+ _ => tcx. sess . span_bug ( p. span ,
657
+ "vec pattern but not vec opt" )
658
+ } ;
659
+
602
660
match slice {
603
- Some ( slice) => {
661
+ Some ( slice) if i >= lo && i <= hi => {
604
662
let n = before. len ( ) + after. len ( ) ;
605
- let i = before. len ( ) ;
606
- if opt_eq ( tcx, & vec_len_ge ( n, i) , opt) {
663
+ let this_opt = vec_len ( n, vec_len_ge ( before. len ( ) ) ,
664
+ ( lo, hi) ) ;
665
+ if opt_eq ( tcx, & this_opt, opt) {
607
666
Some ( vec:: append_one ( ( * before) . clone ( ) , slice) +
608
667
* after)
609
668
} else {
610
669
None
611
670
}
612
671
}
613
- None => {
672
+ None if i >= lo && i <= hi => {
614
673
let n = before. len ( ) ;
615
- if opt_eq ( tcx, & vec_len_eq ( n ) , opt) {
674
+ if opt_eq ( tcx, & vec_len ( n , vec_len_eq , ( lo , hi ) ) , opt) {
616
675
Some ( ( * before) . clone ( ) )
617
676
} else {
618
677
None
619
678
}
620
679
}
680
+ _ => None
621
681
}
622
682
}
623
683
_ => {
624
684
assert_is_binding_or_wild ( bcx, p) ;
625
- Some ( vec:: from_elem ( variant_size, dummy) )
685
+ // In most cases, a binding/wildcard match be
686
+ // considered to match against any Opt. However, when
687
+ // doing vector pattern matching, submatches are
688
+ // considered even if the eventual match might be from
689
+ // a different submatch. Thus, when a submatch fails
690
+ // when doing a vector match, we proceed to the next
691
+ // submatch. Thus, including a default match would
692
+ // cause the default match to fire spuriously.
693
+ match * opt {
694
+ vec_len( * ) => None ,
695
+ _ => Some ( vec:: from_elem ( variant_size, dummy) )
696
+ }
626
697
}
627
- }
698
+ } ;
699
+ i += 1 ;
700
+ answer
628
701
}
629
702
}
630
703
@@ -805,9 +878,25 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
805
878
if set. iter ( ) . any ( |l| opt_eq ( tcx, l, & val) ) { return ; }
806
879
set. push ( val) ;
807
880
}
881
+ // Vector comparisions are special in that since the actual
882
+ // conditions over-match, we need to be careful about them. This
883
+ // means that in order to properly handle things in order, we need
884
+ // to not always merge conditions.
885
+ fn add_veclen_to_set ( set : & mut ~[ Opt ] , i : uint ,
886
+ len : uint , vlo : VecLenOpt ) {
887
+ match set. last_opt ( ) {
888
+ // If the last condition in the list matches the one we want
889
+ // to add, then extend its range. Otherwise, make a new
890
+ // vec_len with a range just covering the new entry.
891
+ Some ( & vec_len( len2, vlo2, ( start, end) ) )
892
+ if len == len2 && vlo == vlo2 =>
893
+ set[ set. len ( ) - 1 ] = vec_len ( len, vlo, ( start, end+1 ) ) ,
894
+ _ => set. push ( vec_len ( len, vlo, ( i, i) ) )
895
+ }
896
+ }
808
897
809
898
let mut found = ~[ ] ;
810
- for br in m. iter ( ) {
899
+ for ( i , br ) in m. iter ( ) . enumerate ( ) {
811
900
let cur = br. pats [ col] ;
812
901
match cur. node {
813
902
ast:: pat_lit( l) => {
@@ -852,12 +941,12 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
852
941
add_to_set ( ccx. tcx , & mut found, range ( l1, l2) ) ;
853
942
}
854
943
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 ( ) )
944
+ let ( len , vec_opt ) = match slice {
945
+ None => ( before. len ( ) , vec_len_eq ) ,
946
+ Some ( _) => ( before. len ( ) + after. len ( ) ,
947
+ vec_len_ge ( before. len ( ) ) )
859
948
} ;
860
- add_to_set ( ccx . tcx , & mut found, opt ) ;
949
+ add_veclen_to_set ( & mut found, i , len , vec_opt ) ;
861
950
}
862
951
_ => { }
863
952
}
@@ -1459,7 +1548,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1459
1548
test_val = Load ( bcx, val) ;
1460
1549
kind = compare;
1461
1550
} ,
1462
- vec_len_eq ( * ) | vec_len_ge ( * ) => {
1551
+ vec_len ( * ) => {
1463
1552
let vt = tvec:: vec_types ( bcx, node_id_type ( bcx, pat_id) ) ;
1464
1553
let unboxed = load_if_immediate ( bcx, val, vt. vec_ty ) ;
1465
1554
let ( _, len) = tvec:: get_base_and_len (
@@ -1492,6 +1581,11 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1492
1581
1493
1582
// Compile subtrees for each option
1494
1583
for ( i, opt) in opts. iter ( ) . enumerate ( ) {
1584
+ // In some cases in vector pattern matching, we need to override
1585
+ // the failure case so that instead of failing, it proceeds to
1586
+ // try more matching. branch_chk, then, is the proper failure case
1587
+ // for the current conditional branch.
1588
+ let mut branch_chk = chk;
1495
1589
let mut opt_cx = else_cx;
1496
1590
if !exhaustive || i+1 < len {
1497
1591
opt_cx = sub_block ( bcx, "match_case" ) ;
@@ -1583,6 +1677,10 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1583
1677
}
1584
1678
} ;
1585
1679
bcx = sub_block ( after_cx, "compare_vec_len_next" ) ;
1680
+
1681
+ // If none of these subcases match, move on to the
1682
+ // next condition.
1683
+ branch_chk = Some :: < mk_fail > ( || bcx. llbb ) ;
1586
1684
CondBr ( after_cx, matches, opt_cx. llbb , bcx. llbb ) ;
1587
1685
}
1588
1686
_ => ( )
@@ -1601,17 +1699,13 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1601
1699
unpacked = argvals;
1602
1700
opt_cx = new_bcx;
1603
1701
}
1604
- vec_len_eq( n) | vec_len_ge( n, _) => {
1605
- let n = match * opt {
1606
- vec_len_ge( * ) => n + 1 u,
1607
- _ => n
1608
- } ;
1609
- let slice = match * opt {
1610
- vec_len_ge( _, i) => Some ( i) ,
1611
- _ => None
1702
+ vec_len( n, vt, _) => {
1703
+ let ( n, slice) = match vt {
1704
+ vec_len_ge( i) => ( n + 1 u, Some ( i) ) ,
1705
+ vec_len_eq => ( n, None )
1612
1706
} ;
1613
- let args = extract_vec_elems ( opt_cx, pat_span, pat_id, n, slice ,
1614
- val, test_val) ;
1707
+ let args = extract_vec_elems ( opt_cx, pat_span, pat_id, n,
1708
+ slice , val, test_val) ;
1615
1709
size = args. vals . len ( ) ;
1616
1710
unpacked = args. vals . clone ( ) ;
1617
1711
opt_cx = args. bcx ;
@@ -1620,7 +1714,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
1620
1714
}
1621
1715
let opt_ms = enter_opt ( opt_cx, m, opt, col, size, val) ;
1622
1716
let opt_vals = vec:: append ( unpacked, vals_left) ;
1623
- compile_submatch ( opt_cx, opt_ms, opt_vals, chk ) ;
1717
+ compile_submatch ( opt_cx, opt_ms, opt_vals, branch_chk ) ;
1624
1718
}
1625
1719
1626
1720
// Compile the fall-through case, if any
0 commit comments