145145 * - `store_non_ref_bindings()`
146146 * - `insert_lllocals()`
147147 *
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+ *
148193 */
149194
150195
@@ -189,14 +234,19 @@ enum Lit {
189234 ConstLit ( ast:: def_id ) , // the def ID of the constant
190235}
191236
237+ #[ deriving( Eq ) ]
238+ pub enum VecLenOpt {
239+ vec_len_eq,
240+ vec_len_ge( /* length of prefix */ uint )
241+ }
242+
192243// An option identifying a branch (either a literal, a enum variant or a
193244// range)
194245enum Opt {
195246 lit( Lit ) ,
196247 var( /* disr val */ uint , @adt:: Repr ) ,
197248 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 ) )
200250}
201251
202252fn 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 {
247297 }
248298 }
249299 ( & 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
253303 }
254304}
255305
@@ -283,10 +333,10 @@ fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result {
283333 return range_result ( rslt ( bcx, consts:: const_expr ( ccx, l1) ) ,
284334 rslt ( bcx, consts:: const_expr ( ccx, l2) ) ) ;
285335 }
286- vec_len_eq ( n ) => {
336+ vec_len ( n , vec_len_eq , _ ) => {
287337 return single_result ( rslt ( bcx, C_int ( ccx, n as int ) ) ) ;
288338 }
289- vec_len_ge ( n , _) => {
339+ vec_len ( n , vec_len_ge ( _ ) , _) => {
290340 return lower_bound ( rslt ( bcx, C_int ( ccx, n as int ) ) ) ;
291341 }
292342 }
@@ -471,10 +521,11 @@ fn enter_match<'r>(bcx: @mut Block,
471521}
472522
473523fn 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 > )
478529 -> ~[ Match < ' r > ] {
479530 debug ! ( "enter_default(bcx=%s, m=%s, col=%u, val=%s)" ,
480531 bcx. to_str( ) ,
@@ -483,13 +534,36 @@ fn enter_default<'r>(bcx: @mut Block,
483534 bcx. val_to_str( val) ) ;
484535 let _indenter = indenter ( ) ;
485536
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| {
487539 match p. node {
488540 ast:: pat_wild | ast:: pat_tup( _) => Some ( ~[ ] ) ,
489541 ast:: pat_ident( _, _, None ) if pat_is_binding ( dm, p) => Some ( ~[ ] ) ,
490542 _ => None
491543 }
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 }
493567}
494568
495569// <pcwalton> nmatsakis: what does enter_opt do?
@@ -523,17 +597,19 @@ fn enter_opt<'r>(bcx: @mut Block,
523597 variant_size : uint ,
524598 val : ValueRef )
525599 -> ~[ 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)" ,
527601 bcx. to_str( ) ,
528602 m. repr( bcx. tcx( ) ) ,
603+ * opt,
529604 col,
530605 bcx. val_to_str( val) ) ;
531606 let _indenter = indenter ( ) ;
532607
533608 let tcx = bcx. tcx ( ) ;
534609 let dummy = @ast:: pat { id : 0 , node : ast:: pat_wild, span : dummy_sp ( ) } ;
610+ let mut i = 0 ;
535611 do enter_match ( bcx, tcx. def_map , m, col, val) |p| {
536- match p. node {
612+ let answer = match p. node {
537613 ast:: pat_enum( * ) |
538614 ast:: pat_ident( _, _, None ) if pat_is_const ( tcx. def_map , p) => {
539615 let const_def = tcx. def_map . get_copy ( & p. id ) ;
@@ -599,32 +675,53 @@ fn enter_opt<'r>(bcx: @mut Block,
599675 }
600676 }
601677 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+
602684 match slice {
603- Some ( slice) => {
685+ Some ( slice) if i >= lo && i <= hi => {
604686 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) {
607690 Some ( vec:: append_one ( ( * before) . clone ( ) , slice) +
608691 * after)
609692 } else {
610693 None
611694 }
612695 }
613- None => {
696+ None if i >= lo && i <= hi => {
614697 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) {
616699 Some ( ( * before) . clone ( ) )
617700 } else {
618701 None
619702 }
620703 }
704+ _ => None
621705 }
622706 }
623707 _ => {
624708 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+ }
626721 }
627- }
722+ } ;
723+ i += 1 ;
724+ answer
628725 }
629726}
630727
@@ -805,9 +902,25 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
805902 if set. iter ( ) . any ( |l| opt_eq ( tcx, l, & val) ) { return ; }
806903 set. push ( val) ;
807904 }
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+ }
808921
809922 let mut found = ~[ ] ;
810- for br in m. iter ( ) {
923+ for ( i , br ) in m. iter ( ) . enumerate ( ) {
811924 let cur = br. pats [ col] ;
812925 match cur. node {
813926 ast:: pat_lit( l) => {
@@ -852,12 +965,12 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
852965 add_to_set ( ccx. tcx , & mut found, range ( l1, l2) ) ;
853966 }
854967 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 ( ) ) )
859972 } ;
860- add_to_set ( ccx . tcx , & mut found, opt ) ;
973+ add_veclen_to_set ( & mut found, i , len , vec_opt ) ;
861974 }
862975 _ => { }
863976 }
@@ -1075,13 +1188,13 @@ fn pick_col(m: &[Match]) -> uint {
10751188 }
10761189 let mut scores = vec:: from_elem ( m[ 0 ] . pats . len ( ) , 0 u) ;
10771190 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+ }
10801194 }
10811195 let mut max_score = 0 u;
10821196 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 ( ) {
10851198 let score = * score;
10861199
10871200 // Irrefutable columns always go first, they'd only be duplicated in
@@ -1090,7 +1203,6 @@ fn pick_col(m: &[Match]) -> uint {
10901203 // If no irrefutable ones are found, we pick the one with the biggest
10911204 // branching factor.
10921205 if score > max_score { max_score = score; best_col = i; }
1093- i += 1 u;
10941206 }
10951207 return best_col;
10961208}
@@ -1460,7 +1572,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
14601572 test_val = Load ( bcx, val) ;
14611573 kind = compare;
14621574 } ,
1463- vec_len_eq ( * ) | vec_len_ge ( * ) => {
1575+ vec_len ( * ) => {
14641576 let vt = tvec:: vec_types ( bcx, node_id_type ( bcx, pat_id) ) ;
14651577 let unboxed = load_if_immediate ( bcx, val, vt. vec_ty ) ;
14661578 let ( _, len) = tvec:: get_base_and_len (
@@ -1487,16 +1599,19 @@ fn compile_submatch_continue(mut bcx: @mut Block,
14871599 C_int ( ccx, 0 ) // Placeholder for when not using a switch
14881600 } ;
14891601
1490- let defaults = enter_default ( else_cx, dm, m, col, val) ;
1602+ let defaults = enter_default ( else_cx, dm, m, col, val, chk ) ;
14911603 let exhaustive = chk. is_none ( ) && defaults. len ( ) == 0 u;
14921604 let len = opts. len ( ) ;
1493- let mut i = 0 u;
14941605
14951606 // 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;
14981613 let mut opt_cx = else_cx;
1499- if !exhaustive || i < len {
1614+ if !exhaustive || i+ 1 < len {
15001615 opt_cx = sub_block ( bcx, "match_case" ) ;
15011616 match kind {
15021617 single => Br ( bcx, opt_cx. llbb ) ,
@@ -1586,6 +1701,10 @@ fn compile_submatch_continue(mut bcx: @mut Block,
15861701 }
15871702 } ;
15881703 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 ) ;
15891708 CondBr ( after_cx, matches, opt_cx. llbb , bcx. llbb ) ;
15901709 }
15911710 _ => ( )
@@ -1604,17 +1723,13 @@ fn compile_submatch_continue(mut bcx: @mut Block,
16041723 unpacked = argvals;
16051724 opt_cx = new_bcx;
16061725 }
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 )
16151730 } ;
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) ;
16181733 size = args. vals . len ( ) ;
16191734 unpacked = args. vals . clone ( ) ;
16201735 opt_cx = args. bcx ;
@@ -1623,7 +1738,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
16231738 }
16241739 let opt_ms = enter_opt ( opt_cx, m, opt, col, size, val) ;
16251740 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 ) ;
16271742 }
16281743
16291744 // Compile the fall-through case, if any
0 commit comments