@@ -7,10 +7,7 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
7
7
use rustc_span:: Span ;
8
8
9
9
use crate :: constructor:: { IntRange , MaybeInfiniteInt } ;
10
- use crate :: errors:: {
11
- NonExhaustiveOmittedPattern , NonExhaustiveOmittedPatternLintOnArm , Overlap ,
12
- OverlappingRangeEndpoints , Uncovered ,
13
- } ;
10
+ use crate :: errors;
14
11
use crate :: rustc:: {
15
12
Constructor , DeconstructedPat , MatchArm , MatchCtxt , PlaceCtxt , RustcMatchCheckCtxt ,
16
13
SplitConstructorSet , WitnessPat ,
@@ -189,9 +186,9 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
189
186
NON_EXHAUSTIVE_OMITTED_PATTERNS ,
190
187
rcx. match_lint_level ,
191
188
rcx. scrut_span ,
192
- NonExhaustiveOmittedPattern {
189
+ errors :: NonExhaustiveOmittedPattern {
193
190
scrut_ty,
194
- uncovered : Uncovered :: new ( rcx. scrut_span , rcx, witnesses) ,
191
+ uncovered : errors :: Uncovered :: new ( rcx. scrut_span , rcx, witnesses) ,
195
192
} ,
196
193
) ;
197
194
}
@@ -203,7 +200,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
203
200
let ( lint_level, lint_level_source) =
204
201
rcx. tcx . lint_level_at_node ( NON_EXHAUSTIVE_OMITTED_PATTERNS , arm. arm_data ) ;
205
202
if !matches ! ( lint_level, rustc_session:: lint:: Level :: Allow ) {
206
- let decorator = NonExhaustiveOmittedPatternLintOnArm {
203
+ let decorator = errors :: NonExhaustiveOmittedPatternLintOnArm {
207
204
lint_span : lint_level_source. span ( ) ,
208
205
suggest_lint_on_match : rcx. whole_match_span . map ( |span| span. shrink_to_lo ( ) ) ,
209
206
lint_level : lint_level. as_str ( ) ,
@@ -220,9 +217,10 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
220
217
}
221
218
}
222
219
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.
224
222
#[ 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 > (
226
224
cx : MatchCtxt < ' a , ' p , ' tcx > ,
227
225
column : & PatternColumn < ' a , ' p , ' tcx > ,
228
226
) {
@@ -235,24 +233,24 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
235
233
let set = column. analyze_ctors ( pcx) ;
236
234
237
235
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 ] | {
239
237
let overlap_as_pat = rcx. hoist_pat_range ( overlap, ty) ;
240
238
let overlaps: Vec < _ > = overlapped_spans
241
239
. iter ( )
242
240
. copied ( )
243
- . map ( |span| Overlap { range : overlap_as_pat. clone ( ) , span } )
241
+ . map ( |span| errors :: Overlap { range : overlap_as_pat. clone ( ) , span } )
244
242
. collect ( ) ;
245
243
rcx. tcx . emit_spanned_lint (
246
244
lint:: builtin:: OVERLAPPING_RANGE_ENDPOINTS ,
247
245
rcx. match_lint_level ,
248
246
this_span,
249
- OverlappingRangeEndpoints { overlap : overlaps, range : this_span } ,
247
+ errors :: OverlappingRangeEndpoints { overlap : overlaps, range : this_span } ,
250
248
) ;
251
249
} ;
252
250
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 {
256
254
if overlap_range. is_singleton ( ) {
257
255
let overlap: MaybeInfiniteInt = overlap_range. lo ;
258
256
// Ranges that look like `lo..=overlap`.
@@ -267,29 +265,72 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
267
265
// Don't lint when one of the ranges is a singleton.
268
266
continue ;
269
267
}
270
- if this_range . lo == overlap {
268
+ if overlap == this_range . lo {
271
269
// `this_range` looks like `overlap..=this_range.hi`; it overlaps with any
272
270
// ranges that look like `lo..=overlap`.
273
271
if !prefixes. is_empty ( ) {
274
- emit_lint ( overlap_range, this_span, & prefixes) ;
272
+ emit_overlap_lint ( overlap_range, this_span, & prefixes) ;
275
273
}
276
274
suffixes. push ( this_span)
277
- } else if this_range . hi == overlap . plus_one ( ) {
275
+ } else if overlap . plus_one ( ) == Some ( this_range . hi ) {
278
276
// `this_range` looks like `this_range.lo..=overlap`; it overlaps with any
279
277
// ranges that look like `overlap..=hi`.
280
278
if !suffixes. is_empty ( ) {
281
- emit_lint ( overlap_range, this_span, & suffixes) ;
279
+ emit_overlap_lint ( overlap_range, this_span, & suffixes) ;
282
280
}
283
281
prefixes. push ( this_span)
284
282
}
285
283
}
286
284
}
287
285
}
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
+ }
288
329
} else {
289
330
// Recurse into the fields.
290
331
for ctor in set. present {
291
332
for col in column. specialize ( pcx, & ctor) {
292
- lint_overlapping_range_endpoints ( cx, & col) ;
333
+ lint_likely_range_mistakes ( cx, & col) ;
293
334
}
294
335
}
295
336
}
0 commit comments