Skip to content

Commit a248648

Browse files
committed
Auto merge of #7267 - camsteffen:sphash-improvements, r=Manishearth
Some SpanlessHash improvements changelog: none * Use `mem::discriminant().hash()` instead of `stable_hash` for simple enums and then use `FxHasher` instead of `StableHasher`. We don't use any StableHash features. * Use `UnHashMap` for maps keyed by spanless hash values.
2 parents c25f4b4 + 7f34057 commit a248648

File tree

3 files changed

+44
-79
lines changed

3 files changed

+44
-79
lines changed

clippy_lints/src/trait_bounds.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
33
use clippy_utils::{in_macro, SpanlessHash};
44
use if_chain::if_chain;
55
use rustc_data_structures::fx::FxHashMap;
6+
use rustc_data_structures::unhash::UnhashMap;
67
use rustc_errors::Applicability;
78
use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
89
use rustc_lint::{LateContext, LateLintPass};
@@ -100,7 +101,7 @@ impl TraitBounds {
100101
hasher.hash_ty(ty);
101102
hasher.finish()
102103
};
103-
let mut map = FxHashMap::default();
104+
let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
104105
let mut applicability = Applicability::MaybeIncorrect;
105106
for bound in gen.where_clause.predicates {
106107
if_chain! {

clippy_utils/src/hir_utils.rs

+35-73
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@ use crate::consts::{constant_context, constant_simple};
22
use crate::differing_macro_contexts;
33
use crate::source::snippet_opt;
44
use rustc_ast::ast::InlineAsmTemplatePiece;
5-
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5+
use rustc_data_structures::fx::FxHasher;
66
use rustc_hir::def::Res;
77
use rustc_hir::HirIdMap;
88
use rustc_hir::{
9-
BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
10-
GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
11-
PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
9+
BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
10+
InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
11+
StmtKind, Ty, TyKind, TypeBinding,
1212
};
1313
use rustc_lexer::{tokenize, TokenKind};
1414
use rustc_lint::LateContext;
15-
use rustc_middle::ich::StableHashingContextProvider;
1615
use rustc_middle::ty::TypeckResults;
1716
use rustc_span::Symbol;
18-
use std::hash::Hash;
17+
use std::hash::{Hash, Hasher};
1918

2019
/// Type used to check whether two ast are the same. This is different from the
2120
/// operator
@@ -169,6 +168,12 @@ impl HirEqInterExpr<'_, '_, '_> {
169168
}
170169
}
171170

171+
pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
172+
let cx = self.inner.cx;
173+
let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
174+
eval_const(left) == eval_const(right)
175+
}
176+
172177
#[allow(clippy::similar_names)]
173178
pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
174179
if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
@@ -244,12 +249,7 @@ impl HirEqInterExpr<'_, '_, '_> {
244249
self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
245250
},
246251
(&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
247-
let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
248-
let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
249-
let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
250-
let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
251-
252-
self.eq_expr(le, re) && ll == rl
252+
self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
253253
},
254254
(&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
255255
(&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
@@ -285,6 +285,7 @@ impl HirEqInterExpr<'_, '_, '_> {
285285

286286
fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
287287
match (left, right) {
288+
(GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
288289
(GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
289290
(GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
290291
_ => false,
@@ -385,10 +386,7 @@ impl HirEqInterExpr<'_, '_, '_> {
385386
match (&left.kind, &right.kind) {
386387
(&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
387388
(&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
388-
let cx = self.inner.cx;
389-
let eval_const =
390-
|body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
391-
self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
389+
self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
392390
},
393391
(&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
394392
l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
@@ -512,15 +510,15 @@ pub struct SpanlessHash<'a, 'tcx> {
512510
/// Context used to evaluate constant expressions.
513511
cx: &'a LateContext<'tcx>,
514512
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
515-
s: StableHasher,
513+
s: FxHasher,
516514
}
517515

518516
impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
519517
pub fn new(cx: &'a LateContext<'tcx>) -> Self {
520518
Self {
521519
cx,
522520
maybe_typeck_results: cx.maybe_typeck_results(),
523-
s: StableHasher::new(),
521+
s: FxHasher::default(),
524522
}
525523
}
526524

@@ -537,13 +535,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
537535
self.hash_expr(e);
538536
}
539537

540-
match b.rules {
541-
BlockCheckMode::DefaultBlock => 0,
542-
BlockCheckMode::UnsafeBlock(_) => 1,
543-
BlockCheckMode::PushUnsafeBlock(_) => 2,
544-
BlockCheckMode::PopUnsafeBlock(_) => 3,
545-
}
546-
.hash(&mut self.s);
538+
std::mem::discriminant(&b.rules).hash(&mut self.s);
547539
}
548540

549541
#[allow(clippy::many_single_char_names, clippy::too_many_lines)]
@@ -554,21 +546,16 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
554546

555547
// const hashing may result in the same hash as some unrelated node, so add a sort of
556548
// discriminant depending on which path we're choosing next
557-
simple_const.is_some().hash(&mut self.s);
558-
559-
if let Some(e) = simple_const {
560-
return e.hash(&mut self.s);
549+
simple_const.hash(&mut self.s);
550+
if simple_const.is_some() {
551+
return;
561552
}
562553

563554
std::mem::discriminant(&e.kind).hash(&mut self.s);
564555

565556
match e.kind {
566557
ExprKind::AddrOf(kind, m, e) => {
567-
match kind {
568-
BorrowKind::Ref => 0,
569-
BorrowKind::Raw => 1,
570-
}
571-
.hash(&mut self.s);
558+
std::mem::discriminant(&kind).hash(&mut self.s);
572559
m.hash(&mut self.s);
573560
self.hash_expr(e);
574561
},
@@ -582,17 +569,15 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
582569
self.hash_expr(r);
583570
},
584571
ExprKind::AssignOp(ref o, l, r) => {
585-
o.node
586-
.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
572+
std::mem::discriminant(&o.node).hash(&mut self.s);
587573
self.hash_expr(l);
588574
self.hash_expr(r);
589575
},
590576
ExprKind::Block(b, _) => {
591577
self.hash_block(b);
592578
},
593579
ExprKind::Binary(op, l, r) => {
594-
op.node
595-
.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
580+
std::mem::discriminant(&op.node).hash(&mut self.s);
596581
self.hash_expr(l);
597582
self.hash_expr(r);
598583
},
@@ -616,11 +601,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
616601
self.hash_ty(ty);
617602
},
618603
ExprKind::Closure(cap, _, eid, _, _) => {
619-
match cap {
620-
CaptureBy::Value => 0,
621-
CaptureBy::Ref => 1,
622-
}
623-
.hash(&mut self.s);
604+
std::mem::discriminant(&cap).hash(&mut self.s);
624605
// closures inherit TypeckResults
625606
self.hash_expr(&self.cx.tcx.hir().body(eid).value);
626607
},
@@ -694,8 +675,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
694675
}
695676
},
696677
ExprKind::If(cond, then, ref else_opt) => {
697-
let c: fn(_, _, _) -> _ = ExprKind::If;
698-
c.hash(&mut self.s);
699678
self.hash_expr(cond);
700679
self.hash_expr(then);
701680
if let Some(e) = *else_opt {
@@ -753,7 +732,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
753732
self.hash_exprs(v);
754733
},
755734
ExprKind::Unary(lop, le) => {
756-
lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
735+
std::mem::discriminant(&lop).hash(&mut self.s);
757736
self.hash_expr(le);
758737
},
759738
}
@@ -766,7 +745,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
766745
}
767746

768747
pub fn hash_name(&mut self, n: Symbol) {
769-
n.as_str().hash(&mut self.s);
748+
n.hash(&mut self.s);
770749
}
771750

772751
pub fn hash_qpath(&mut self, p: &QPath<'_>) {
@@ -778,7 +757,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
778757
self.hash_name(path.ident.name);
779758
},
780759
QPath::LangItem(lang_item, ..) => {
781-
lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
760+
std::mem::discriminant(&lang_item).hash(&mut self.s);
782761
},
783762
}
784763
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
@@ -788,7 +767,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
788767
std::mem::discriminant(&pat.kind).hash(&mut self.s);
789768
match pat.kind {
790769
PatKind::Binding(ann, _, _, pat) => {
791-
ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
770+
std::mem::discriminant(&ann).hash(&mut self.s);
792771
if let Some(pat) = pat {
793772
self.hash_pat(pat);
794773
}
@@ -808,11 +787,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
808787
if let Some(e) = e {
809788
self.hash_expr(e);
810789
}
811-
i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
790+
std::mem::discriminant(&i).hash(&mut self.s);
812791
},
813-
PatKind::Ref(pat, m) => {
792+
PatKind::Ref(pat, mu) => {
814793
self.hash_pat(pat);
815-
m.hash(&mut self.s);
794+
std::mem::discriminant(&mu).hash(&mut self.s);
816795
},
817796
PatKind::Slice(l, m, r) => {
818797
for pat in l {
@@ -857,6 +836,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
857836
_ => {
858837
for seg in path.segments {
859838
self.hash_name(seg.ident.name);
839+
self.hash_generic_args(seg.args().args);
860840
}
861841
},
862842
}
@@ -928,10 +908,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
928908
for arg in bfn.decl.inputs {
929909
self.hash_ty(arg);
930910
}
911+
std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
931912
match bfn.decl.output {
932-
FnRetTy::DefaultReturn(_) => {
933-
().hash(&mut self.s);
934-
},
913+
FnRetTy::DefaultReturn(_) => {},
935914
FnRetTy::Return(ty) => {
936915
self.hash_ty(ty);
937916
},
@@ -943,24 +922,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
943922
self.hash_ty(ty);
944923
}
945924
},
946-
TyKind::Path(ref qpath) => match qpath {
947-
QPath::Resolved(ref maybe_ty, path) => {
948-
if let Some(ty) = maybe_ty {
949-
self.hash_ty(ty);
950-
}
951-
for segment in path.segments {
952-
segment.ident.name.hash(&mut self.s);
953-
self.hash_generic_args(segment.args().args);
954-
}
955-
},
956-
QPath::TypeRelative(ty, segment) => {
957-
self.hash_ty(ty);
958-
segment.ident.name.hash(&mut self.s);
959-
},
960-
QPath::LangItem(lang_item, ..) => {
961-
lang_item.hash(&mut self.s);
962-
},
963-
},
925+
TyKind::Path(ref qpath) => self.hash_qpath(qpath),
964926
TyKind::OpaqueDef(_, arg_list) => {
965927
self.hash_generic_args(arg_list);
966928
},

clippy_utils/src/lib.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use std::hash::BuildHasherDefault;
6363

6464
use if_chain::if_chain;
6565
use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind};
66-
use rustc_data_structures::fx::FxHashMap;
66+
use rustc_data_structures::unhash::UnhashMap;
6767
use rustc_hir as hir;
6868
use rustc_hir::def::{DefKind, Res};
6969
use rustc_hir::def_id::DefId;
@@ -1572,14 +1572,16 @@ where
15721572
Hash: Fn(&T) -> u64,
15731573
Eq: Fn(&T, &T) -> bool,
15741574
{
1575-
if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
1576-
return vec![(&exprs[0], &exprs[1])];
1575+
match exprs {
1576+
[a, b] if eq(a, b) => return vec![(a, b)],
1577+
_ if exprs.len() <= 2 => return vec![],
1578+
_ => {},
15771579
}
15781580

15791581
let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
15801582

1581-
let mut map: FxHashMap<_, Vec<&_>> =
1582-
FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
1583+
let mut map: UnhashMap<u64, Vec<&_>> =
1584+
UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
15831585

15841586
for expr in exprs {
15851587
match map.entry(hash(expr)) {

0 commit comments

Comments
 (0)