@@ -8,10 +8,7 @@ use rustc_span::Span;
88
99use  crate :: constructor:: { Constructor ,  IntRange ,  MaybeInfiniteInt ,  SplitConstructorSet } ; 
1010use  crate :: cx:: MatchCheckCtxt ; 
11- use  crate :: errors:: { 
12-     NonExhaustiveOmittedPattern ,  NonExhaustiveOmittedPatternLintOnArm ,  Overlap , 
13-     OverlappingRangeEndpoints ,  Uncovered , 
14- } ; 
11+ use  crate :: errors; 
1512use  crate :: pat:: { DeconstructedPat ,  WitnessPat } ; 
1613use  crate :: usefulness:: PatCtxt ; 
1714use  crate :: MatchArm ; 
@@ -184,9 +181,9 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
184181                NON_EXHAUSTIVE_OMITTED_PATTERNS , 
185182                cx. match_lint_level , 
186183                cx. scrut_span , 
187-                 NonExhaustiveOmittedPattern  { 
184+                 errors :: NonExhaustiveOmittedPattern  { 
188185                    scrut_ty, 
189-                     uncovered :  Uncovered :: new ( cx. scrut_span ,  cx,  witnesses) , 
186+                     uncovered :  errors :: Uncovered :: new ( cx. scrut_span ,  cx,  witnesses) , 
190187                } , 
191188            ) ; 
192189        } 
@@ -198,7 +195,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
198195            let  ( lint_level,  lint_level_source)  =
199196                cx. tcx . lint_level_at_node ( NON_EXHAUSTIVE_OMITTED_PATTERNS ,  arm. hir_id ) ; 
200197            if  !matches ! ( lint_level,  rustc_session:: lint:: Level :: Allow )  { 
201-                 let  decorator = NonExhaustiveOmittedPatternLintOnArm  { 
198+                 let  decorator = errors :: NonExhaustiveOmittedPatternLintOnArm  { 
202199                    lint_span :  lint_level_source. span ( ) , 
203200                    suggest_lint_on_match :  cx. whole_match_span . map ( |span| span. shrink_to_lo ( ) ) , 
204201                    lint_level :  lint_level. as_str ( ) , 
@@ -215,9 +212,10 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
215212    } 
216213} 
217214
218- /// Traverse the patterns to warn the user about ranges that overlap on their endpoints. 
215+ /// Traverse the patterns to warn the user about ranges that overlap on their endpoints or are 
216+ /// distant by one. 
219217#[ instrument( level = "debug" ,  skip( cx) ) ]  
220- pub ( crate )  fn  lint_overlapping_range_endpoints < ' p ,  ' tcx > ( 
218+ pub ( crate )  fn  lint_likely_range_mistakes < ' p ,  ' tcx > ( 
221219    cx :  & MatchCheckCtxt < ' p ,  ' tcx > , 
222220    column :  & PatternColumn < ' p ,  ' tcx > , 
223221)  { 
@@ -229,24 +227,24 @@ pub(crate) fn lint_overlapping_range_endpoints<'p, 'tcx>(
229227    let  set = column. analyze_ctors ( pcx) ; 
230228
231229    if  matches ! ( ty. kind( ) ,  ty:: Char  | ty:: Int ( _)  | ty:: Uint ( _) )  { 
232-         let  emit_lint  = |overlap :  & IntRange ,  this_span :  Span ,  overlapped_spans :  & [ Span ] | { 
230+         let  emit_overlap_lint  = |overlap :  & IntRange ,  this_span :  Span ,  overlapped_spans :  & [ Span ] | { 
233231            let  overlap_as_pat = cx. hoist_pat_range ( overlap,  ty) ; 
234232            let  overlaps:  Vec < _ >  = overlapped_spans
235233                . iter ( ) 
236234                . copied ( ) 
237-                 . map ( |span| Overlap  {  range :  overlap_as_pat. clone ( ) ,  span } ) 
235+                 . map ( |span| errors :: Overlap  {  range :  overlap_as_pat. clone ( ) ,  span } ) 
238236                . collect ( ) ; 
239237            cx. tcx . emit_spanned_lint ( 
240238                lint:: builtin:: OVERLAPPING_RANGE_ENDPOINTS , 
241239                cx. match_lint_level , 
242240                this_span, 
243-                 OverlappingRangeEndpoints  {  overlap :  overlaps,  range :  this_span } , 
241+                 errors :: OverlappingRangeEndpoints  {  overlap :  overlaps,  range :  this_span } , 
244242            ) ; 
245243        } ; 
246244
247-         // If  two ranges overlapped, the split set  will contain their intersection  as a singleton. 
248-         let  split_int_ranges  = set. present . iter ( ) . filter_map ( |c| c. as_int_range ( ) ) ; 
249-         for  overlap_range in  split_int_ranges . clone ( )  { 
245+         // The  two cases we are interested in  will show up  as a singleton after range splitting . 
246+         let  present_int_ranges  = set. present . iter ( ) . filter_map ( |c| c. as_int_range ( ) ) ; 
247+         for  overlap_range in  present_int_ranges  { 
250248            if  overlap_range. is_singleton ( )  { 
251249                let  overlap:  MaybeInfiniteInt  = overlap_range. lo ; 
252250                // Ranges that look like `lo..=overlap`. 
@@ -261,29 +259,72 @@ pub(crate) fn lint_overlapping_range_endpoints<'p, 'tcx>(
261259                        // Don't lint when one of the ranges is a singleton. 
262260                        continue ; 
263261                    } 
264-                     if  this_range . lo  == overlap  { 
262+                     if  overlap  == this_range . lo  { 
265263                        // `this_range` looks like `overlap..=this_range.hi`; it overlaps with any 
266264                        // ranges that look like `lo..=overlap`. 
267265                        if  !prefixes. is_empty ( )  { 
268-                             emit_lint ( overlap_range,  this_span,  & prefixes) ; 
266+                             emit_overlap_lint ( overlap_range,  this_span,  & prefixes) ; 
269267                        } 
270268                        suffixes. push ( this_span) 
271-                     }  else  if  this_range . hi  == overlap . plus_one ( )  { 
269+                     }  else  if  overlap . plus_one ( )  == Some ( this_range . hi )  { 
272270                        // `this_range` looks like `this_range.lo..=overlap`; it overlaps with any 
273271                        // ranges that look like `overlap..=hi`. 
274272                        if  !suffixes. is_empty ( )  { 
275-                             emit_lint ( overlap_range,  this_span,  & suffixes) ; 
273+                             emit_overlap_lint ( overlap_range,  this_span,  & suffixes) ; 
276274                        } 
277275                        prefixes. push ( this_span) 
278276                    } 
279277                } 
280278            } 
281279        } 
280+ 
281+         let  missing_int_ranges = set. missing . iter ( ) . filter_map ( |c| c. as_int_range ( ) ) ; 
282+         for  point_range in  missing_int_ranges { 
283+             if  point_range. is_singleton ( )  { 
284+                 let  point:  MaybeInfiniteInt  = point_range. lo ; 
285+                 // Ranges that look like `lo..point`. 
286+                 let  mut  onebefore:  SmallVec < [ _ ;  1 ] >  = Default :: default ( ) ; 
287+                 // Ranges that look like `point+1..=hi`. 
288+                 let  mut  oneafter:  SmallVec < [ _ ;  1 ] >  = Default :: default ( ) ; 
289+                 for  pat in  column. iter ( )  { 
290+                     let  this_span = pat. span ( ) ; 
291+                     let  Constructor :: IntRange ( this_range)  = pat. ctor ( )  else  {  continue  } ; 
292+ 
293+                     if  point == this_range. hi  { 
294+                         onebefore. push ( this_span) 
295+                     }  else  if  point. plus_one ( )  == Some ( this_range. lo )  { 
296+                         oneafter. push ( this_span) 
297+                     } 
298+                 } 
299+ 
300+                 if  !onebefore. is_empty ( )  && !oneafter. is_empty ( )  { 
301+                     // We have some `lo..point` and some `point+1..hi` but no `point`. 
302+                     let  point_as_pat = cx. hoist_pat_range ( point_range,  ty) ; 
303+                     for  span_after in  oneafter { 
304+                         let  spans_before:  Vec < _ >  = onebefore
305+                             . iter ( ) 
306+                             . copied ( ) 
307+                             . map ( |span| errors:: GappedRange  {  range :  point_as_pat. clone ( ) ,  span } ) 
308+                             . collect ( ) ; 
309+                         cx. tcx . emit_spanned_lint ( 
310+                             lint:: builtin:: OVERLAPPING_RANGE_ENDPOINTS , 
311+                             cx. match_lint_level , 
312+                             span_after, 
313+                             errors:: SmallGapBetweenRanges  { 
314+                                 range :  point_as_pat. clone ( ) , 
315+                                 first_range :  span_after, 
316+                                 gap_with :  spans_before, 
317+                             } , 
318+                         ) ; 
319+                     } 
320+                 } 
321+             } 
322+         } 
282323    }  else  { 
283324        // Recurse into the fields. 
284325        for  ctor in  set. present  { 
285326            for  col in  column. specialize ( pcx,  & ctor)  { 
286-                 lint_overlapping_range_endpoints ( cx,  & col) ; 
327+                 lint_likely_range_mistakes ( cx,  & col) ; 
287328            } 
288329        } 
289330    } 
0 commit comments