3 use rustc_front::hir::*;
4 use std::hash::{Hash, Hasher, SipHasher};
7 use utils::differing_macro_contexts;
9 /// Type used to check whether two ast are the same. This is different from the operator
10 /// `==` on ast types as this operator would compare true equality with ID and span.
12 /// Note that some expressions kinds are not considered but could be added.
13 pub struct SpanlessEq<'a, 'tcx: 'a> {
14 /// Context used to evaluate constant expressions.
15 cx: &'a LateContext<'a, 'tcx>,
16 /// If is true, never consider as equal expressions containing fonction calls.
20 impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
21 pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
28 pub fn ignore_fn(self) -> Self {
35 /// Check whether two statements are the same.
36 pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool {
37 match (&left.node, &right.node) {
38 (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => {
39 if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) {
41 l.ty.is_none() && r.ty.is_none() && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
46 (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) |
47 (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r),
52 /// Check whether two blocks are the same.
53 pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
54 over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) &&
55 both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
58 pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool {
59 if self.ignore_fn && differing_macro_contexts(left.span, right.span) {
63 if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) {
69 match (&left.node, &right.node) {
70 (&ExprAddrOf(l_mut, ref le), &ExprAddrOf(r_mut, ref re)) => l_mut == r_mut && self.eq_expr(le, re),
71 (&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()),
72 (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr),
73 (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => {
74 lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
76 (&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r),
77 (&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => {
78 l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
80 (&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()),
81 (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
82 (&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => {
83 !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
85 (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt),
86 (&ExprField(ref l_f_exp, ref l_f_ident), &ExprField(ref r_f_exp, ref r_f_ident)) => {
87 l_f_ident.node == r_f_ident.node && self.eq_expr(l_f_exp, r_f_exp)
89 (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
90 (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => {
91 self.eq_expr(lc, rc) && self.eq_block(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
93 (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
94 (&ExprLoop(ref lb, ref ll), &ExprLoop(ref rb, ref rl)) => {
95 self.eq_block(lb, rb) && both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
97 (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
98 ls == rs && self.eq_expr(le, re) &&
100 self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
101 over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
104 (&ExprMethodCall(ref l_name, ref l_tys, ref l_args),
105 &ExprMethodCall(ref r_name, ref r_tys, ref r_args)) => {
107 !self.ignore_fn && l_name.node == r_name.node && l_tys.is_empty() && r_tys.is_empty() &&
108 self.eq_exprs(l_args, r_args)
110 (&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => self.eq_expr(le, re) && self.eq_expr(ll, rl),
111 (&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
112 (&ExprPath(ref l_qself, ref l_subpath), &ExprPath(ref r_qself, ref r_subpath)) => {
113 both(l_qself, r_qself, |l, r| self.eq_qself(l, r)) && self.eq_path(l_subpath, r_subpath)
115 (&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
116 self.eq_path(l_path, r_path) &&
117 both(lo, ro, |l, r| self.eq_expr(l, r)) &&
118 over(lf, rf, |l, r| self.eq_field(l, r))
120 (&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
121 (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
122 (&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
123 (&ExprVec(ref l), &ExprVec(ref r)) => self.eq_exprs(l, r),
124 (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => {
125 self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
131 fn eq_exprs(&self, left: &[P<Expr>], right: &[P<Expr>]) -> bool {
132 over(left, right, |l, r| self.eq_expr(l, r))
135 fn eq_field(&self, left: &Field, right: &Field) -> bool {
136 left.name.node == right.name.node && self.eq_expr(&left.expr, &right.expr)
139 /// Check whether two patterns are the same.
140 pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool {
141 match (&left.node, &right.node) {
142 (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
143 (&PatKind::TupleStruct(ref lp, ref la), &PatKind::TupleStruct(ref rp, ref ra)) => {
144 self.eq_path(lp, rp) && both(la, ra, |l, r| over(l, r, |l, r| self.eq_pat(l, r)))
146 (&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(ref rb, ref ri, ref rp)) => {
147 lb == rb && li.node.name.as_str() == ri.node.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
149 (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
150 (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => {
151 self.eq_qself(ls, rs) && self.eq_path(lp, rp)
153 (&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => over(l, r, |l, r| self.eq_pat(l, r)),
154 (&PatKind::Range(ref ls, ref le), &PatKind::Range(ref rs, ref re)) => {
155 self.eq_expr(ls, rs) && self.eq_expr(le, re)
157 (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
158 (&PatKind::Vec(ref ls, ref li, ref le), &PatKind::Vec(ref rs, ref ri, ref re)) => {
159 over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) &&
160 both(li, ri, |l, r| self.eq_pat(l, r))
162 (&PatKind::Wild, &PatKind::Wild) => true,
167 fn eq_path(&self, left: &Path, right: &Path) -> bool {
168 // The == of idents doesn't work with different contexts,
169 // we have to be explicit about hygiene
170 left.global == right.global &&
173 |l, r| l.identifier.name.as_str() == r.identifier.name.as_str() && l.parameters == r.parameters)
176 fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool {
177 left.ty.node == right.ty.node && left.position == right.position
180 fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
181 match (&left.node, &right.node) {
182 (&TyVec(ref l_vec), &TyVec(ref r_vec)) => self.eq_ty(l_vec, r_vec),
183 (&TyFixedLengthVec(ref lt, ref ll), &TyFixedLengthVec(ref rt, ref rl)) => {
184 self.eq_ty(lt, rt) && self.eq_expr(ll, rl)
186 (&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
187 (&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {
188 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
190 (&TyPath(ref lq, ref l_path), &TyPath(ref rq, ref r_path)) => {
191 both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(l_path, r_path)
193 (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
194 (&TyInfer, &TyInfer) => true,
200 /// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`.
201 fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
202 where F: FnMut(&X, &X) -> bool
204 l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
207 /// Check if two slices are equal as per `eq_fn`.
208 fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
209 where F: FnMut(&X, &X) -> bool
211 left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
215 /// Type used to hash an ast element. This is different from the `Hash` trait on ast types as this
216 /// trait would consider IDs and spans.
218 /// All expressions kind are hashed, but some might have a weaker hash.
219 pub struct SpanlessHash<'a, 'tcx: 'a> {
220 /// Context used to evaluate constant expressions.
221 cx: &'a LateContext<'a, 'tcx>,
225 impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
226 pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
233 pub fn finish(&self) -> u64 {
237 pub fn hash_block(&mut self, b: &Block) {
242 if let Some(ref e) = b.expr {
246 b.rules.hash(&mut self.s);
249 pub fn hash_expr(&mut self, e: &Expr) {
250 if let Some(e) = constant(self.cx, e) {
251 return e.hash(&mut self.s);
255 ExprAddrOf(m, ref e) => {
256 let c: fn(_, _) -> _ = ExprAddrOf;
262 let c: fn(_) -> _ = ExprAgain;
265 self.hash_name(&i.node.name);
268 ExprAssign(ref l, ref r) => {
269 let c: fn(_, _) -> _ = ExprAssign;
274 ExprAssignOp(ref o, ref l, ref r) => {
275 let c: fn(_, _, _) -> _ = ExprAssignOp;
281 ExprBlock(ref b) => {
282 let c: fn(_) -> _ = ExprBlock;
286 ExprBinary(op, ref l, ref r) => {
287 let c: fn(_, _, _) -> _ = ExprBinary;
289 op.node.hash(&mut self.s);
294 let c: fn(_) -> _ = ExprBreak;
297 self.hash_name(&i.node.name);
301 let c: fn(_) -> _ = ExprBox;
305 ExprCall(ref fun, ref args) => {
306 let c: fn(_, _) -> _ = ExprCall;
309 self.hash_exprs(args);
311 ExprCast(ref e, ref _ty) => {
312 let c: fn(_, _) -> _ = ExprCast;
317 ExprClosure(cap, _, ref b) => {
318 let c: fn(_, _, _) -> _ = ExprClosure;
320 cap.hash(&mut self.s);
323 ExprField(ref e, ref f) => {
324 let c: fn(_, _) -> _ = ExprField;
327 self.hash_name(&f.node);
329 ExprIndex(ref a, ref i) => {
330 let c: fn(_, _) -> _ = ExprIndex;
335 ExprInlineAsm(..) => {
336 let c: fn(_, _, _) -> _ = ExprInlineAsm;
339 ExprIf(ref cond, ref t, ref e) => {
340 let c: fn(_, _, _) -> _ = ExprIf;
342 self.hash_expr(cond);
344 if let Some(ref e) = *e {
349 let c: fn(_) -> _ = ExprLit;
353 ExprLoop(ref b, ref i) => {
354 let c: fn(_, _) -> _ = ExprLoop;
357 if let Some(i) = *i {
358 self.hash_name(&i.name);
361 ExprMatch(ref e, ref arms, ref s) => {
362 let c: fn(_, _, _) -> _ = ExprMatch;
368 if let Some(ref e) = arm.guard {
371 self.hash_expr(&arm.body);
376 ExprMethodCall(ref name, ref _tys, ref args) => {
377 let c: fn(_, _, _) -> _ = ExprMethodCall;
379 self.hash_name(&name.node);
380 self.hash_exprs(args);
382 ExprRepeat(ref e, ref l) => {
383 let c: fn(_, _) -> _ = ExprRepeat;
389 let c: fn(_) -> _ = ExprRet;
391 if let Some(ref e) = *e {
395 ExprPath(ref _qself, ref subpath) => {
396 let c: fn(_, _) -> _ = ExprPath;
398 self.hash_path(subpath);
400 ExprStruct(ref path, ref fields, ref expr) => {
401 let c: fn(_, _, _) -> _ = ExprStruct;
404 self.hash_path(path);
407 self.hash_name(&f.name.node);
408 self.hash_expr(&f.expr);
411 if let Some(ref e) = *expr {
415 ExprTup(ref tup) => {
416 let c: fn(_) -> _ = ExprTup;
418 self.hash_exprs(tup);
420 ExprTupField(ref le, li) => {
421 let c: fn(_, _) -> _ = ExprTupField;
425 li.node.hash(&mut self.s);
428 let c: fn(_, _) -> _ = ExprType;
430 // what’s an ExprType anyway?
432 ExprUnary(lop, ref le) => {
433 let c: fn(_, _) -> _ = ExprUnary;
436 lop.hash(&mut self.s);
440 let c: fn(_) -> _ = ExprVec;
445 ExprWhile(ref cond, ref b, l) => {
446 let c: fn(_, _, _) -> _ = ExprWhile;
449 self.hash_expr(cond);
452 self.hash_name(&l.name);
458 pub fn hash_exprs(&mut self, e: &[P<Expr>]) {
464 pub fn hash_name(&mut self, n: &Name) {
465 n.as_str().hash(&mut self.s);
468 pub fn hash_path(&mut self, p: &Path) {
469 p.global.hash(&mut self.s);
470 for p in &p.segments {
471 self.hash_name(&p.identifier.name);
475 pub fn hash_stmt(&mut self, b: &Stmt) {
477 StmtDecl(ref _decl, _) => {
478 let c: fn(_, _) -> _ = StmtDecl;
482 StmtExpr(ref expr, _) => {
483 let c: fn(_, _) -> _ = StmtExpr;
485 self.hash_expr(expr);
487 StmtSemi(ref expr, _) => {
488 let c: fn(_, _) -> _ = StmtSemi;
490 self.hash_expr(expr);