diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 6df62b5965ee..f587dac843eb 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,9 +1,9 @@ use crate::utils::{in_macro, span_lint}; -use syntax::ast::*; -use rustc::lint::{EarlyLintPass, EarlyContext, LintArray, LintPass}; +use core::hash::{Hash, Hasher}; +use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; use rustc_data_structures::fx::FxHashSet; -use core::hash::{Hash, Hasher}; +use syntax::ast::*; declare_clippy_lint! { pub TYPE_REPETITION_IN_BOUNDS, @@ -11,15 +11,12 @@ declare_clippy_lint! { "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" } - #[derive(Copy, Clone)] pub struct TraitBounds; impl LintPass for TraitBounds { fn get_lints(&self) -> LintArray { - lint_array!( - TYPE_REPETITION_IN_BOUNDS - ) + lint_array!(TYPE_REPETITION_IN_BOUNDS) } fn name(&self) -> &'static str { @@ -55,16 +52,17 @@ impl<'ast> Hash for HashTy<'ast> { HashTy(ty).hash(h); } }, - Tup(ps) => for p in ps { - HashTy(p).hash(h); + Tup(ps) => { + for p in ps { + HashTy(p).hash(h); + } }, Path(qs, p) => { if let Some(q) = qs { HashTy(&q.ty).hash(h); } }, - TraitObject(b, os) => { - }, + TraitObject(b, os) => {}, ImplTrait(t, o) => {}, Paren(p) => HashTy(p).hash(h), _ => {}, @@ -74,21 +72,63 @@ impl<'ast> Hash for HashTy<'ast> { impl<'ast> PartialEq for HashTy<'ast> { fn eq(&self, other: &Self) -> bool { - unimplemented!() + use TyKind::*; + + if std::mem::discriminant(&self.0.node) != std::mem::discriminant(&other.0.node) { + return false; + } + match (&self.0.node, &other.0.node) { + (Slice(p), Slice(q)) => HashTy(p).eq(&HashTy(q)), + (Array(p, len1), Array(q, len2)) => HashTy(p).eq(&HashTy(q)), + (Ptr(mt), Ptr(mt2)) => (mt.mutbl == mt2.mutbl) && HashTy(&mt.ty).eq(&HashTy(&mt2.ty)), + (Rptr(l, mt), Rptr(l2, mt2)) => mt.mutbl == mt2.mutbl && HashTy(&mt.ty).eq(&HashTy(&mt2.ty)), + (BareFn(p), BareFn(p2)) => { + if p.decl.inputs.len() != p2.decl.inputs.len() { + false + } else { + let arg_not_match = p + .decl + .inputs + .iter() + .zip(p2.decl.inputs.iter()) + .any(|(a, b)| !HashTy(&a.ty).eq(&HashTy(&b.ty))); + + let ret_type_match = match (&p.decl.output, &p2.decl.output) { + (&FunctionRetTy::Default(_), &FunctionRetTy::Default(_)) => true, + (&FunctionRetTy::Ty(ref t1), &FunctionRetTy::Ty(ref t2)) => HashTy(t1).eq(&HashTy(t2)), + _ => false, + }; + !arg_not_match && ret_type_match + } + }, + (Tup(p1), Tup(p2)) => { + p1.len() == p2.len() && p1.iter().zip(p2.iter()).all(|(a, b)| HashTy(a).eq(&HashTy(b))) + }, + (Path(q1, _), Path(q2, _)) => { + if let (Some(a), Some(b)) = (q1, q2) { + HashTy(&a.ty).eq(&HashTy(&b.ty)) + } else { + false + } + }, + (TraitObject(_, _), TraitObject(_, _)) => true, + (ImplTrait(_, _), ImplTrait(_, _)) => true, + (Paren(p), Paren(q)) => HashTy(p).eq(&HashTy(q)), + _ => false, + } } fn ne(&self, other: &Self) -> bool { - unimplemented!() + !self.eq(other) } } impl<'ast> Eq for HashTy<'ast> {} - impl EarlyLintPass for TraitBounds { fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { if in_macro(gen.span) { - return + return; } let mut set = FxHashSet::default(); for bound in &gen.where_clause.predicates {