Merge pull request #1490 from Manishearth/excl_range_pat_overlap
correctly check exclusive range patterns for overlap
This commit is contained in:
commit
909ef37f08
@ -10,6 +10,7 @@
|
|||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![feature(repeat_str)]
|
#![feature(repeat_str)]
|
||||||
#![feature(conservative_impl_trait)]
|
#![feature(conservative_impl_trait)]
|
||||||
|
#![feature(collections_bound)]
|
||||||
|
|
||||||
#![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)]
|
#![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)]
|
||||||
#![allow(needless_lifetimes)]
|
#![allow(needless_lifetimes)]
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
use rustc_const_eval::ConstContext;
|
use rustc_const_eval::ConstContext;
|
||||||
use rustc_const_math::ConstInt;
|
use rustc_const_math::ConstInt;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::Bound;
|
||||||
use syntax::ast::LitKind;
|
use syntax::ast::LitKind;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use utils::paths;
|
use utils::paths;
|
||||||
@ -361,10 +362,14 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> {
|
|||||||
}
|
}
|
||||||
.filter_map(|pat| {
|
.filter_map(|pat| {
|
||||||
if_let_chain! {[
|
if_let_chain! {[
|
||||||
let PatKind::Range(ref lhs, ref rhs, _) = pat.node,
|
let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node,
|
||||||
let Ok(lhs) = constcx.eval(lhs, ExprTypeChecked),
|
let Ok(lhs) = constcx.eval(lhs, ExprTypeChecked),
|
||||||
let Ok(rhs) = constcx.eval(rhs, ExprTypeChecked)
|
let Ok(rhs) = constcx.eval(rhs, ExprTypeChecked)
|
||||||
], {
|
], {
|
||||||
|
let rhs = match *range_end {
|
||||||
|
RangeEnd::Included => Bound::Included(rhs),
|
||||||
|
RangeEnd::Excluded => Bound::Excluded(rhs),
|
||||||
|
};
|
||||||
return Some(SpannedRange { span: pat.span, node: (lhs, rhs) });
|
return Some(SpannedRange { span: pat.span, node: (lhs, rhs) });
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -372,7 +377,7 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> {
|
|||||||
let PatKind::Lit(ref value) = pat.node,
|
let PatKind::Lit(ref value) = pat.node,
|
||||||
let Ok(value) = constcx.eval(value, ExprTypeChecked)
|
let Ok(value) = constcx.eval(value, ExprTypeChecked)
|
||||||
], {
|
], {
|
||||||
return Some(SpannedRange { span: pat.span, node: (value.clone(), value) });
|
return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) });
|
||||||
}}
|
}}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -384,7 +389,7 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> {
|
|||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct SpannedRange<T> {
|
pub struct SpannedRange<T> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub node: (T, T),
|
pub node: (T, Bound<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
type TypedRanges = Vec<SpannedRange<ConstInt>>;
|
type TypedRanges = Vec<SpannedRange<ConstInt>>;
|
||||||
@ -393,13 +398,26 @@ pub struct SpannedRange<T> {
|
|||||||
/// `Uint` and `Int` probably don't make sense.
|
/// `Uint` and `Int` probably don't make sense.
|
||||||
fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges {
|
fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges {
|
||||||
ranges.iter()
|
ranges.iter()
|
||||||
.filter_map(|range| if let (ConstVal::Integral(start), ConstVal::Integral(end)) = range.node {
|
.filter_map(|range| match range.node {
|
||||||
Some(SpannedRange {
|
(ConstVal::Integral(start), Bound::Included(ConstVal::Integral(end))) => {
|
||||||
span: range.span,
|
Some(SpannedRange {
|
||||||
node: (start, end),
|
span: range.span,
|
||||||
})
|
node: (start, Bound::Included(end)),
|
||||||
} else {
|
})
|
||||||
None
|
},
|
||||||
|
(ConstVal::Integral(start), Bound::Excluded(ConstVal::Integral(end))) => {
|
||||||
|
Some(SpannedRange {
|
||||||
|
span: range.span,
|
||||||
|
node: (start, Bound::Excluded(end)),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
(ConstVal::Integral(start), Bound::Unbounded) => {
|
||||||
|
Some(SpannedRange {
|
||||||
|
span: range.span,
|
||||||
|
node: (start, Bound::Unbounded),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -443,7 +461,7 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &
|
|||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
enum Kind<'a, T: 'a> {
|
enum Kind<'a, T: 'a> {
|
||||||
Start(T, &'a SpannedRange<T>),
|
Start(T, &'a SpannedRange<T>),
|
||||||
End(T, &'a SpannedRange<T>),
|
End(Bound<T>, &'a SpannedRange<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Copy> Kind<'a, T> {
|
impl<'a, T: Copy> Kind<'a, T> {
|
||||||
@ -454,9 +472,9 @@ fn range(&self) -> &'a SpannedRange<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value(self) -> T {
|
fn value(self) -> Bound<T> {
|
||||||
match self {
|
match self {
|
||||||
Kind::Start(t, _) |
|
Kind::Start(t, _) => Bound::Included(t),
|
||||||
Kind::End(t, _) => t,
|
Kind::End(t, _) => t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,7 +488,25 @@ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|||||||
|
|
||||||
impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
|
impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.value().cmp(&other.value())
|
match (self.value(), other.value()) {
|
||||||
|
(Bound::Included(a), Bound::Included(b)) |
|
||||||
|
(Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b),
|
||||||
|
// Range patterns cannot be unbounded (yet)
|
||||||
|
(Bound::Unbounded, _) |
|
||||||
|
(_, Bound::Unbounded) => unimplemented!(),
|
||||||
|
(Bound::Included(a), Bound::Excluded(b)) => {
|
||||||
|
match a.cmp(&b) {
|
||||||
|
Ordering::Equal => Ordering::Greater,
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Bound::Excluded(a), Bound::Included(b)) => {
|
||||||
|
match a.cmp(&b) {
|
||||||
|
Ordering::Equal => Ordering::Less,
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +526,7 @@ fn cmp(&self, other: &Self) -> Ordering {
|
|||||||
return Some((ra, rb));
|
return Some((ra, rb));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (),
|
(&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
|
||||||
_ => return Some((a.range(), b.range())),
|
_ => return Some((a.range(), b.range())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![feature(plugin)]
|
#![feature(plugin)]
|
||||||
|
#![feature(exclusive_range_pattern)]
|
||||||
|
|
||||||
#![plugin(clippy)]
|
#![plugin(clippy)]
|
||||||
#![deny(clippy)]
|
#![deny(clippy)]
|
||||||
@ -228,14 +229,14 @@ fn overlapping() {
|
|||||||
|
|
||||||
match 42 {
|
match 42 {
|
||||||
0 ... 10 => println!("0 ... 10"), //~ERROR: some ranges overlap
|
0 ... 10 => println!("0 ... 10"), //~ERROR: some ranges overlap
|
||||||
0 ... 11 => println!("0 ... 10"), //~NOTE overlaps with this
|
0 ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
match 42 {
|
match 42 {
|
||||||
0 ... 5 => println!("0 ... 5"), //~ERROR: some ranges overlap
|
0 ... 5 => println!("0 ... 5"), //~ERROR: some ranges overlap
|
||||||
6 ... 7 => println!("6 ... 7"),
|
6 ... 7 => println!("6 ... 7"),
|
||||||
FOO ... 11 => println!("0 ... 10"), //~NOTE overlaps with this
|
FOO ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,9 +246,33 @@ fn overlapping() {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match 42 {
|
||||||
|
2 => println!("2"), //~NOTE overlaps with this
|
||||||
|
0 ... 2 => println!("0 ... 2"), //~ERROR: some ranges overlap
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
match 42 {
|
match 42 {
|
||||||
0 ... 10 => println!("0 ... 10"),
|
0 ... 10 => println!("0 ... 10"),
|
||||||
11 ... 50 => println!("0 ... 10"),
|
11 ... 50 => println!("11 ... 50"),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match 42 {
|
||||||
|
2 => println!("2"),
|
||||||
|
0 .. 2 => println!("0 .. 2"),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match 42 {
|
||||||
|
0 .. 10 => println!("0 .. 10"),
|
||||||
|
10 .. 50 => println!("10 .. 50"),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match 42 {
|
||||||
|
0 .. 11 => println!("0 .. 11"), //~ERROR: some ranges overlap
|
||||||
|
0 ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
|
#![feature(collections_bound)]
|
||||||
|
|
||||||
extern crate clippy_lints;
|
extern crate clippy_lints;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
use std::collections::Bound;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_overlapping() {
|
fn test_overlapping() {
|
||||||
@ -16,9 +18,12 @@ fn test_overlapping() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(None, overlapping::<u8>(&[]));
|
assert_eq!(None, overlapping::<u8>(&[]));
|
||||||
assert_eq!(None, overlapping(&[sp(1, 4)]));
|
assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
|
||||||
assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6)]));
|
assert_eq!(None, overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))]));
|
||||||
assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6), sp(10, 11)]));
|
assert_eq!(None,
|
||||||
assert_eq!(Some((&sp(1, 4), &sp(3, 6))), overlapping(&[sp(1, 4), sp(3, 6)]));
|
overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6)), sp(10, Bound::Included(11))]));
|
||||||
assert_eq!(Some((&sp(5, 6), &sp(6, 11))), overlapping(&[sp(1, 4), sp(5, 6), sp(6, 11)]));
|
assert_eq!(Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
|
||||||
|
overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))]));
|
||||||
|
assert_eq!(Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
|
||||||
|
overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6)), sp(6, Bound::Included(11))]));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user