308
308
use self :: ArmType :: * ;
309
309
use self :: Usefulness :: * ;
310
310
use super :: deconstruct_pat:: {
311
- Constructor , ConstructorSet , DeconstructedPat , SplitConstructorSet , WitnessPat ,
311
+ Constructor , ConstructorSet , DeconstructedPat , IntRange , SplitConstructorSet , WitnessPat ,
312
312
} ;
313
- use crate :: errors:: { NonExhaustiveOmittedPattern , Uncovered } ;
313
+ use crate :: errors:: { NonExhaustiveOmittedPattern , Overlap , OverlappingRangeEndpoints , Uncovered } ;
314
314
315
315
use rustc_data_structures:: captures:: Captures ;
316
316
@@ -319,6 +319,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
319
319
use rustc_hir:: def_id:: DefId ;
320
320
use rustc_hir:: HirId ;
321
321
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
322
+ use rustc_session:: lint;
322
323
use rustc_session:: lint:: builtin:: NON_EXHAUSTIVE_OMITTED_PATTERNS ;
323
324
use rustc_span:: { Span , DUMMY_SP } ;
324
325
@@ -475,11 +476,6 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
475
476
Matrix { patterns : vec ! [ ] }
476
477
}
477
478
478
- /// Number of columns of this matrix. `None` is the matrix is empty.
479
- pub ( super ) fn column_count ( & self ) -> Option < usize > {
480
- self . patterns . get ( 0 ) . map ( |r| r. len ( ) )
481
- }
482
-
483
479
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
484
480
/// expands it.
485
481
fn push ( & mut self , row : PatStack < ' p , ' tcx > ) {
@@ -835,15 +831,6 @@ fn is_useful<'p, 'tcx>(
835
831
836
832
let v_ctor = v. head ( ) . ctor ( ) ;
837
833
debug ! ( ?v_ctor) ;
838
- if let Constructor :: IntRange ( ctor_range) = & v_ctor {
839
- // Lint on likely incorrect range patterns (#63987)
840
- ctor_range. lint_overlapping_range_endpoints (
841
- pcx,
842
- matrix. heads ( ) ,
843
- matrix. column_count ( ) . unwrap_or ( 0 ) ,
844
- lint_root,
845
- )
846
- }
847
834
// We split the head constructor of `v`.
848
835
let split_ctors = v_ctor. split ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
849
836
// For each constructor, we compute whether there's a value that starts with it that would
@@ -903,6 +890,9 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
903
890
let column_ctors = self . patterns . iter ( ) . map ( |p| p. ctor ( ) ) ;
904
891
ConstructorSet :: for_ty ( pcx. cx , pcx. ty ) . split ( pcx, column_ctors)
905
892
}
893
+ fn iter < ' a > ( & ' a self ) -> impl Iterator < Item = & ' p DeconstructedPat < ' p , ' tcx > > + Captures < ' a > {
894
+ self . patterns . iter ( ) . copied ( )
895
+ }
906
896
907
897
/// Does specialization: given a constructor, this takes the patterns from the column that match
908
898
/// the constructor, and outputs their fields.
@@ -993,6 +983,82 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
993
983
witnesses
994
984
}
995
985
986
+ /// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
987
+ #[ instrument( level = "debug" , skip( cx, lint_root) ) ]
988
+ fn lint_overlapping_range_endpoints < ' p , ' tcx > (
989
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
990
+ column : & PatternColumn < ' p , ' tcx > ,
991
+ lint_root : HirId ,
992
+ ) {
993
+ if column. is_empty ( ) {
994
+ return ;
995
+ }
996
+ let ty = column. head_ty ( ) ;
997
+ let pcx = & PatCtxt { cx, ty, span : DUMMY_SP , is_top_level : false } ;
998
+
999
+ let set = column. analyze_ctors ( pcx) ;
1000
+
1001
+ if IntRange :: is_integral ( ty) {
1002
+ let emit_lint = |overlap : & IntRange , this_span : Span , overlapped_spans : & [ Span ] | {
1003
+ let overlap_as_pat = overlap. to_pat ( cx. tcx , ty) ;
1004
+ let overlaps: Vec < _ > = overlapped_spans
1005
+ . iter ( )
1006
+ . copied ( )
1007
+ . map ( |span| Overlap { range : overlap_as_pat. clone ( ) , span } )
1008
+ . collect ( ) ;
1009
+ cx. tcx . emit_spanned_lint (
1010
+ lint:: builtin:: OVERLAPPING_RANGE_ENDPOINTS ,
1011
+ lint_root,
1012
+ this_span,
1013
+ OverlappingRangeEndpoints { overlap : overlaps, range : this_span } ,
1014
+ ) ;
1015
+ } ;
1016
+
1017
+ // If two ranges overlapped, the split set will contain their intersection as a singleton.
1018
+ let split_int_ranges = set. present . iter ( ) . filter_map ( |c| c. as_int_range ( ) ) ;
1019
+ for overlap_range in split_int_ranges. clone ( ) {
1020
+ if overlap_range. is_singleton ( ) {
1021
+ let overlap: u128 = overlap_range. boundaries ( ) . 0 ;
1022
+ // Spans of ranges that start or end with the overlap.
1023
+ let mut prefixes: SmallVec < [ _ ; 1 ] > = Default :: default ( ) ;
1024
+ let mut suffixes: SmallVec < [ _ ; 1 ] > = Default :: default ( ) ;
1025
+ // Iterate on patterns that contained `overlap`.
1026
+ for pat in column. iter ( ) {
1027
+ let this_span = pat. span ( ) ;
1028
+ let Constructor :: IntRange ( this_range) = pat. ctor ( ) else { continue } ;
1029
+ if this_range. is_singleton ( ) {
1030
+ // Don't lint when one of the ranges is a singleton.
1031
+ continue ;
1032
+ }
1033
+ let ( start, end) = this_range. boundaries ( ) ;
1034
+ if start == overlap {
1035
+ // `this_range` looks like `overlap..=end`; it overlaps with any ranges that
1036
+ // look like `start..=overlap`.
1037
+ if !prefixes. is_empty ( ) {
1038
+ emit_lint ( overlap_range, this_span, & prefixes) ;
1039
+ }
1040
+ suffixes. push ( this_span)
1041
+ } else if end == overlap {
1042
+ // `this_range` looks like `start..=overlap`; it overlaps with any ranges
1043
+ // that look like `overlap..=end`.
1044
+ if !suffixes. is_empty ( ) {
1045
+ emit_lint ( overlap_range, this_span, & suffixes) ;
1046
+ }
1047
+ prefixes. push ( this_span)
1048
+ }
1049
+ }
1050
+ }
1051
+ }
1052
+ } else {
1053
+ // Recurse into the fields.
1054
+ for ctor in set. present {
1055
+ for col in column. specialize ( pcx, & ctor) {
1056
+ lint_overlapping_range_endpoints ( cx, & col, lint_root) ;
1057
+ }
1058
+ }
1059
+ }
1060
+ }
1061
+
996
1062
/// The arm of a match expression.
997
1063
#[ derive( Clone , Copy , Debug ) ]
998
1064
pub ( crate ) struct MatchArm < ' p , ' tcx > {
@@ -1063,6 +1129,10 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1063
1129
NoWitnesses { .. } => bug ! ( ) ,
1064
1130
} ;
1065
1131
1132
+ let pat_column = arms. iter ( ) . flat_map ( |arm| arm. pat . flatten_or_pat ( ) ) . collect :: < Vec < _ > > ( ) ;
1133
+ let pat_column = PatternColumn :: new ( pat_column) ;
1134
+ lint_overlapping_range_endpoints ( cx, & pat_column, lint_root) ;
1135
+
1066
1136
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
1067
1137
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
1068
1138
if cx. refutable
@@ -1072,10 +1142,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1072
1142
rustc_session:: lint:: Level :: Allow
1073
1143
)
1074
1144
{
1075
- let pat_column = arms. iter ( ) . flat_map ( |arm| arm. pat . flatten_or_pat ( ) ) . collect :: < Vec < _ > > ( ) ;
1076
- let pat_column = PatternColumn :: new ( pat_column) ;
1077
1145
let witnesses = collect_nonexhaustive_missing_variants ( cx, & pat_column) ;
1078
-
1079
1146
if !witnesses. is_empty ( ) {
1080
1147
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
1081
1148
// is not exhaustive enough.
0 commit comments