@@ -8,10 +8,7 @@ use rustc_span::Span;
8
8
9
9
use crate :: constructor:: { Constructor , IntRange , MaybeInfiniteInt , SplitConstructorSet } ;
10
10
use crate :: cx:: MatchCheckCtxt ;
11
- use crate :: errors:: {
12
- NonExhaustiveOmittedPattern , NonExhaustiveOmittedPatternLintOnArm , Overlap ,
13
- OverlappingRangeEndpoints , Uncovered ,
14
- } ;
11
+ use crate :: errors;
15
12
use crate :: pat:: { DeconstructedPat , WitnessPat } ;
16
13
use crate :: usefulness:: PatCtxt ;
17
14
use crate :: MatchArm ;
@@ -184,9 +181,9 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
184
181
NON_EXHAUSTIVE_OMITTED_PATTERNS ,
185
182
cx. match_lint_level ,
186
183
cx. scrut_span ,
187
- NonExhaustiveOmittedPattern {
184
+ errors :: NonExhaustiveOmittedPattern {
188
185
scrut_ty,
189
- uncovered : Uncovered :: new ( cx. scrut_span , cx, witnesses) ,
186
+ uncovered : errors :: Uncovered :: new ( cx. scrut_span , cx, witnesses) ,
190
187
} ,
191
188
) ;
192
189
}
@@ -198,7 +195,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
198
195
let ( lint_level, lint_level_source) =
199
196
cx. tcx . lint_level_at_node ( NON_EXHAUSTIVE_OMITTED_PATTERNS , arm. hir_id ) ;
200
197
if !matches ! ( lint_level, rustc_session:: lint:: Level :: Allow ) {
201
- let decorator = NonExhaustiveOmittedPatternLintOnArm {
198
+ let decorator = errors :: NonExhaustiveOmittedPatternLintOnArm {
202
199
lint_span : lint_level_source. span ( ) ,
203
200
suggest_lint_on_match : cx. whole_match_span . map ( |span| span. shrink_to_lo ( ) ) ,
204
201
lint_level : lint_level. as_str ( ) ,
@@ -215,9 +212,10 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
215
212
}
216
213
}
217
214
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.
219
217
#[ 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 > (
221
219
cx : & MatchCheckCtxt < ' p , ' tcx > ,
222
220
column : & PatternColumn < ' p , ' tcx > ,
223
221
) {
@@ -229,24 +227,24 @@ pub(crate) fn lint_overlapping_range_endpoints<'p, 'tcx>(
229
227
let set = column. analyze_ctors ( pcx) ;
230
228
231
229
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 ] | {
233
231
let overlap_as_pat = cx. hoist_pat_range ( overlap, ty) ;
234
232
let overlaps: Vec < _ > = overlapped_spans
235
233
. iter ( )
236
234
. copied ( )
237
- . map ( |span| Overlap { range : overlap_as_pat. clone ( ) , span } )
235
+ . map ( |span| errors :: Overlap { range : overlap_as_pat. clone ( ) , span } )
238
236
. collect ( ) ;
239
237
cx. tcx . emit_spanned_lint (
240
238
lint:: builtin:: OVERLAPPING_RANGE_ENDPOINTS ,
241
239
cx. match_lint_level ,
242
240
this_span,
243
- OverlappingRangeEndpoints { overlap : overlaps, range : this_span } ,
241
+ errors :: OverlappingRangeEndpoints { overlap : overlaps, range : this_span } ,
244
242
) ;
245
243
} ;
246
244
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 {
250
248
if overlap_range. is_singleton ( ) {
251
249
let overlap: MaybeInfiniteInt = overlap_range. lo ;
252
250
// Ranges that look like `lo..=overlap`.
@@ -261,29 +259,72 @@ pub(crate) fn lint_overlapping_range_endpoints<'p, 'tcx>(
261
259
// Don't lint when one of the ranges is a singleton.
262
260
continue ;
263
261
}
264
- if this_range . lo == overlap {
262
+ if overlap == this_range . lo {
265
263
// `this_range` looks like `overlap..=this_range.hi`; it overlaps with any
266
264
// ranges that look like `lo..=overlap`.
267
265
if !prefixes. is_empty ( ) {
268
- emit_lint ( overlap_range, this_span, & prefixes) ;
266
+ emit_overlap_lint ( overlap_range, this_span, & prefixes) ;
269
267
}
270
268
suffixes. push ( this_span)
271
- } else if this_range . hi == overlap . plus_one ( ) {
269
+ } else if overlap . plus_one ( ) == Some ( this_range . hi ) {
272
270
// `this_range` looks like `this_range.lo..=overlap`; it overlaps with any
273
271
// ranges that look like `overlap..=hi`.
274
272
if !suffixes. is_empty ( ) {
275
- emit_lint ( overlap_range, this_span, & suffixes) ;
273
+ emit_overlap_lint ( overlap_range, this_span, & suffixes) ;
276
274
}
277
275
prefixes. push ( this_span)
278
276
}
279
277
}
280
278
}
281
279
}
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
+ }
282
323
} else {
283
324
// Recurse into the fields.
284
325
for ctor in set. present {
285
326
for col in column. specialize ( pcx, & ctor) {
286
- lint_overlapping_range_endpoints ( cx, & col) ;
327
+ lint_likely_range_mistakes ( cx, & col) ;
287
328
}
288
329
}
289
330
}
0 commit comments