@@ -7,10 +7,7 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
77use rustc_span:: Span ;
88
99use crate :: constructor:: { IntRange , MaybeInfiniteInt } ;
10- use crate :: errors:: {
11- NonExhaustiveOmittedPattern , NonExhaustiveOmittedPatternLintOnArm , Overlap ,
12- OverlappingRangeEndpoints , Uncovered ,
13- } ;
10+ use crate :: errors;
1411use crate :: rustc:: {
1512 Constructor , DeconstructedPat , MatchArm , MatchCtxt , PlaceCtxt , RustcMatchCheckCtxt ,
1613 SplitConstructorSet , WitnessPat ,
@@ -189,9 +186,9 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
189186 NON_EXHAUSTIVE_OMITTED_PATTERNS ,
190187 rcx. match_lint_level ,
191188 rcx. scrut_span ,
192- NonExhaustiveOmittedPattern {
189+ errors :: NonExhaustiveOmittedPattern {
193190 scrut_ty,
194- uncovered : Uncovered :: new ( rcx. scrut_span , rcx, witnesses) ,
191+ uncovered : errors :: Uncovered :: new ( rcx. scrut_span , rcx, witnesses) ,
195192 } ,
196193 ) ;
197194 }
@@ -203,7 +200,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
203200 let ( lint_level, lint_level_source) =
204201 rcx. tcx . lint_level_at_node ( NON_EXHAUSTIVE_OMITTED_PATTERNS , arm. arm_data ) ;
205202 if !matches ! ( lint_level, rustc_session:: lint:: Level :: Allow ) {
206- let decorator = NonExhaustiveOmittedPatternLintOnArm {
203+ let decorator = errors :: NonExhaustiveOmittedPatternLintOnArm {
207204 lint_span : lint_level_source. span ( ) ,
208205 suggest_lint_on_match : rcx. whole_match_span . map ( |span| span. shrink_to_lo ( ) ) ,
209206 lint_level : lint_level. as_str ( ) ,
@@ -220,9 +217,10 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
220217 }
221218}
222219
223- /// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
220+ /// Traverse the patterns to warn the user about ranges that overlap on their endpoints or are
221+ /// distant by one.
224222#[ instrument( level = "debug" , skip( cx) ) ]
225- pub ( crate ) fn lint_overlapping_range_endpoints < ' a , ' p , ' tcx > (
223+ pub ( crate ) fn lint_likely_range_mistakes < ' a , ' p , ' tcx > (
226224 cx : MatchCtxt < ' a , ' p , ' tcx > ,
227225 column : & PatternColumn < ' a , ' p , ' tcx > ,
228226) {
@@ -235,24 +233,24 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
235233 let set = column. analyze_ctors ( pcx) ;
236234
237235 if matches ! ( ty. kind( ) , ty:: Char | ty:: Int ( _) | ty:: Uint ( _) ) {
238- let emit_lint = |overlap : & IntRange , this_span : Span , overlapped_spans : & [ Span ] | {
236+ let emit_overlap_lint = |overlap : & IntRange , this_span : Span , overlapped_spans : & [ Span ] | {
239237 let overlap_as_pat = rcx. hoist_pat_range ( overlap, ty) ;
240238 let overlaps: Vec < _ > = overlapped_spans
241239 . iter ( )
242240 . copied ( )
243- . map ( |span| Overlap { range : overlap_as_pat. clone ( ) , span } )
241+ . map ( |span| errors :: Overlap { range : overlap_as_pat. clone ( ) , span } )
244242 . collect ( ) ;
245243 rcx. tcx . emit_spanned_lint (
246244 lint:: builtin:: OVERLAPPING_RANGE_ENDPOINTS ,
247245 rcx. match_lint_level ,
248246 this_span,
249- OverlappingRangeEndpoints { overlap : overlaps, range : this_span } ,
247+ errors :: OverlappingRangeEndpoints { overlap : overlaps, range : this_span } ,
250248 ) ;
251249 } ;
252250
253- // If two ranges overlapped, the split set will contain their intersection as a singleton.
254- let split_int_ranges = set. present . iter ( ) . filter_map ( |c| c. as_int_range ( ) ) ;
255- for overlap_range in split_int_ranges . clone ( ) {
251+ // The two cases we are interested in will show up as a singleton after range splitting .
252+ let present_int_ranges = set. present . iter ( ) . filter_map ( |c| c. as_int_range ( ) ) ;
253+ for overlap_range in present_int_ranges {
256254 if overlap_range. is_singleton ( ) {
257255 let overlap: MaybeInfiniteInt = overlap_range. lo ;
258256 // Ranges that look like `lo..=overlap`.
@@ -267,29 +265,72 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
267265 // Don't lint when one of the ranges is a singleton.
268266 continue ;
269267 }
270- if this_range . lo == overlap {
268+ if overlap == this_range . lo {
271269 // `this_range` looks like `overlap..=this_range.hi`; it overlaps with any
272270 // ranges that look like `lo..=overlap`.
273271 if !prefixes. is_empty ( ) {
274- emit_lint ( overlap_range, this_span, & prefixes) ;
272+ emit_overlap_lint ( overlap_range, this_span, & prefixes) ;
275273 }
276274 suffixes. push ( this_span)
277- } else if this_range . hi == overlap . plus_one ( ) {
275+ } else if overlap . plus_one ( ) == Some ( this_range . hi ) {
278276 // `this_range` looks like `this_range.lo..=overlap`; it overlaps with any
279277 // ranges that look like `overlap..=hi`.
280278 if !suffixes. is_empty ( ) {
281- emit_lint ( overlap_range, this_span, & suffixes) ;
279+ emit_overlap_lint ( overlap_range, this_span, & suffixes) ;
282280 }
283281 prefixes. push ( this_span)
284282 }
285283 }
286284 }
287285 }
286+
287+ let missing_int_ranges = set. missing . iter ( ) . filter_map ( |c| c. as_int_range ( ) ) ;
288+ for point_range in missing_int_ranges {
289+ if point_range. is_singleton ( ) {
290+ let point: MaybeInfiniteInt = point_range. lo ;
291+ // Ranges that look like `lo..point`.
292+ let mut onebefore: SmallVec < [ _ ; 1 ] > = Default :: default ( ) ;
293+ // Ranges that look like `point+1..=hi`.
294+ let mut oneafter: SmallVec < [ _ ; 1 ] > = Default :: default ( ) ;
295+ for pat in column. iter ( ) {
296+ let this_span = * pat. data ( ) ;
297+ let Constructor :: IntRange ( this_range) = pat. ctor ( ) else { continue } ;
298+
299+ if point == this_range. hi && !this_range. is_singleton ( ) {
300+ onebefore. push ( this_span)
301+ } else if point. plus_one ( ) == Some ( this_range. lo ) {
302+ oneafter. push ( this_span)
303+ }
304+ }
305+
306+ if !onebefore. is_empty ( ) && !oneafter. is_empty ( ) {
307+ // We have some `lo..point` and some `point+1..hi` but no `point`.
308+ let point_as_pat = rcx. hoist_pat_range ( point_range, ty) ;
309+ for span_after in oneafter {
310+ let spans_before: Vec < _ > = onebefore
311+ . iter ( )
312+ . copied ( )
313+ . map ( |span| errors:: GappedRange { range : point_as_pat. clone ( ) , span } )
314+ . collect ( ) ;
315+ rcx. tcx . emit_spanned_lint (
316+ lint:: builtin:: SMALL_GAPS_BETWEEN_RANGES ,
317+ rcx. match_lint_level ,
318+ span_after,
319+ errors:: SmallGapBetweenRanges {
320+ range : point_as_pat. clone ( ) ,
321+ first_range : span_after,
322+ gap_with : spans_before,
323+ } ,
324+ ) ;
325+ }
326+ }
327+ }
328+ }
288329 } else {
289330 // Recurse into the fields.
290331 for ctor in set. present {
291332 for col in column. specialize ( pcx, & ctor) {
292- lint_overlapping_range_endpoints ( cx, & col) ;
333+ lint_likely_range_mistakes ( cx, & col) ;
293334 }
294335 }
295336 }
0 commit comments