mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 23:20:39 +00:00
Fix Hash
implementation for Constant
This commit is contained in:
parent
68ecd06f4c
commit
07228a1041
2 changed files with 68 additions and 35 deletions
|
@ -2,22 +2,21 @@
|
||||||
|
|
||||||
use rustc::lint::LateContext;
|
use rustc::lint::LateContext;
|
||||||
use rustc::middle::const_eval::lookup_const_by_id;
|
use rustc::middle::const_eval::lookup_const_by_id;
|
||||||
use rustc::middle::def::PathResolution;
|
use rustc::middle::def::{Def, PathResolution};
|
||||||
use rustc::middle::def::Def;
|
|
||||||
use rustc_front::hir::*;
|
use rustc_front::hir::*;
|
||||||
use syntax::ptr::P;
|
|
||||||
use std::cmp::PartialOrd;
|
|
||||||
use std::cmp::Ordering::{self, Greater, Less, Equal};
|
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 std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
use syntax::ast::Lit_;
|
use syntax::ast::{LitIntType, Lit_};
|
||||||
use syntax::ast::LitIntType;
|
|
||||||
use syntax::ast::{UintTy, FloatTy, StrStyle};
|
|
||||||
use syntax::ast::Sign::{self, Plus, Minus};
|
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 {
|
pub enum FloatWidth {
|
||||||
Fw32,
|
Fw32,
|
||||||
Fw64,
|
Fw64,
|
||||||
|
@ -34,7 +33,7 @@ impl From<FloatTy> for FloatWidth {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// a Lit_-like enum to fold constant `Expr`s into
|
/// a Lit_-like enum to fold constant `Expr`s into
|
||||||
#[derive(Eq, Debug, Clone, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Constant {
|
pub enum Constant {
|
||||||
/// a String "abc"
|
/// a String "abc"
|
||||||
Str(String, StrStyle),
|
Str(String, StrStyle),
|
||||||
|
@ -100,19 +99,13 @@ impl PartialEq for Constant {
|
||||||
(&Constant::Int(lv, lty), &Constant::Int(rv, rty)) => {
|
(&Constant::Int(lv, lty), &Constant::Int(rv, rty)) => {
|
||||||
lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0))
|
lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0))
|
||||||
}
|
}
|
||||||
(&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => {
|
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
|
||||||
use self::FloatWidth::*;
|
// we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
|
||||||
if match (lw, rw) {
|
// `Fw32 == Fw64` so don’t compare them
|
||||||
(FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true,
|
|
||||||
_ => false,
|
|
||||||
} {
|
|
||||||
match (ls.parse::<f64>(), rs.parse::<f64>()) {
|
match (ls.parse::<f64>(), rs.parse::<f64>()) {
|
||||||
(Ok(l), Ok(r)) => l.eq(&r),
|
(Ok(l), Ok(r)) => l.eq(&r),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(&Constant::Bool(l), &Constant::Bool(r)) => l == r,
|
(&Constant::Bool(l), &Constant::Bool(r)) => l == r,
|
||||||
(&Constant::Vec(ref l), &Constant::Vec(ref 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, _) => {
|
||||||
|
// don’t 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 {
|
impl PartialOrd for Constant {
|
||||||
fn partial_cmp(&self, other: &Constant) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Constant) -> Option<Ordering> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
|
@ -143,19 +176,11 @@ impl PartialOrd for Constant {
|
||||||
(false, true) => Greater,
|
(false, true) => Greater,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => {
|
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
|
||||||
use self::FloatWidth::*;
|
|
||||||
if match (lw, rw) {
|
|
||||||
(FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true,
|
|
||||||
_ => false,
|
|
||||||
} {
|
|
||||||
match (ls.parse::<f64>(), rs.parse::<f64>()) {
|
match (ls.parse::<f64>(), rs.parse::<f64>()) {
|
||||||
(Ok(ref l), Ok(ref r)) => l.partial_cmp(r),
|
(Ok(ref l), Ok(ref r)) => l.partial_cmp(r),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),
|
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),
|
||||||
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(&r),
|
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(&r),
|
||||||
|
|
|
@ -17,7 +17,7 @@ use syntax::ast::LitIntType::*;
|
||||||
use syntax::ast::StrStyle::*;
|
use syntax::ast::StrStyle::*;
|
||||||
use syntax::ast::Sign::*;
|
use syntax::ast::Sign::*;
|
||||||
|
|
||||||
use clippy::consts::{constant_simple, Constant};
|
use clippy::consts::{constant_simple, Constant, FloatWidth};
|
||||||
|
|
||||||
fn spanned<T>(t: T) -> Spanned<T> {
|
fn spanned<T>(t: T) -> Spanned<T> {
|
||||||
Spanned{ node: t, span: COMMAND_LINE_SP }
|
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(BiSub, litone.clone(), litzero.clone()));
|
||||||
check(ONE, &binop(BiMul, litone.clone(), litone.clone()));
|
check(ONE, &binop(BiMul, litone.clone(), litone.clone()));
|
||||||
check(ONE, &binop(BiDiv, 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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue