Fix Hash implementation for Constant

This commit is contained in:
mcarton 2016-02-12 15:51:55 +01:00
parent 68ecd06f4c
commit 07228a1041
2 changed files with 68 additions and 35 deletions

View file

@ -2,22 +2,21 @@
use rustc::lint::LateContext;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::PathResolution;
use rustc::middle::def::Def;
use rustc::middle::def::{Def, PathResolution};
use rustc_front::hir::*;
use syntax::ptr::P;
use std::cmp::PartialOrd;
use std::cmp::Ordering::{self, Greater, Less, Equal};
use std::rc::Rc;
use std::cmp::PartialOrd;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use syntax::ast::Lit_;
use syntax::ast::LitIntType;
use syntax::ast::{UintTy, FloatTy, StrStyle};
use std::rc::Rc;
use syntax::ast::{LitIntType, Lit_};
use syntax::ast::Sign::{self, Plus, Minus};
use syntax::ast::{UintTy, FloatTy, StrStyle};
use syntax::ptr::P;
#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
#[derive(Debug, Copy, Clone)]
pub enum FloatWidth {
Fw32,
Fw64,
@ -34,7 +33,7 @@ impl From<FloatTy> for FloatWidth {
}
/// a Lit_-like enum to fold constant `Expr`s into
#[derive(Eq, Debug, Clone, Hash)]
#[derive(Debug, Clone)]
pub enum Constant {
/// a String "abc"
Str(String, StrStyle),
@ -100,19 +99,13 @@ impl PartialEq for Constant {
(&Constant::Int(lv, lty), &Constant::Int(rv, rty)) => {
lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0))
}
(&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => {
use self::FloatWidth::*;
if match (lw, rw) {
(FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true,
_ => false,
} {
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
// we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
// `Fw32 == Fw64` so dont compare them
match (ls.parse::<f64>(), rs.parse::<f64>()) {
(Ok(l), Ok(r)) => l.eq(&r),
_ => false,
}
} else {
false
}
}
(&Constant::Bool(l), &Constant::Bool(r)) => l == r,
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l == r,
@ -123,6 +116,46 @@ impl PartialEq for Constant {
}
}
impl Hash for Constant {
fn hash<H>(&self, state: &mut H) where H: Hasher {
match *self {
Constant::Str(ref s, ref k) => {
s.hash(state);
k.hash(state);
}
Constant::Binary(ref b) => {
b.hash(state);
}
Constant::Byte(u) => {
u.hash(state);
}
Constant::Char(c) => {
c.hash(state);
}
Constant::Int(u, t) => {
u.hash(state);
t.hash(state);
}
Constant::Float(ref f, _) => {
// dont use the width here because of PartialEq implementation
if let Ok(f) = f.parse::<f64>() {
unsafe { mem::transmute::<f64, u64>(f) }.hash(state);
}
}
Constant::Bool(b) => {
b.hash(state);
}
Constant::Vec(ref v) | Constant::Tuple(ref v)=> {
v.hash(state);
}
Constant::Repeat(ref c, l) => {
c.hash(state);
l.hash(state);
}
}
}
}
impl PartialOrd for Constant {
fn partial_cmp(&self, other: &Constant) -> Option<Ordering> {
match (self, other) {
@ -143,19 +176,11 @@ impl PartialOrd for Constant {
(false, true) => Greater,
})
}
(&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => {
use self::FloatWidth::*;
if match (lw, rw) {
(FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true,
_ => false,
} {
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
match (ls.parse::<f64>(), rs.parse::<f64>()) {
(Ok(ref l), Ok(ref r)) => l.partial_cmp(r),
_ => None,
}
} else {
None
}
}
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(&r),

View file

@ -17,7 +17,7 @@ use syntax::ast::LitIntType::*;
use syntax::ast::StrStyle::*;
use syntax::ast::Sign::*;
use clippy::consts::{constant_simple, Constant};
use clippy::consts::{constant_simple, Constant, FloatWidth};
fn spanned<T>(t: T) -> Spanned<T> {
Spanned{ node: t, span: COMMAND_LINE_SP }
@ -78,4 +78,12 @@ fn test_ops() {
check(ONE, &binop(BiSub, litone.clone(), litzero.clone()));
check(ONE, &binop(BiMul, litone.clone(), litone.clone()));
check(ONE, &binop(BiDiv, litone.clone(), litone.clone()));
let half_any = Constant::Float("0.5".into(), FloatWidth::FwAny);
let half32 = Constant::Float("0.5".into(), FloatWidth::Fw32);
let half64 = Constant::Float("0.5".into(), FloatWidth::Fw64);
assert_eq!(half_any, half32);
assert_eq!(half_any, half64);
assert_eq!(half32, half64); // for transitivity
}