@@ -588,6 +588,8 @@ enum Constructor<'tcx> {
588
588
ConstantRange ( u128 , u128 , Ty < ' tcx > , RangeEnd , Span ) ,
589
589
/// Array patterns of length n.
590
590
FixedLenSlice ( u64 ) ,
591
+ /// Slice patterns. Stands for any array constructor of length >= n.
592
+ VarLenSlice ( u64 ) ,
591
593
}
592
594
593
595
// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
@@ -602,6 +604,7 @@ impl<'tcx> std::cmp::PartialEq for Constructor<'tcx> {
602
604
Constructor :: ConstantRange ( b_start, b_end, b_ty, b_range_end, _) ,
603
605
) => a_start == b_start && a_end == b_end && a_ty == b_ty && a_range_end == b_range_end,
604
606
( Constructor :: FixedLenSlice ( a) , Constructor :: FixedLenSlice ( b) ) => a == b,
607
+ ( Constructor :: VarLenSlice ( a) , Constructor :: VarLenSlice ( b) ) => a == b,
605
608
_ => false ,
606
609
}
607
610
}
@@ -611,6 +614,7 @@ impl<'tcx> Constructor<'tcx> {
611
614
fn is_slice ( & self ) -> bool {
612
615
match self {
613
616
FixedLenSlice { .. } => true ,
617
+ VarLenSlice { .. } => true ,
614
618
_ => false ,
615
619
}
616
620
}
@@ -645,6 +649,7 @@ impl<'tcx> Constructor<'tcx> {
645
649
)
646
650
}
647
651
Constructor :: FixedLenSlice ( val) => format ! ( "[{}]" , val) ,
652
+ Constructor :: VarLenSlice ( val) => format ! ( "[{}, ..]" , val) ,
648
653
_ => bug ! ( "bad constructor being displayed: `{:?}" , self ) ,
649
654
}
650
655
}
@@ -653,19 +658,59 @@ impl<'tcx> Constructor<'tcx> {
653
658
// anything in `other_ctors`.
654
659
fn subtract_ctors (
655
660
& self ,
661
+ pcx : PatCtxt < ' tcx > ,
656
662
tcx : TyCtxt < ' tcx > ,
657
663
param_env : ty:: ParamEnv < ' tcx > ,
658
664
other_ctors : & Vec < Constructor < ' tcx > > ,
659
665
) -> Vec < Constructor < ' tcx > > {
660
666
match self {
661
667
// Those constructors can only match themselves.
662
- Single | Variant ( _) | FixedLenSlice ( _ ) => {
668
+ Single | Variant ( _) => {
663
669
if other_ctors. iter ( ) . any ( |c| c == self ) {
664
670
vec ! [ ]
665
671
} else {
666
672
vec ! [ self . clone( ) ]
667
673
}
668
674
}
675
+ FixedLenSlice ( _) | VarLenSlice ( _) => {
676
+ let mut remaining_ctors = if let VarLenSlice ( len) = self {
677
+ ( * len..pcx. max_slice_length + 1 ) . map ( FixedLenSlice ) . collect ( )
678
+ } else {
679
+ vec ! [ self . clone( ) ]
680
+ } ;
681
+
682
+ // For each used ctor, subtract from the current set of constructors.
683
+ // Naming: we remove the "neg" constructors from the "pos" ones.
684
+ // Remember, VarLenSlice(n) covers the union of FixedLenSlice from
685
+ // n to infinity.
686
+ for neg_ctor in other_ctors {
687
+ remaining_ctors = remaining_ctors
688
+ . into_iter ( )
689
+ . flat_map ( |pos_ctor| -> SmallVec < [ Constructor < ' tcx > ; 1 ] > {
690
+ // Compute pos_ctor \ neg_ctor
691
+ match ( & pos_ctor, neg_ctor) {
692
+ ( FixedLenSlice ( pos_len) , VarLenSlice ( neg_len) ) => {
693
+ if neg_len <= pos_len {
694
+ smallvec ! [ ]
695
+ } else {
696
+ smallvec ! [ pos_ctor]
697
+ }
698
+ }
699
+ _ if pos_ctor == * neg_ctor => smallvec ! [ ] ,
700
+ _ => smallvec ! [ pos_ctor] ,
701
+ }
702
+ } )
703
+ . collect ( ) ;
704
+
705
+ // If the constructors that have been considered so far already cover
706
+ // the entire range of `self`, no need to look at more constructors.
707
+ if remaining_ctors. is_empty ( ) {
708
+ break ;
709
+ }
710
+ }
711
+
712
+ remaining_ctors
713
+ }
669
714
ConstantRange ( ..) | ConstantValue ( ..) => {
670
715
let mut remaining_ctors = vec ! [ self . clone( ) ] ;
671
716
for other_ctor in other_ctors {
@@ -719,7 +764,7 @@ impl<'tcx> Constructor<'tcx> {
719
764
match ty. kind {
720
765
ty:: Tuple ( ref fs) => fs. len ( ) as u64 ,
721
766
ty:: Slice ( ..) | ty:: Array ( ..) => match * self {
722
- FixedLenSlice ( length) => length,
767
+ FixedLenSlice ( length) | VarLenSlice ( length ) => length,
723
768
ConstantValue ( ..) => 0 ,
724
769
_ => bug ! ( "bad slice pattern {:?} {:?}" , self , ty) ,
725
770
} ,
@@ -999,7 +1044,7 @@ fn all_constructors<'a, 'tcx>(
999
1044
if cx. is_uninhabited ( sub_ty) {
1000
1045
vec ! [ FixedLenSlice ( 0 ) ]
1001
1046
} else {
1002
- ( 0 ..pcx . max_slice_length + 1 ) . map ( |length| FixedLenSlice ( length ) ) . collect ( )
1047
+ vec ! [ VarLenSlice ( 0 ) ]
1003
1048
}
1004
1049
}
1005
1050
ty:: Adt ( def, substs) if def. is_enum ( ) => def
@@ -1403,6 +1448,7 @@ impl<'tcx> IntRange<'tcx> {
1403
1448
1404
1449
// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
1405
1450
struct MissingConstructors < ' tcx > {
1451
+ pcx : PatCtxt < ' tcx > ,
1406
1452
tcx : TyCtxt < ' tcx > ,
1407
1453
param_env : ty:: ParamEnv < ' tcx > ,
1408
1454
all_ctors : Vec < Constructor < ' tcx > > ,
@@ -1411,12 +1457,13 @@ struct MissingConstructors<'tcx> {
1411
1457
1412
1458
impl < ' tcx > MissingConstructors < ' tcx > {
1413
1459
fn new (
1460
+ pcx : PatCtxt < ' tcx > ,
1414
1461
tcx : TyCtxt < ' tcx > ,
1415
1462
param_env : ty:: ParamEnv < ' tcx > ,
1416
1463
all_ctors : Vec < Constructor < ' tcx > > ,
1417
1464
used_ctors : Vec < Constructor < ' tcx > > ,
1418
1465
) -> Self {
1419
- MissingConstructors { tcx, param_env, all_ctors, used_ctors }
1466
+ MissingConstructors { pcx , tcx, param_env, all_ctors, used_ctors }
1420
1467
}
1421
1468
1422
1469
fn into_inner ( self ) -> ( Vec < Constructor < ' tcx > > , Vec < Constructor < ' tcx > > ) {
@@ -1435,7 +1482,7 @@ impl<'tcx> MissingConstructors<'tcx> {
1435
1482
/// Iterate over all_ctors \ used_ctors
1436
1483
fn iter < ' a > ( & ' a self ) -> impl Iterator < Item = Constructor < ' tcx > > + Captures < ' a > {
1437
1484
self . all_ctors . iter ( ) . flat_map ( move |req_ctor| {
1438
- req_ctor. subtract_ctors ( self . tcx , self . param_env , & self . used_ctors )
1485
+ req_ctor. subtract_ctors ( self . pcx , self . tcx , self . param_env , & self . used_ctors )
1439
1486
} )
1440
1487
}
1441
1488
}
@@ -1531,9 +1578,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
1531
1578
split_grouped_constructors (
1532
1579
cx. tcx ,
1533
1580
cx. param_env ,
1581
+ pcx,
1534
1582
constructors,
1535
1583
matrix,
1536
- pcx. ty ,
1537
1584
pcx. span ,
1538
1585
Some ( hir_id) ,
1539
1586
)
@@ -1578,7 +1625,8 @@ pub fn is_useful<'p, 'a, 'tcx>(
1578
1625
// non-wildcard patterns in the current column. To determine if
1579
1626
// the set is empty, we can check that `.peek().is_none()`, so
1580
1627
// we only fully construct them on-demand, because they're rarely used and can be big.
1581
- let missing_ctors = MissingConstructors :: new ( cx. tcx , cx. param_env , all_ctors, used_ctors) ;
1628
+ let missing_ctors =
1629
+ MissingConstructors :: new ( pcx, cx. tcx , cx. param_env , all_ctors, used_ctors) ;
1582
1630
1583
1631
debug ! (
1584
1632
"missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}" ,
@@ -1595,19 +1643,13 @@ pub fn is_useful<'p, 'a, 'tcx>(
1595
1643
1596
1644
if missing_ctors. is_empty ( ) && !is_non_exhaustive {
1597
1645
let ( all_ctors, _) = missing_ctors. into_inner ( ) ;
1598
- split_grouped_constructors (
1599
- cx. tcx ,
1600
- cx. param_env ,
1601
- all_ctors,
1602
- matrix,
1603
- pcx. ty ,
1604
- DUMMY_SP ,
1605
- None ,
1606
- )
1607
- . into_iter ( )
1608
- . map ( |c| is_useful_specialized ( cx, matrix, v, c, pcx. ty , witness_preference, hir_id) )
1609
- . find ( |result| result. is_useful ( ) )
1610
- . unwrap_or ( NotUseful )
1646
+ split_grouped_constructors ( cx. tcx , cx. param_env , pcx, all_ctors, matrix, DUMMY_SP , None )
1647
+ . into_iter ( )
1648
+ . map ( |c| {
1649
+ is_useful_specialized ( cx, matrix, v, c, pcx. ty , witness_preference, hir_id)
1650
+ } )
1651
+ . find ( |result| result. is_useful ( ) )
1652
+ . unwrap_or ( NotUseful )
1611
1653
} else {
1612
1654
let matrix = matrix. specialize_wildcard ( ) ;
1613
1655
let v = v. to_tail ( ) ;
@@ -1731,7 +1773,7 @@ fn pat_constructors<'tcx>(
1731
1773
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
1732
1774
let pat_len = prefix. len ( ) as u64 + suffix. len ( ) as u64 ;
1733
1775
if slice. is_some ( ) {
1734
- Some ( ( pat_len..pcx . max_slice_length + 1 ) . map ( FixedLenSlice ) . collect ( ) )
1776
+ Some ( vec ! [ VarLenSlice ( pat_len) ] )
1735
1777
} else {
1736
1778
Some ( vec ! [ FixedLenSlice ( pat_len) ] )
1737
1779
}
@@ -1755,7 +1797,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx>(
1755
1797
match ty. kind {
1756
1798
ty:: Tuple ( ref fs) => fs. into_iter ( ) . map ( |t| t. expect_ty ( ) ) . collect ( ) ,
1757
1799
ty:: Slice ( ty) | ty:: Array ( ty, _) => match * ctor {
1758
- FixedLenSlice ( length) => ( 0 ..length) . map ( |_| ty) . collect ( ) ,
1800
+ FixedLenSlice ( length) | VarLenSlice ( length ) => ( 0 ..length) . map ( |_| ty) . collect ( ) ,
1759
1801
ConstantValue ( ..) => vec ! [ ] ,
1760
1802
_ => bug ! ( "bad slice pattern {:?} {:?}" , ctor, ty) ,
1761
1803
} ,
@@ -1914,21 +1956,22 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>)
1914
1956
///
1915
1957
/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
1916
1958
/// ranges that case.
1959
+ ///
1960
+ /// This also splits variable-length slices into fixed-length slices.
1917
1961
fn split_grouped_constructors < ' p , ' tcx > (
1918
1962
tcx : TyCtxt < ' tcx > ,
1919
1963
param_env : ty:: ParamEnv < ' tcx > ,
1964
+ pcx : PatCtxt < ' tcx > ,
1920
1965
ctors : Vec < Constructor < ' tcx > > ,
1921
1966
matrix : & Matrix < ' p , ' tcx > ,
1922
- ty : Ty < ' tcx > ,
1923
1967
span : Span ,
1924
1968
hir_id : Option < HirId > ,
1925
1969
) -> Vec < Constructor < ' tcx > > {
1970
+ let ty = pcx. ty ;
1926
1971
let mut split_ctors = Vec :: with_capacity ( ctors. len ( ) ) ;
1927
1972
1928
1973
for ctor in ctors. into_iter ( ) {
1929
1974
match ctor {
1930
- // For now, only ranges may denote groups of "subconstructors", so we only need to
1931
- // special-case constant ranges.
1932
1975
ConstantRange ( ..) if should_treat_range_exhaustively ( tcx, & ctor) => {
1933
1976
// We only care about finding all the subranges within the range of the constructor
1934
1977
// range. Anything else is irrelevant, because it is guaranteed to result in
@@ -2010,6 +2053,9 @@ fn split_grouped_constructors<'p, 'tcx>(
2010
2053
split_ctors. push ( IntRange :: range_to_ctor ( tcx, ty, range, span) ) ;
2011
2054
}
2012
2055
}
2056
+ VarLenSlice ( len) => {
2057
+ split_ctors. extend ( ( len..pcx. max_slice_length + 1 ) . map ( FixedLenSlice ) )
2058
+ }
2013
2059
// Any other constructor can be used unchanged.
2014
2060
_ => split_ctors. push ( ctor) ,
2015
2061
}
@@ -2252,7 +2298,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
2252
2298
2253
2299
PatKind :: Array { ref prefix, ref slice, ref suffix }
2254
2300
| PatKind :: Slice { ref prefix, ref slice, ref suffix } => match * constructor {
2255
- FixedLenSlice ( ..) => {
2301
+ FixedLenSlice ( ..) | VarLenSlice ( .. ) => {
2256
2302
let pat_len = prefix. len ( ) + suffix. len ( ) ;
2257
2303
if let Some ( slice_count) = ctor_wild_subpatterns. len ( ) . checked_sub ( pat_len) {
2258
2304
if slice_count == 0 || slice. is_some ( ) {
0 commit comments