@@ -15,6 +15,9 @@ use self::WitnessPreference::*;
15
15
use rustc:: middle:: const_val:: ConstVal ;
16
16
use eval:: { compare_const_vals} ;
17
17
18
+ use rustc_const_math:: ConstInt ;
19
+
20
+ use rustc_data_structures:: fnv:: FnvHashMap ;
18
21
use rustc_data_structures:: indexed_vec:: Idx ;
19
22
20
23
use pattern:: { FieldPattern , Pattern , PatternKind } ;
@@ -157,6 +160,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
157
160
/// associated types to get field types.
158
161
pub wild_pattern : & ' a Pattern < ' tcx > ,
159
162
pub pattern_arena : & ' a TypedArena < Pattern < ' tcx > > ,
163
+ pub byte_array_map : FnvHashMap < * const Pattern < ' tcx > , Vec < & ' a Pattern < ' tcx > > > ,
160
164
}
161
165
162
166
impl < ' a , ' tcx > MatchCheckCtxt < ' a , ' tcx > {
@@ -177,8 +181,31 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
177
181
tcx : tcx,
178
182
wild_pattern : & wild_pattern,
179
183
pattern_arena : & pattern_arena,
184
+ byte_array_map : FnvHashMap ( ) ,
180
185
} )
181
186
}
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
+ }
182
209
}
183
210
184
211
#[ derive( Clone , Debug , PartialEq ) ]
@@ -357,7 +384,8 @@ impl Witness {
357
384
/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
358
385
/// still be unmatched if the first constructor is replaced by any of the constructors
359
386
/// in the return value.
360
- fn missing_constructors ( cx : & MatchCheckCtxt , matrix : & Matrix ,
387
+ fn missing_constructors ( cx : & mut MatchCheckCtxt ,
388
+ matrix : & Matrix ,
361
389
pcx : PatternContext ) -> Vec < Constructor > {
362
390
let used_constructors: Vec < Constructor > =
363
391
matrix. 0 . iter ( )
@@ -371,14 +399,20 @@ fn missing_constructors(cx: &MatchCheckCtxt, matrix: &Matrix,
371
399
372
400
/// This determines the set of all possible constructors of a pattern matching
373
401
/// 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
+ ///
374
407
/// but is instead bounded by the maximum fixed length of slice patterns in
375
408
/// 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 > {
377
410
match pcx. ty . sty {
378
411
ty:: TyBool =>
379
412
[ true , false ] . iter ( ) . map ( |b| ConstantValue ( ConstVal :: Bool ( * b) ) ) . collect ( ) ,
380
413
ty:: TySlice ( _) =>
381
414
( 0 ..pcx. max_slice_length +1 ) . map ( |length| Slice ( length) ) . collect ( ) ,
415
+ ty:: TyArray ( _, length) => vec ! [ Slice ( length) ] ,
382
416
ty:: TyAdt ( def, _) if def. is_enum ( ) && def. variants . len ( ) > 1 =>
383
417
def. variants . iter ( ) . map ( |v| Variant ( v. did ) ) . collect ( ) ,
384
418
_ => vec ! [ Single ]
@@ -398,7 +432,7 @@ fn all_constructors(_cx: &MatchCheckCtxt, pcx: PatternContext) -> Vec<Constructo
398
432
///
399
433
/// Note: is_useful doesn't work on empty types, as the paper notes.
400
434
/// 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 > ,
402
436
matrix : & Matrix < ' a , ' tcx > ,
403
437
v : & [ & ' a Pattern < ' tcx > ] ,
404
438
witness : WitnessPreference )
@@ -416,19 +450,22 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
416
450
if rows[ 0 ] . is_empty ( ) {
417
451
return NotUseful ;
418
452
}
419
- assert ! ( rows. iter( ) . all( |r| r. len( ) == v. len( ) ) ) ;
420
453
454
+ let & Matrix ( ref rows) = matrix;
455
+ assert ! ( rows. iter( ) . all( |r| r. len( ) == v. len( ) ) ) ;
421
456
let pcx = PatternContext {
422
457
ty : rows. iter ( ) . map ( |r| r[ 0 ] . ty ) . find ( |ty| !ty. references_error ( ) )
423
458
. unwrap_or ( v[ 0 ] . ty ) ,
424
459
max_slice_length : rows. iter ( ) . filter_map ( |row| match * row[ 0 ] . kind {
425
460
PatternKind :: Slice { ref prefix, slice : _, ref suffix } =>
426
461
Some ( prefix. len ( ) + suffix. len ( ) ) ,
462
+ PatternKind :: Constant { value : ConstVal :: ByteStr ( ref data) } =>
463
+ Some ( data. len ( ) ) ,
427
464
_ => None
428
465
} ) . max ( ) . map_or ( 0 , |v| v + 1 )
429
466
} ;
430
467
431
- debug ! ( "is_useful : pcx={:?}, expanding {:?}" , pcx, v[ 0 ] ) ;
468
+ debug ! ( "is_useful_expand_first_col : pcx={:?}, expanding {:?}" , pcx, v[ 0 ] ) ;
432
469
433
470
if let Some ( constructors) = pat_constructors ( cx, v[ 0 ] , pcx) {
434
471
debug ! ( "is_useful - expanding constructors: {:?}" , constructors) ;
@@ -453,6 +490,7 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
453
490
} ) . collect ( ) ;
454
491
match is_useful ( cx, & matrix, & v[ 1 ..] , witness) {
455
492
UsefulWithWitness ( pats) => {
493
+ let cx = & * cx;
456
494
UsefulWithWitness ( pats. into_iter ( ) . flat_map ( |witness| {
457
495
constructors. iter ( ) . map ( move |ctor| {
458
496
witness. clone ( ) . push_wild_constructor ( cx, ctor, pcx. ty )
@@ -466,15 +504,15 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
466
504
}
467
505
468
506
fn is_useful_specialized < ' a , ' tcx > (
469
- cx : & MatchCheckCtxt < ' a , ' tcx > ,
507
+ cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
470
508
& Matrix ( ref m) : & Matrix < ' a , ' tcx > ,
471
509
v : & [ & ' a Pattern < ' tcx > ] ,
472
510
ctor : Constructor ,
473
511
lty : Ty < ' tcx > ,
474
512
witness : WitnessPreference ) -> Usefulness
475
513
{
476
514
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| {
478
516
specialize ( cx, & r[ ..] , & ctor, 0 , arity)
479
517
} ) . collect ( ) ) ;
480
518
match specialize ( cx, v, & ctor, 0 , arity) {
@@ -498,22 +536,26 @@ fn is_useful_specialized<'a, 'tcx>(
498
536
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
499
537
///
500
538
/// 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 ,
502
540
pat : & Pattern ,
503
541
pcx : PatternContext )
504
542
-> Option < Vec < Constructor > >
505
543
{
506
544
match * pat. kind {
507
545
PatternKind :: Binding { .. } | PatternKind :: Wild =>
508
546
None ,
509
- PatternKind :: Leaf { .. } | PatternKind :: Deref { .. } | PatternKind :: Array { .. } =>
547
+ PatternKind :: Leaf { .. } | PatternKind :: Deref { .. } =>
510
548
Some ( vec ! [ Single ] ) ,
511
549
PatternKind :: Variant { adt_def, variant_index, .. } =>
512
550
Some ( vec ! [ Variant ( adt_def. variants[ variant_index] . did) ] ) ,
513
551
PatternKind :: Constant { ref value } =>
514
552
Some ( vec ! [ ConstantValue ( value. clone( ) ) ] ) ,
515
553
PatternKind :: Range { ref lo, ref hi } =>
516
554
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
+ } ,
517
559
PatternKind :: Slice { ref prefix, ref slice, ref suffix } => {
518
560
let pat_len = prefix. len ( ) + suffix. len ( ) ;
519
561
if slice. is_some ( ) {
@@ -535,23 +577,55 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
535
577
match ty. sty {
536
578
ty:: TyTuple ( ref fs) => fs. len ( ) ,
537
579
ty:: TyBox ( _) => 1 ,
538
- ty:: TySlice ( _ ) => match * ctor {
580
+ ty:: TySlice ( .. ) | ty :: TyArray ( .. ) => match * ctor {
539
581
Slice ( length) => length,
540
- ConstantValue ( _) => {
541
- // TODO: this is utterly wrong, but required for byte arrays
542
- 0
543
- }
582
+ ConstantValue ( _) => 0 ,
544
583
_ => bug ! ( "bad slice pattern {:?} {:?}" , ctor, ty)
545
584
} ,
546
585
ty:: TyRef ( ..) => 1 ,
547
586
ty:: TyAdt ( adt, _) => {
548
587
ctor. variant_for_adt ( adt) . fields . len ( )
549
588
}
550
- ty:: TyArray ( _, n) => n,
551
589
_ => 0
552
590
}
553
591
}
554
592
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
+
555
629
fn range_covered_by_constructor ( tcx : TyCtxt , span : Span ,
556
630
ctor : & Constructor ,
557
631
from : & ConstVal , to : & ConstVal )
@@ -568,7 +642,7 @@ fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
568
642
}
569
643
570
644
fn patterns_for_variant < ' a , ' tcx > (
571
- cx : & MatchCheckCtxt < ' a , ' tcx > ,
645
+ cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
572
646
subpatterns : & ' a [ FieldPattern < ' tcx > ] ,
573
647
arity : usize )
574
648
-> Vec < & ' a Pattern < ' tcx > >
@@ -592,7 +666,7 @@ fn patterns_for_variant<'a, 'tcx>(
592
666
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
593
667
/// fields filled with wild patterns.
594
668
fn specialize < ' a , ' tcx > (
595
- cx : & MatchCheckCtxt < ' a , ' tcx > ,
669
+ cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
596
670
r : & [ & ' a Pattern < ' tcx > ] ,
597
671
constructor : & Constructor , col : usize , arity : usize )
598
672
-> Option < Vec < & ' a Pattern < ' tcx > > >
@@ -616,13 +690,27 @@ fn specialize<'a, 'tcx>(
616
690
PatternKind :: Deref { ref subpattern } => Some ( vec ! [ subpattern] ) ,
617
691
618
692
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
+ }
626
714
}
627
715
}
628
716
@@ -636,29 +724,36 @@ fn specialize<'a, 'tcx>(
636
724
}
637
725
}
638
726
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 } |
648
728
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
+ }
659
745
}
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)
662
757
}
663
758
}
664
759
} ;
0 commit comments