Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3ef781c

Browse files
committedDec 20, 2023
Lint small gaps between ranges
1 parent 57ad505 commit 3ef781c

File tree

13 files changed

+399
-82
lines changed

13 files changed

+399
-82
lines changed
 

‎compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ declare_lint_pass! {
8787
RUST_2021_PRELUDE_COLLISIONS,
8888
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
8989
SINGLE_USE_LIFETIMES,
90+
SMALL_GAPS_BETWEEN_RANGES,
9091
SOFT_UNSTABLE,
9192
STABLE_FEATURES,
9293
SUSPICIOUS_AUTO_TRAIT_IMPLS,
@@ -835,6 +836,35 @@ declare_lint! {
835836
"detects range patterns with overlapping endpoints"
836837
}
837838

839+
declare_lint! {
840+
/// The `small_gaps_between_ranges` lint detects `match` expressions that use [range patterns]
841+
/// that skip over a single number.
842+
///
843+
/// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns
844+
///
845+
/// ### Example
846+
///
847+
/// ```rust
848+
/// let x = 123u32;
849+
/// match x {
850+
/// 0..100 => { println!("small"); }
851+
/// 101..1000 => { println!("large"); }
852+
/// _ => { println!("larger"); }
853+
/// }
854+
/// ```
855+
///
856+
/// {{produces}}
857+
///
858+
/// ### Explanation
859+
///
860+
/// It is likely a mistake to have range patterns in a match expression that miss out a single
861+
/// number. Check that the beginning and end values are what you expect, and keep in mind that
862+
/// with `..=` the right bound is inclusive, and with `..` it is exclusive.
863+
pub SMALL_GAPS_BETWEEN_RANGES,
864+
Warn,
865+
"detects range patterns separated by a single number"
866+
}
867+
838868
declare_lint! {
839869
/// The `bindings_with_variant_name` lint detects pattern bindings with
840870
/// the same name as one of the matched variants.

‎compiler/rustc_pattern_analysis/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ pattern_analysis_overlapping_range_endpoints = multiple patterns overlap on thei
1111
.label = ... with this range
1212
.note = you likely meant to write mutually exclusive ranges
1313
14+
pattern_analysis_small_gap_between_ranges = multiple ranges are one apart
15+
.label = ... with this range
16+
.note = you likely meant to match `{$range}` too
17+
1418
pattern_analysis_uncovered = {$count ->
1519
[1] pattern `{$witness_1}`
1620
[2] patterns `{$witness_1}` and `{$witness_2}`

‎compiler/rustc_pattern_analysis/src/constructor.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ impl fmt::Display for RangeEnd {
193193
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
194194
pub enum MaybeInfiniteInt {
195195
NegInfinity,
196-
/// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite`.
196+
/// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite_{int,uint}`.
197197
#[non_exhaustive]
198198
Finite(u128),
199199
/// The integer after `u128::MAX`. We need it to represent `x..=u128::MAX` as an exclusive range.
@@ -230,25 +230,22 @@ impl MaybeInfiniteInt {
230230
}
231231

232232
/// Note: this will not turn a finite value into an infinite one or vice-versa.
233-
pub fn minus_one(self) -> Self {
233+
pub fn minus_one(self) -> Option<Self> {
234234
match self {
235-
Finite(n) => match n.checked_sub(1) {
236-
Some(m) => Finite(m),
237-
None => panic!("Called `MaybeInfiniteInt::minus_one` on 0"),
238-
},
239-
JustAfterMax => Finite(u128::MAX),
240-
x => x,
235+
Finite(n) => n.checked_sub(1).map(Finite),
236+
JustAfterMax => Some(Finite(u128::MAX)),
237+
x => Some(x),
241238
}
242239
}
243240
/// Note: this will not turn a finite value into an infinite one or vice-versa.
244-
pub fn plus_one(self) -> Self {
241+
pub fn plus_one(self) -> Option<Self> {
245242
match self {
246243
Finite(n) => match n.checked_add(1) {
247-
Some(m) => Finite(m),
248-
None => JustAfterMax,
244+
Some(m) => Some(Finite(m)),
245+
None => Some(JustAfterMax),
249246
},
250-
JustAfterMax => panic!("Called `MaybeInfiniteInt::plus_one` on u128::MAX+1"),
251-
x => x,
247+
JustAfterMax => None,
248+
x => Some(x),
252249
}
253250
}
254251
}
@@ -269,18 +266,25 @@ impl IntRange {
269266
pub fn is_singleton(&self) -> bool {
270267
// Since `lo` and `hi` can't be the same `Infinity` and `plus_one` never changes from finite
271268
// to infinite, this correctly only detects ranges that contain exacly one `Finite(x)`.
272-
self.lo.plus_one() == self.hi
269+
// `unwrap()` is ok since `self.lo` will never be `JustAfterMax`.
270+
self.lo.plus_one().unwrap() == self.hi
273271
}
274272

273+
/// Construct a singleton range.
274+
/// `x` be a `Finite(_)` value.
275275
#[inline]
276276
pub fn from_singleton(x: MaybeInfiniteInt) -> IntRange {
277-
IntRange { lo: x, hi: x.plus_one() }
277+
// `unwrap()` is ok on a finite value
278+
IntRange { lo: x, hi: x.plus_one().unwrap() }
278279
}
279280

281+
/// Construct a range with these boundaries.
282+
/// `lo` must not be `PosInfinity` or `JustAfterMax`. `hi` must not be `NegInfinity`.
283+
/// If `end` is `Included`, `hi` must also not be `JustAfterMax`.
280284
#[inline]
281285
pub fn from_range(lo: MaybeInfiniteInt, mut hi: MaybeInfiniteInt, end: RangeEnd) -> IntRange {
282286
if end == RangeEnd::Included {
283-
hi = hi.plus_one();
287+
hi = hi.plus_one().unwrap();
284288
}
285289
if lo >= hi {
286290
// This should have been caught earlier by E0030.

‎compiler/rustc_pattern_analysis/src/errors.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,36 @@ impl<'tcx> AddToDiagnostic for Overlap<'tcx> {
7272
}
7373
}
7474

75+
#[derive(LintDiagnostic)]
76+
#[diag(pattern_analysis_small_gap_between_ranges)]
77+
#[note]
78+
pub struct SmallGapBetweenRanges<'tcx> {
79+
#[label]
80+
pub first_range: Span,
81+
pub range: Pat<'tcx>,
82+
#[subdiagnostic]
83+
pub gap_with: Vec<GappedRange<'tcx>>,
84+
}
85+
86+
pub struct GappedRange<'tcx> {
87+
pub span: Span,
88+
pub range: Pat<'tcx>,
89+
}
90+
91+
impl<'tcx> AddToDiagnostic for GappedRange<'tcx> {
92+
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
93+
where
94+
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
95+
{
96+
let GappedRange { span, range } = self;
97+
98+
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
99+
// does not support `#[subdiagnostic(eager)]`...
100+
let message = format!("this range has a small gap on `{range}`...");
101+
diag.span_label(span, message);
102+
}
103+
}
104+
75105
#[derive(LintDiagnostic)]
76106
#[diag(pattern_analysis_non_exhaustive_omitted_pattern)]
77107
#[help]

‎compiler/rustc_pattern_analysis/src/lib.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,7 @@ use rustc_index::Idx;
2626
use rustc_middle::ty::Ty;
2727

2828
use crate::constructor::{Constructor, ConstructorSet};
29-
#[cfg(feature = "rustc")]
30-
use crate::lints::{
31-
lint_nonexhaustive_missing_variants, lint_overlapping_range_endpoints, PatternColumn,
32-
};
3329
use crate::pat::DeconstructedPat;
34-
#[cfg(feature = "rustc")]
35-
use crate::rustc::RustcMatchCheckCtxt;
36-
#[cfg(feature = "rustc")]
37-
use crate::usefulness::{compute_match_usefulness, ValidityConstraint};
3830

3931
// It's not possible to only enable the `typed_arena` dependency when the `rustc` feature is off, so
4032
// we use another feature instead. The crate won't compile if one of these isn't enabled.
@@ -109,26 +101,32 @@ impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {}
109101
/// useful, and runs some lints.
110102
#[cfg(feature = "rustc")]
111103
pub fn analyze_match<'p, 'tcx>(
112-
tycx: &RustcMatchCheckCtxt<'p, 'tcx>,
104+
tycx: &rustc::RustcMatchCheckCtxt<'p, 'tcx>,
113105
arms: &[rustc::MatchArm<'p, 'tcx>],
114106
scrut_ty: Ty<'tcx>,
115107
) -> rustc::UsefulnessReport<'p, 'tcx> {
108+
use crate::lints::PatternColumn;
109+
use crate::usefulness::ValidityConstraint;
110+
116111
// Arena to store the extra wildcards we construct during analysis.
117112
let wildcard_arena = tycx.pattern_arena;
118113
let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
119114
let cx = MatchCtxt { tycx, wildcard_arena };
120115

121-
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
116+
let report = usefulness::compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
122117

123-
let pat_column = PatternColumn::new(arms);
118+
// Only run the lints if the match is exhaustive.
119+
if report.non_exhaustiveness_witnesses.is_empty() {
120+
let pat_column = PatternColumn::new(arms);
124121

125-
// Lint on ranges that overlap on their endpoints, which is likely a mistake.
126-
lint_overlapping_range_endpoints(cx, &pat_column);
122+
// Detect possible range-related mistakes.
123+
lints::lint_likely_range_mistakes(cx, &pat_column);
127124

128-
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
129-
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
130-
if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
131-
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)
125+
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid
126+
// hitting `if let`s.
127+
if tycx.refutable {
128+
lints::lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)
129+
}
132130
}
133131

134132
report

‎compiler/rustc_pattern_analysis/src/lints.rs

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
77
use rustc_span::Span;
88

99
use crate::constructor::{IntRange, MaybeInfiniteInt};
10-
use crate::errors::{
11-
NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap,
12-
OverlappingRangeEndpoints, Uncovered,
13-
};
10+
use crate::errors;
1411
use 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
}

‎compiler/rustc_pattern_analysis/src/rustc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,12 +659,12 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
659659
let value = mir::Const::from_ty_const(c, cx.tcx);
660660
lo = PatRangeBoundary::Finite(value);
661661
}
662-
let hi = if matches!(range.hi, Finite(0)) {
662+
let hi = if let Some(hi) = range.hi.minus_one() {
663+
hi
664+
} else {
663665
// The range encodes `..ty::MIN`, so we can't convert it to an inclusive range.
664666
end = rustc_hir::RangeEnd::Excluded;
665667
range.hi
666-
} else {
667-
range.hi.minus_one()
668668
};
669669
let hi = cx.hoist_pat_range_bdy(hi, ty);
670670
PatKind::Range(Box::new(PatRange { lo, hi, end, ty }))

‎tests/ui/match/issue-18060.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// run-pass
22
// Regression test for #18060: match arms were matching in the wrong order.
33

4+
#[allow(overlapping_range_endpoints)]
5+
#[allow(small_gaps_between_ranges)]
46
fn main() {
57
assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
68
assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });

‎tests/ui/mir/mir_match_test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![feature(exclusive_range_pattern)]
22
#![allow(overlapping_range_endpoints)]
3+
#![allow(small_gaps_between_ranges)]
34

45
// run-pass
56

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#![feature(exclusive_range_pattern)]
2+
#![deny(small_gaps_between_ranges)]
3+
4+
macro_rules! m {
5+
($s:expr, $t1:pat, $t2:pat) => {
6+
match $s {
7+
$t1 => {}
8+
$t2 => {}
9+
_ => {}
10+
}
11+
};
12+
}
13+
14+
fn main() {
15+
m!(0u8, 20..30, 31..=40); //~ ERROR multiple ranges are one apart
16+
m!(0u8, 31..=40, 20..30); //~ ERROR multiple ranges are one apart
17+
m!(0u8, 20..30, 29..=40); //~ WARN multiple patterns overlap on their endpoints
18+
m!(0u8, 20..30, 30..=40);
19+
m!(0u8, 20..30, 31..=40); //~ ERROR multiple ranges are one apart
20+
m!(0u8, 20..30, 32..=40);
21+
m!(0u8, 20..30, 31); //~ ERROR multiple ranges are one apart
22+
m!(0u8, 20..30, 31..=32); //~ ERROR multiple ranges are one apart
23+
// Don't lint if the lower one is a singleton.
24+
m!(0u8, 30, 32..=40);
25+
// Don't lint two singletons.
26+
m!(0u8, 30, 32);
27+
28+
// Don't lint if the gap is caught by another range.
29+
match 0u8 {
30+
0..10 => {}
31+
11..20 => {}
32+
10 => {}
33+
_ => {}
34+
}
35+
match 0u8 {
36+
0..10 => {}
37+
11..20 => {}
38+
5..15 => {}
39+
_ => {}
40+
}
41+
42+
match 0u8 {
43+
0..10 => {}
44+
21..30 => {} //~ ERROR multiple ranges are one apart
45+
11..20 => {} //~ ERROR multiple ranges are one apart
46+
_ => {}
47+
}
48+
match (0u8, true) {
49+
(0..10, true) => {}
50+
(11..20, true) => {} //~ ERROR multiple ranges are one apart
51+
(11..20, false) => {} //~ ERROR multiple ranges are one apart
52+
_ => {}
53+
}
54+
match (true, 0u8) {
55+
(true, 0..10) => {}
56+
(true, 11..20) => {} //~ ERROR multiple ranges are one apart
57+
(false, 11..20) => {} //~ ERROR multiple ranges are one apart
58+
_ => {}
59+
}
60+
match Some(0u8) {
61+
Some(0..10) => {}
62+
Some(11..20) => {} //~ ERROR multiple ranges are one apart
63+
_ => {}
64+
}
65+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
error: multiple ranges are one apart
2+
--> $DIR/gap_between_ranges.rs:15:21
3+
|
4+
LL | m!(0u8, 20..30, 31..=40);
5+
| ------ ^^^^^^^ ... with this range
6+
| |
7+
| this range has a small gap on `30_u8`...
8+
|
9+
= note: you likely meant to match `30_u8` too
10+
note: the lint level is defined here
11+
--> $DIR/gap_between_ranges.rs:2:9
12+
|
13+
LL | #![deny(small_gaps_between_ranges)]
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
15+
16+
error: multiple ranges are one apart
17+
--> $DIR/gap_between_ranges.rs:16:13
18+
|
19+
LL | m!(0u8, 31..=40, 20..30);
20+
| ^^^^^^^ ------ this range has a small gap on `30_u8`...
21+
| |
22+
| ... with this range
23+
|
24+
= note: you likely meant to match `30_u8` too
25+
26+
warning: multiple patterns overlap on their endpoints
27+
--> $DIR/gap_between_ranges.rs:17:21
28+
|
29+
LL | m!(0u8, 20..30, 29..=40);
30+
| ------ ^^^^^^^ ... with this range
31+
| |
32+
| this range overlaps on `29_u8`...
33+
|
34+
= note: you likely meant to write mutually exclusive ranges
35+
= note: `#[warn(overlapping_range_endpoints)]` on by default
36+
37+
error: multiple ranges are one apart
38+
--> $DIR/gap_between_ranges.rs:19:21
39+
|
40+
LL | m!(0u8, 20..30, 31..=40);
41+
| ------ ^^^^^^^ ... with this range
42+
| |
43+
| this range has a small gap on `30_u8`...
44+
|
45+
= note: you likely meant to match `30_u8` too
46+
47+
error: multiple ranges are one apart
48+
--> $DIR/gap_between_ranges.rs:21:21
49+
|
50+
LL | m!(0u8, 20..30, 31);
51+
| ------ ^^ ... with this range
52+
| |
53+
| this range has a small gap on `30_u8`...
54+
|
55+
= note: you likely meant to match `30_u8` too
56+
57+
error: multiple ranges are one apart
58+
--> $DIR/gap_between_ranges.rs:22:21
59+
|
60+
LL | m!(0u8, 20..30, 31..=32);
61+
| ------ ^^^^^^^ ... with this range
62+
| |
63+
| this range has a small gap on `30_u8`...
64+
|
65+
= note: you likely meant to match `30_u8` too
66+
67+
error: multiple ranges are one apart
68+
--> $DIR/gap_between_ranges.rs:45:9
69+
|
70+
LL | 0..10 => {}
71+
| ----- this range has a small gap on `10_u8`...
72+
LL | 21..30 => {}
73+
LL | 11..20 => {}
74+
| ^^^^^^ ... with this range
75+
|
76+
= note: you likely meant to match `10_u8` too
77+
78+
error: multiple ranges are one apart
79+
--> $DIR/gap_between_ranges.rs:44:9
80+
|
81+
LL | 21..30 => {}
82+
| ^^^^^^ ... with this range
83+
LL | 11..20 => {}
84+
| ------ this range has a small gap on `20_u8`...
85+
|
86+
= note: you likely meant to match `20_u8` too
87+
88+
error: multiple ranges are one apart
89+
--> $DIR/gap_between_ranges.rs:50:10
90+
|
91+
LL | (0..10, true) => {}
92+
| ----- this range has a small gap on `10_u8`...
93+
LL | (11..20, true) => {}
94+
| ^^^^^^ ... with this range
95+
|
96+
= note: you likely meant to match `10_u8` too
97+
98+
error: multiple ranges are one apart
99+
--> $DIR/gap_between_ranges.rs:51:10
100+
|
101+
LL | (0..10, true) => {}
102+
| ----- this range has a small gap on `10_u8`...
103+
LL | (11..20, true) => {}
104+
LL | (11..20, false) => {}
105+
| ^^^^^^ ... with this range
106+
|
107+
= note: you likely meant to match `10_u8` too
108+
109+
error: multiple ranges are one apart
110+
--> $DIR/gap_between_ranges.rs:56:16
111+
|
112+
LL | (true, 0..10) => {}
113+
| ----- this range has a small gap on `10_u8`...
114+
LL | (true, 11..20) => {}
115+
| ^^^^^^ ... with this range
116+
|
117+
= note: you likely meant to match `10_u8` too
118+
119+
error: multiple ranges are one apart
120+
--> $DIR/gap_between_ranges.rs:57:17
121+
|
122+
LL | (true, 0..10) => {}
123+
| ----- this range has a small gap on `10_u8`...
124+
LL | (true, 11..20) => {}
125+
LL | (false, 11..20) => {}
126+
| ^^^^^^ ... with this range
127+
|
128+
= note: you likely meant to match `10_u8` too
129+
130+
error: multiple ranges are one apart
131+
--> $DIR/gap_between_ranges.rs:62:14
132+
|
133+
LL | Some(0..10) => {}
134+
| ----- this range has a small gap on `10_u8`...
135+
LL | Some(11..20) => {}
136+
| ^^^^^^ ... with this range
137+
|
138+
= note: you likely meant to match `10_u8` too
139+
140+
error: aborting due to 12 previous errors; 1 warning emitted
141+

‎tests/ui/pattern/usefulness/integer-ranges/reachability.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![feature(exclusive_range_pattern)]
22
#![allow(overlapping_range_endpoints)]
3+
#![allow(small_gaps_between_ranges)]
34
#![deny(unreachable_patterns)]
45

56
macro_rules! m {

‎tests/ui/pattern/usefulness/integer-ranges/reachability.stderr

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,157 @@
11
error: unreachable pattern
2-
--> $DIR/reachability.rs:18:17
2+
--> $DIR/reachability.rs:19:17
33
|
44
LL | m!(0u8, 42, 42);
55
| ^^
66
|
77
note: the lint level is defined here
8-
--> $DIR/reachability.rs:3:9
8+
--> $DIR/reachability.rs:4:9
99
|
1010
LL | #![deny(unreachable_patterns)]
1111
| ^^^^^^^^^^^^^^^^^^^^
1212

1313
error: unreachable pattern
14-
--> $DIR/reachability.rs:22:22
14+
--> $DIR/reachability.rs:23:22
1515
|
1616
LL | m!(0u8, 20..=30, 20);
1717
| ^^
1818

1919
error: unreachable pattern
20-
--> $DIR/reachability.rs:23:22
20+
--> $DIR/reachability.rs:24:22
2121
|
2222
LL | m!(0u8, 20..=30, 21);
2323
| ^^
2424

2525
error: unreachable pattern
26-
--> $DIR/reachability.rs:24:22
26+
--> $DIR/reachability.rs:25:22
2727
|
2828
LL | m!(0u8, 20..=30, 25);
2929
| ^^
3030

3131
error: unreachable pattern
32-
--> $DIR/reachability.rs:25:22
32+
--> $DIR/reachability.rs:26:22
3333
|
3434
LL | m!(0u8, 20..=30, 29);
3535
| ^^
3636

3737
error: unreachable pattern
38-
--> $DIR/reachability.rs:26:22
38+
--> $DIR/reachability.rs:27:22
3939
|
4040
LL | m!(0u8, 20..=30, 30);
4141
| ^^
4242

4343
error: unreachable pattern
44-
--> $DIR/reachability.rs:29:21
44+
--> $DIR/reachability.rs:30:21
4545
|
4646
LL | m!(0u8, 20..30, 20);
4747
| ^^
4848

4949
error: unreachable pattern
50-
--> $DIR/reachability.rs:30:21
50+
--> $DIR/reachability.rs:31:21
5151
|
5252
LL | m!(0u8, 20..30, 21);
5353
| ^^
5454

5555
error: unreachable pattern
56-
--> $DIR/reachability.rs:31:21
56+
--> $DIR/reachability.rs:32:21
5757
|
5858
LL | m!(0u8, 20..30, 25);
5959
| ^^
6060

6161
error: unreachable pattern
62-
--> $DIR/reachability.rs:32:21
62+
--> $DIR/reachability.rs:33:21
6363
|
6464
LL | m!(0u8, 20..30, 29);
6565
| ^^
6666

6767
error: unreachable pattern
68-
--> $DIR/reachability.rs:36:22
68+
--> $DIR/reachability.rs:37:22
6969
|
7070
LL | m!(0u8, 20..=30, 20..=30);
7171
| ^^^^^^^
7272

7373
error: unreachable pattern
74-
--> $DIR/reachability.rs:37:22
74+
--> $DIR/reachability.rs:38:22
7575
|
7676
LL | m!(0u8, 20.. 30, 20.. 30);
7777
| ^^^^^^^
7878

7979
error: unreachable pattern
80-
--> $DIR/reachability.rs:38:22
80+
--> $DIR/reachability.rs:39:22
8181
|
8282
LL | m!(0u8, 20..=30, 20.. 30);
8383
| ^^^^^^^
8484

8585
error: unreachable pattern
86-
--> $DIR/reachability.rs:40:22
86+
--> $DIR/reachability.rs:41:22
8787
|
8888
LL | m!(0u8, 20..=30, 21..=30);
8989
| ^^^^^^^
9090

9191
error: unreachable pattern
92-
--> $DIR/reachability.rs:41:22
92+
--> $DIR/reachability.rs:42:22
9393
|
9494
LL | m!(0u8, 20..=30, 20..=29);
9595
| ^^^^^^^
9696

9797
error: unreachable pattern
98-
--> $DIR/reachability.rs:43:24
98+
--> $DIR/reachability.rs:44:24
9999
|
100100
LL | m!('a', 'A'..='z', 'a'..='z');
101101
| ^^^^^^^^^
102102

103103
error: unreachable pattern
104-
--> $DIR/reachability.rs:50:9
104+
--> $DIR/reachability.rs:51:9
105105
|
106106
LL | 5..=8 => {},
107107
| ^^^^^
108108

109109
error: unreachable pattern
110-
--> $DIR/reachability.rs:56:9
110+
--> $DIR/reachability.rs:57:9
111111
|
112112
LL | 5..15 => {},
113113
| ^^^^^
114114

115115
error: unreachable pattern
116-
--> $DIR/reachability.rs:63:9
116+
--> $DIR/reachability.rs:64:9
117117
|
118118
LL | 5..25 => {},
119119
| ^^^^^
120120

121121
error: unreachable pattern
122-
--> $DIR/reachability.rs:71:9
122+
--> $DIR/reachability.rs:72:9
123123
|
124124
LL | 5..25 => {},
125125
| ^^^^^
126126

127127
error: unreachable pattern
128-
--> $DIR/reachability.rs:77:9
128+
--> $DIR/reachability.rs:78:9
129129
|
130130
LL | 5..15 => {},
131131
| ^^^^^
132132

133133
error: unreachable pattern
134-
--> $DIR/reachability.rs:84:9
134+
--> $DIR/reachability.rs:85:9
135135
|
136136
LL | _ => {},
137137
| - matches any value
138138
LL | '\u{D7FF}'..='\u{E000}' => {},
139139
| ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
140140

141141
error: unreachable pattern
142-
--> $DIR/reachability.rs:89:9
142+
--> $DIR/reachability.rs:90:9
143143
|
144144
LL | '\u{D7FF}'..='\u{E000}' => {},
145145
| ^^^^^^^^^^^^^^^^^^^^^^^
146146

147147
error: unreachable pattern
148-
--> $DIR/reachability.rs:105:9
148+
--> $DIR/reachability.rs:106:9
149149
|
150150
LL | &FOO => {}
151151
| ^^^^
152152

153153
error: unreachable pattern
154-
--> $DIR/reachability.rs:106:9
154+
--> $DIR/reachability.rs:107:9
155155
|
156156
LL | BAR => {}
157157
| ^^^

0 commit comments

Comments
 (0)
Please sign in to comment.