Skip to content

Commit c3d4577

Browse files
author
Michael Wright
committed
Fix match_overlapping_arm false negative
Fixes #7816
1 parent 310ecb0 commit c3d4577

File tree

3 files changed

+44
-25
lines changed

3 files changed

+44
-25
lines changed

clippy_lints/src/matches.rs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ use rustc_span::source_map::{Span, Spanned};
3434
use rustc_span::sym;
3535
use std::cmp::Ordering;
3636
use std::collections::hash_map::Entry;
37-
use std::iter;
3837
use std::ops::Bound;
3938

4039
declare_clippy_lint! {
@@ -1703,12 +1702,6 @@ where
17031702
}
17041703

17051704
impl<'a, T: Copy> Kind<'a, T> {
1706-
fn range(&self) -> &'a SpannedRange<T> {
1707-
match *self {
1708-
Kind::Start(_, r) | Kind::End(_, r) => r,
1709-
}
1710-
}
1711-
17121705
fn value(self) -> Bound<T> {
17131706
match self {
17141707
Kind::Start(t, _) => Bound::Included(t),
@@ -1726,7 +1719,19 @@ where
17261719
impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
17271720
fn cmp(&self, other: &Self) -> Ordering {
17281721
match (self.value(), other.value()) {
1729-
(Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b),
1722+
(Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => {
1723+
let value_cmp = a.cmp(&b);
1724+
// In the case of ties, starts come before ends
1725+
if value_cmp == Ordering::Equal {
1726+
match (self, other) {
1727+
(Kind::Start(..), Kind::End(..)) => Ordering::Less,
1728+
(Kind::End(..), Kind::Start(..)) => Ordering::Greater,
1729+
_ => Ordering::Equal,
1730+
}
1731+
} else {
1732+
value_cmp
1733+
}
1734+
},
17301735
// Range patterns cannot be unbounded (yet)
17311736
(Bound::Unbounded, _) | (_, Bound::Unbounded) => unimplemented!(),
17321737
(Bound::Included(a), Bound::Excluded(b)) => match a.cmp(&b) {
@@ -1750,24 +1755,17 @@ where
17501755

17511756
values.sort();
17521757

1753-
for (a, b) in iter::zip(&values, values.iter().skip(1)) {
1754-
match (a, b) {
1755-
(&Kind::Start(_, ra), &Kind::End(_, rb)) => {
1756-
if ra.node != rb.node {
1757-
return Some((ra, rb));
1758-
}
1759-
},
1760-
(&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
1761-
_ => {
1762-
// skip if the range `a` is completely included into the range `b`
1763-
if let Ordering::Equal | Ordering::Less = a.cmp(b) {
1764-
let kind_a = Kind::End(a.range().node.1, a.range());
1765-
let kind_b = Kind::End(b.range().node.1, b.range());
1766-
if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
1767-
return None;
1758+
let mut started = vec![];
1759+
1760+
for value in values {
1761+
match value {
1762+
Kind::Start(_, r) => started.push(r),
1763+
Kind::End(_, er) => {
1764+
if let Some(sr) = started.pop() {
1765+
if sr != er {
1766+
return Some((er, sr));
17681767
}
17691768
}
1770-
return Some((a.range(), b.range()));
17711769
},
17721770
}
17731771
}

tests/ui/match_overlapping_arm.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ fn overlapping() {
100100
_ => (),
101101
}
102102

103+
// Issue #7816 - overlap after included range
104+
match 42 {
105+
5..=10 => (),
106+
0..=20 => (),
107+
21..=30 => (),
108+
21..=40 => (),
109+
_ => (),
110+
}
111+
103112
// Issue #7829
104113
match 0 {
105114
-1..=1 => (),

tests/ui/match_overlapping_arm.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,17 @@ note: overlaps with this
7171
LL | ..26 => println!("..26"),
7272
| ^^^^
7373

74-
error: aborting due to 6 previous errors
74+
error: some ranges overlap
75+
--> $DIR/match_overlapping_arm.rs:107:9
76+
|
77+
LL | 21..=30 => (),
78+
| ^^^^^^^
79+
|
80+
note: overlaps with this
81+
--> $DIR/match_overlapping_arm.rs:108:9
82+
|
83+
LL | 21..=40 => (),
84+
| ^^^^^^^
85+
86+
error: aborting due to 7 previous errors
7587

0 commit comments

Comments
 (0)