Skip to content

Commit 07228a1

Browse files
committed
Fix Hash implementation for Constant
1 parent 68ecd06 commit 07228a1

File tree

2 files changed

+68
-35
lines changed

2 files changed

+68
-35
lines changed

src/consts.rs

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,21 @@
22

33
use rustc::lint::LateContext;
44
use rustc::middle::const_eval::lookup_const_by_id;
5-
use rustc::middle::def::PathResolution;
6-
use rustc::middle::def::Def;
5+
use rustc::middle::def::{Def, PathResolution};
76
use rustc_front::hir::*;
8-
use syntax::ptr::P;
9-
use std::cmp::PartialOrd;
107
use std::cmp::Ordering::{self, Greater, Less, Equal};
11-
use std::rc::Rc;
8+
use std::cmp::PartialOrd;
9+
use std::hash::{Hash, Hasher};
10+
use std::mem;
1211
use std::ops::Deref;
13-
14-
use syntax::ast::Lit_;
15-
use syntax::ast::LitIntType;
16-
use syntax::ast::{UintTy, FloatTy, StrStyle};
12+
use std::rc::Rc;
13+
use syntax::ast::{LitIntType, Lit_};
1714
use syntax::ast::Sign::{self, Plus, Minus};
15+
use syntax::ast::{UintTy, FloatTy, StrStyle};
16+
use syntax::ptr::P;
1817

1918

20-
#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
19+
#[derive(Debug, Copy, Clone)]
2120
pub enum FloatWidth {
2221
Fw32,
2322
Fw64,
@@ -34,7 +33,7 @@ impl From<FloatTy> for FloatWidth {
3433
}
3534

3635
/// a Lit_-like enum to fold constant `Expr`s into
37-
#[derive(Eq, Debug, Clone, Hash)]
36+
#[derive(Debug, Clone)]
3837
pub enum Constant {
3938
/// a String "abc"
4039
Str(String, StrStyle),
@@ -100,18 +99,12 @@ impl PartialEq for Constant {
10099
(&Constant::Int(lv, lty), &Constant::Int(rv, rty)) => {
101100
lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0))
102101
}
103-
(&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => {
104-
use self::FloatWidth::*;
105-
if match (lw, rw) {
106-
(FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true,
102+
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
103+
// we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
104+
// `Fw32 == Fw64` so don’t compare them
105+
match (ls.parse::<f64>(), rs.parse::<f64>()) {
106+
(Ok(l), Ok(r)) => l.eq(&r),
107107
_ => false,
108-
} {
109-
match (ls.parse::<f64>(), rs.parse::<f64>()) {
110-
(Ok(l), Ok(r)) => l.eq(&r),
111-
_ => false,
112-
}
113-
} else {
114-
false
115108
}
116109
}
117110
(&Constant::Bool(l), &Constant::Bool(r)) => l == r,
@@ -123,6 +116,46 @@ impl PartialEq for Constant {
123116
}
124117
}
125118

119+
impl Hash for Constant {
120+
fn hash<H>(&self, state: &mut H) where H: Hasher {
121+
match *self {
122+
Constant::Str(ref s, ref k) => {
123+
s.hash(state);
124+
k.hash(state);
125+
}
126+
Constant::Binary(ref b) => {
127+
b.hash(state);
128+
}
129+
Constant::Byte(u) => {
130+
u.hash(state);
131+
}
132+
Constant::Char(c) => {
133+
c.hash(state);
134+
}
135+
Constant::Int(u, t) => {
136+
u.hash(state);
137+
t.hash(state);
138+
}
139+
Constant::Float(ref f, _) => {
140+
// don’t use the width here because of PartialEq implementation
141+
if let Ok(f) = f.parse::<f64>() {
142+
unsafe { mem::transmute::<f64, u64>(f) }.hash(state);
143+
}
144+
}
145+
Constant::Bool(b) => {
146+
b.hash(state);
147+
}
148+
Constant::Vec(ref v) | Constant::Tuple(ref v)=> {
149+
v.hash(state);
150+
}
151+
Constant::Repeat(ref c, l) => {
152+
c.hash(state);
153+
l.hash(state);
154+
}
155+
}
156+
}
157+
}
158+
126159
impl PartialOrd for Constant {
127160
fn partial_cmp(&self, other: &Constant) -> Option<Ordering> {
128161
match (self, other) {
@@ -143,18 +176,10 @@ impl PartialOrd for Constant {
143176
(false, true) => Greater,
144177
})
145178
}
146-
(&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => {
147-
use self::FloatWidth::*;
148-
if match (lw, rw) {
149-
(FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true,
150-
_ => false,
151-
} {
152-
match (ls.parse::<f64>(), rs.parse::<f64>()) {
153-
(Ok(ref l), Ok(ref r)) => l.partial_cmp(r),
154-
_ => None,
155-
}
156-
} else {
157-
None
179+
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
180+
match (ls.parse::<f64>(), rs.parse::<f64>()) {
181+
(Ok(ref l), Ok(ref r)) => l.partial_cmp(r),
182+
_ => None,
158183
}
159184
}
160185
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),

tests/consts.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use syntax::ast::LitIntType::*;
1717
use syntax::ast::StrStyle::*;
1818
use syntax::ast::Sign::*;
1919

20-
use clippy::consts::{constant_simple, Constant};
20+
use clippy::consts::{constant_simple, Constant, FloatWidth};
2121

2222
fn spanned<T>(t: T) -> Spanned<T> {
2323
Spanned{ node: t, span: COMMAND_LINE_SP }
@@ -78,4 +78,12 @@ fn test_ops() {
7878
check(ONE, &binop(BiSub, litone.clone(), litzero.clone()));
7979
check(ONE, &binop(BiMul, litone.clone(), litone.clone()));
8080
check(ONE, &binop(BiDiv, litone.clone(), litone.clone()));
81+
82+
let half_any = Constant::Float("0.5".into(), FloatWidth::FwAny);
83+
let half32 = Constant::Float("0.5".into(), FloatWidth::Fw32);
84+
let half64 = Constant::Float("0.5".into(), FloatWidth::Fw64);
85+
86+
assert_eq!(half_any, half32);
87+
assert_eq!(half_any, half64);
88+
assert_eq!(half32, half64); // for transitivity
8189
}

0 commit comments

Comments
 (0)