@@ -15,6 +15,9 @@ use self::WitnessPreference::*;
1515use rustc:: middle:: const_val:: ConstVal ;
1616use eval:: { compare_const_vals} ;
1717
18+ use rustc_const_math:: ConstInt ;
19+
20+ use rustc_data_structures:: fnv:: FnvHashMap ;
1821use rustc_data_structures:: indexed_vec:: Idx ;
1922
2023use pattern:: { FieldPattern , Pattern , PatternKind } ;
@@ -157,6 +160,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
157160 /// associated types to get field types.
158161 pub wild_pattern : & ' a Pattern < ' tcx > ,
159162 pub pattern_arena : & ' a TypedArena < Pattern < ' tcx > > ,
163+ pub byte_array_map : FnvHashMap < * const Pattern < ' tcx > , Vec < & ' a Pattern < ' tcx > > > ,
160164}
161165
162166impl < ' a , ' tcx > MatchCheckCtxt < ' a , ' tcx > {
@@ -177,8 +181,31 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
177181 tcx : tcx,
178182 wild_pattern : & wild_pattern,
179183 pattern_arena : & pattern_arena,
184+ byte_array_map : FnvHashMap ( ) ,
180185 } )
181186 }
187+
188+ // convert a byte-string pattern to a list of u8 patterns.
189+ fn lower_byte_str_pattern ( & mut self , pat : & ' a Pattern < ' tcx > ) -> Vec < & ' a Pattern < ' tcx > > {
190+ let pattern_arena = & * self . pattern_arena ;
191+ let tcx = self . tcx ;
192+ self . byte_array_map . entry ( pat) . or_insert_with ( || {
193+ match pat. kind {
194+ box PatternKind :: Constant {
195+ value : ConstVal :: ByteStr ( ref data)
196+ } => {
197+ data. iter ( ) . map ( |c| & * pattern_arena. alloc ( Pattern {
198+ ty : tcx. types . u8 ,
199+ span : pat. span ,
200+ kind : box PatternKind :: Constant {
201+ value : ConstVal :: Integral ( ConstInt :: U8 ( * c) )
202+ }
203+ } ) ) . collect ( )
204+ }
205+ _ => span_bug ! ( pat. span, "unexpected byte array pattern {:?}" , pat)
206+ }
207+ } ) . clone ( )
208+ }
182209}
183210
184211#[ derive( Clone , Debug , PartialEq ) ]
@@ -357,7 +384,8 @@ impl Witness {
357384/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
358385/// still be unmatched if the first constructor is replaced by any of the constructors
359386/// in the return value.
360- fn missing_constructors ( cx : & MatchCheckCtxt , matrix : & Matrix ,
387+ fn missing_constructors ( cx : & mut MatchCheckCtxt ,
388+ matrix : & Matrix ,
361389 pcx : PatternContext ) -> Vec < Constructor > {
362390 let used_constructors: Vec < Constructor > =
363391 matrix. 0 . iter ( )
@@ -371,14 +399,20 @@ fn missing_constructors(cx: &MatchCheckCtxt, matrix: &Matrix,
371399
372400/// This determines the set of all possible constructors of a pattern matching
373401/// values of type `left_ty`. For vectors, this would normally be an infinite set
402+ ///
403+ /// This intentionally does not list ConstantValue specializations for
404+ /// non-booleans, because we currently assume that there is always a
405+ /// "non-standard constant" that matches. See issue #12483.
406+ ///
374407/// but is instead bounded by the maximum fixed length of slice patterns in
375408/// the column of patterns being analyzed.
376- fn all_constructors ( _cx : & MatchCheckCtxt , pcx : PatternContext ) -> Vec < Constructor > {
409+ fn all_constructors ( _cx : & mut MatchCheckCtxt , pcx : PatternContext ) -> Vec < Constructor > {
377410 match pcx. ty . sty {
378411 ty:: TyBool =>
379412 [ true , false ] . iter ( ) . map ( |b| ConstantValue ( ConstVal :: Bool ( * b) ) ) . collect ( ) ,
380413 ty:: TySlice ( _) =>
381414 ( 0 ..pcx. max_slice_length +1 ) . map ( |length| Slice ( length) ) . collect ( ) ,
415+ ty:: TyArray ( _, length) => vec ! [ Slice ( length) ] ,
382416 ty:: TyAdt ( def, _) if def. is_enum ( ) && def. variants . len ( ) > 1 =>
383417 def. variants . iter ( ) . map ( |v| Variant ( v. did ) ) . collect ( ) ,
384418 _ => vec ! [ Single ]
@@ -398,7 +432,7 @@ fn all_constructors(_cx: &MatchCheckCtxt, pcx: PatternContext) -> Vec<Constructo
398432///
399433/// Note: is_useful doesn't work on empty types, as the paper notes.
400434/// So it assumes that v is non-empty.
401- pub fn is_useful < ' a , ' tcx > ( cx : & MatchCheckCtxt < ' a , ' tcx > ,
435+ pub fn is_useful < ' a , ' tcx > ( cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
402436 matrix : & Matrix < ' a , ' tcx > ,
403437 v : & [ & ' a Pattern < ' tcx > ] ,
404438 witness : WitnessPreference )
@@ -416,19 +450,22 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
416450 if rows[ 0 ] . is_empty ( ) {
417451 return NotUseful ;
418452 }
419- assert ! ( rows. iter( ) . all( |r| r. len( ) == v. len( ) ) ) ;
420453
454+ let & Matrix ( ref rows) = matrix;
455+ assert ! ( rows. iter( ) . all( |r| r. len( ) == v. len( ) ) ) ;
421456 let pcx = PatternContext {
422457 ty : rows. iter ( ) . map ( |r| r[ 0 ] . ty ) . find ( |ty| !ty. references_error ( ) )
423458 . unwrap_or ( v[ 0 ] . ty ) ,
424459 max_slice_length : rows. iter ( ) . filter_map ( |row| match * row[ 0 ] . kind {
425460 PatternKind :: Slice { ref prefix, slice : _, ref suffix } =>
426461 Some ( prefix. len ( ) + suffix. len ( ) ) ,
462+ PatternKind :: Constant { value : ConstVal :: ByteStr ( ref data) } =>
463+ Some ( data. len ( ) ) ,
427464 _ => None
428465 } ) . max ( ) . map_or ( 0 , |v| v + 1 )
429466 } ;
430467
431- debug ! ( "is_useful : pcx={:?}, expanding {:?}" , pcx, v[ 0 ] ) ;
468+ debug ! ( "is_useful_expand_first_col : pcx={:?}, expanding {:?}" , pcx, v[ 0 ] ) ;
432469
433470 if let Some ( constructors) = pat_constructors ( cx, v[ 0 ] , pcx) {
434471 debug ! ( "is_useful - expanding constructors: {:?}" , constructors) ;
@@ -453,6 +490,7 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
453490 } ) . collect ( ) ;
454491 match is_useful ( cx, & matrix, & v[ 1 ..] , witness) {
455492 UsefulWithWitness ( pats) => {
493+ let cx = & * cx;
456494 UsefulWithWitness ( pats. into_iter ( ) . flat_map ( |witness| {
457495 constructors. iter ( ) . map ( move |ctor| {
458496 witness. clone ( ) . push_wild_constructor ( cx, ctor, pcx. ty )
@@ -466,15 +504,15 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
466504}
467505
468506fn is_useful_specialized < ' a , ' tcx > (
469- cx : & MatchCheckCtxt < ' a , ' tcx > ,
507+ cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
470508 & Matrix ( ref m) : & Matrix < ' a , ' tcx > ,
471509 v : & [ & ' a Pattern < ' tcx > ] ,
472510 ctor : Constructor ,
473511 lty : Ty < ' tcx > ,
474512 witness : WitnessPreference ) -> Usefulness
475513{
476514 let arity = constructor_arity ( cx, & ctor, lty) ;
477- let matrix = Matrix ( m. iter ( ) . filter_map ( |r| {
515+ let matrix = Matrix ( m. iter ( ) . flat_map ( |r| {
478516 specialize ( cx, & r[ ..] , & ctor, 0 , arity)
479517 } ) . collect ( ) ) ;
480518 match specialize ( cx, v, & ctor, 0 , arity) {
@@ -498,22 +536,26 @@ fn is_useful_specialized<'a, 'tcx>(
498536/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
499537///
500538/// Returns None in case of a catch-all, which can't be specialized.
501- fn pat_constructors ( _cx : & MatchCheckCtxt ,
539+ fn pat_constructors ( _cx : & mut MatchCheckCtxt ,
502540 pat : & Pattern ,
503541 pcx : PatternContext )
504542 -> Option < Vec < Constructor > >
505543{
506544 match * pat. kind {
507545 PatternKind :: Binding { .. } | PatternKind :: Wild =>
508546 None ,
509- PatternKind :: Leaf { .. } | PatternKind :: Deref { .. } | PatternKind :: Array { .. } =>
547+ PatternKind :: Leaf { .. } | PatternKind :: Deref { .. } =>
510548 Some ( vec ! [ Single ] ) ,
511549 PatternKind :: Variant { adt_def, variant_index, .. } =>
512550 Some ( vec ! [ Variant ( adt_def. variants[ variant_index] . did) ] ) ,
513551 PatternKind :: Constant { ref value } =>
514552 Some ( vec ! [ ConstantValue ( value. clone( ) ) ] ) ,
515553 PatternKind :: Range { ref lo, ref hi } =>
516554 Some ( vec ! [ ConstantRange ( lo. clone( ) , hi. clone( ) ) ] ) ,
555+ PatternKind :: Array { .. } => match pcx. ty . sty {
556+ ty:: TyArray ( _, length) => Some ( vec ! [ Slice ( length) ] ) ,
557+ _ => span_bug ! ( pat. span, "bad ty {:?} for array pattern" , pcx. ty)
558+ } ,
517559 PatternKind :: Slice { ref prefix, ref slice, ref suffix } => {
518560 let pat_len = prefix. len ( ) + suffix. len ( ) ;
519561 if slice. is_some ( ) {
@@ -535,23 +577,55 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
535577 match ty. sty {
536578 ty:: TyTuple ( ref fs) => fs. len ( ) ,
537579 ty:: TyBox ( _) => 1 ,
538- ty:: TySlice ( _ ) => match * ctor {
580+ ty:: TySlice ( .. ) | ty :: TyArray ( .. ) => match * ctor {
539581 Slice ( length) => length,
540- ConstantValue ( _) => {
541- // TODO: this is utterly wrong, but required for byte arrays
542- 0
543- }
582+ ConstantValue ( _) => 0 ,
544583 _ => bug ! ( "bad slice pattern {:?} {:?}" , ctor, ty)
545584 } ,
546585 ty:: TyRef ( ..) => 1 ,
547586 ty:: TyAdt ( adt, _) => {
548587 ctor. variant_for_adt ( adt) . fields . len ( )
549588 }
550- ty:: TyArray ( _, n) => n,
551589 _ => 0
552590 }
553591}
554592
593+ fn slice_pat_covered_by_constructor ( _tcx : TyCtxt , _span : Span ,
594+ ctor : & Constructor ,
595+ prefix : & [ Pattern ] ,
596+ slice : & Option < Pattern > ,
597+ suffix : & [ Pattern ] )
598+ -> Result < bool , ErrorReported > {
599+ let data = match * ctor {
600+ ConstantValue ( ConstVal :: ByteStr ( ref data) ) => data,
601+ _ => bug ! ( )
602+ } ;
603+
604+ let pat_len = prefix. len ( ) + suffix. len ( ) ;
605+ if data. len ( ) < pat_len || ( slice. is_none ( ) && data. len ( ) > pat_len) {
606+ return Ok ( false ) ;
607+ }
608+
609+ for ( ch, pat) in
610+ data[ ..prefix. len ( ) ] . iter ( ) . zip ( prefix) . chain (
611+ data[ data. len ( ) -suffix. len ( ) ..] . iter ( ) . zip ( suffix) )
612+ {
613+ match pat. kind {
614+ box PatternKind :: Constant { ref value } => match * value {
615+ ConstVal :: Integral ( ConstInt :: U8 ( u) ) => {
616+ if u != * ch {
617+ return Ok ( false ) ;
618+ }
619+ } ,
620+ _ => span_bug ! ( pat. span, "bad const u8 {:?}" , value)
621+ } ,
622+ _ => { }
623+ }
624+ }
625+
626+ Ok ( true )
627+ }
628+
555629fn range_covered_by_constructor ( tcx : TyCtxt , span : Span ,
556630 ctor : & Constructor ,
557631 from : & ConstVal , to : & ConstVal )
@@ -568,7 +642,7 @@ fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
568642}
569643
570644fn patterns_for_variant < ' a , ' tcx > (
571- cx : & MatchCheckCtxt < ' a , ' tcx > ,
645+ cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
572646 subpatterns : & ' a [ FieldPattern < ' tcx > ] ,
573647 arity : usize )
574648 -> Vec < & ' a Pattern < ' tcx > >
@@ -592,7 +666,7 @@ fn patterns_for_variant<'a, 'tcx>(
592666/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
593667/// fields filled with wild patterns.
594668fn specialize < ' a , ' tcx > (
595- cx : & MatchCheckCtxt < ' a , ' tcx > ,
669+ cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
596670 r : & [ & ' a Pattern < ' tcx > ] ,
597671 constructor : & Constructor , col : usize , arity : usize )
598672 -> Option < Vec < & ' a Pattern < ' tcx > > >
@@ -616,13 +690,27 @@ fn specialize<'a, 'tcx>(
616690 PatternKind :: Deref { ref subpattern } => Some ( vec ! [ subpattern] ) ,
617691
618692 PatternKind :: Constant { ref value } => {
619- assert_eq ! ( constructor_arity( cx, constructor, pat. ty) , 0 ) ;
620- match range_covered_by_constructor (
621- cx. tcx , pat. span , constructor, value, value
622- ) {
623- Ok ( true ) => Some ( vec ! [ ] ) ,
624- Ok ( false ) => None ,
625- Err ( ErrorReported ) => None ,
693+ match * constructor {
694+ Slice ( ..) => match * value {
695+ ConstVal :: ByteStr ( ref data) => {
696+ if arity == data. len ( ) {
697+ Some ( cx. lower_byte_str_pattern ( pat) )
698+ } else {
699+ None
700+ }
701+ }
702+ _ => span_bug ! ( pat. span,
703+ "unexpected const-val {:?} with ctor {:?}" , value, constructor)
704+ } ,
705+ _ => {
706+ match range_covered_by_constructor (
707+ cx. tcx , pat. span , constructor, value, value
708+ ) {
709+ Ok ( true ) => Some ( vec ! [ ] ) ,
710+ Ok ( false ) => None ,
711+ Err ( ErrorReported ) => None ,
712+ }
713+ }
626714 }
627715 }
628716
@@ -636,29 +724,36 @@ fn specialize<'a, 'tcx>(
636724 }
637725 }
638726
639- PatternKind :: Array { ref prefix, slice : _, ref suffix } => {
640- let pat_len = prefix. len ( ) + suffix. len ( ) ;
641- Some (
642- prefix. iter ( ) . chain (
643- repeat ( cx. wild_pattern ) . take ( arity - pat_len) . chain (
644- suffix. iter ( )
645- ) ) . collect ( ) )
646- }
647-
727+ PatternKind :: Array { ref prefix, ref slice, ref suffix } |
648728 PatternKind :: Slice { ref prefix, ref slice, ref suffix } => {
649- let pat_len = prefix. len ( ) + suffix. len ( ) ;
650- if let Some ( slice_count) = arity. checked_sub ( pat_len) {
651- if slice_count == 0 || slice. is_some ( ) {
652- Some (
653- prefix. iter ( ) . chain (
654- repeat ( cx. wild_pattern ) . take ( slice_count) . chain (
655- suffix. iter ( )
656- ) ) . collect ( ) )
657- } else {
658- None
729+ match * constructor {
730+ Slice ( ..) => {
731+ let pat_len = prefix. len ( ) + suffix. len ( ) ;
732+ if let Some ( slice_count) = arity. checked_sub ( pat_len) {
733+ if slice_count == 0 || slice. is_some ( ) {
734+ Some (
735+ prefix. iter ( ) . chain (
736+ repeat ( cx. wild_pattern ) . take ( slice_count) . chain (
737+ suffix. iter ( )
738+ ) ) . collect ( ) )
739+ } else {
740+ None
741+ }
742+ } else {
743+ None
744+ }
659745 }
660- } else {
661- None
746+ ConstantValue ( ..) => {
747+ match slice_pat_covered_by_constructor (
748+ cx. tcx , pat. span , constructor, prefix, slice, suffix
749+ ) {
750+ Ok ( true ) => Some ( vec ! [ ] ) ,
751+ Ok ( false ) => None ,
752+ Err ( ErrorReported ) => None
753+ }
754+ }
755+ _ => span_bug ! ( pat. span,
756+ "unexpected ctor {:?} for slice pat" , constructor)
662757 }
663758 }
664759 } ;
0 commit comments