about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGrzegorz <grzegorz.bartoszek@thaumatec.com>2019-02-26 12:12:27 +0100
committerGrzegorz <grzegorz.bartoszek@thaumatec.com>2019-02-26 12:12:27 +0100
commita7f4d41a7d1aa8547df583bd0239a3e35c740018 (patch)
tree82e7e937e303024c41ccbb0c809ab97d5dc8a49a
parentd0717d1f9531a03d154aaeb0cad94c243915a146 (diff)
downloadrust-a7f4d41a7d1aa8547df583bd0239a3e35c740018.tar.gz
rust-a7f4d41a7d1aa8547df583bd0239a3e35c740018.zip
do not trigger redundant_closure when there is a difference in borrow level between closure parameter and "self"
-rw-r--r--clippy_lints/src/eta_reduction.rs23
-rw-r--r--tests/ui/eta.rs8
2 files changed, 22 insertions, 9 deletions
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 05793f32c6c..331d1a0ec1d 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -133,18 +133,13 @@ fn get_ufcs_type_name(
     let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id).sty;
 
     if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
-        //if the method expectes &self, ufcs requires explicit borrowing so closure can't be removed
-        return match (expected_type_of_self, actual_type_of_self) {
-            (ty::Ref(_, _, _), ty::Ref(_, _, _)) => Some(cx.tcx.item_path_str(trait_id)),
-            (l, r) => match (l, r) {
-                (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => None,
-                (_, _) => Some(cx.tcx.item_path_str(trait_id)),
-            },
-        };
+        if match_borrow_depth(expected_type_of_self, actual_type_of_self) {
+            return Some(cx.tcx.item_path_str(trait_id));
+        }
     }
 
     cx.tcx.impl_of_method(method_def_id).and_then(|_| {
-        //a type may implicitly implement other types methods (e.g. Deref)
+        //a type may implicitly implement other type's methods (e.g. Deref)
         if match_types(expected_type_of_self, actual_type_of_self) {
             return Some(get_type_name(cx, &actual_type_of_self));
         }
@@ -152,6 +147,16 @@ fn get_ufcs_type_name(
     })
 }
 
+fn match_borrow_depth(lhs: &ty::TyKind<'_>, rhs: &ty::TyKind<'_>) -> bool {
+    match (lhs, rhs) {
+        (ty::Ref(_, t1, _), ty::Ref(_, t2, _)) => match_borrow_depth(&t1.sty, &t2.sty),
+        (l, r) => match (l, r) {
+            (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
+            (_, _) => true,
+        },
+    }
+}
+
 fn match_types(lhs: &ty::TyKind<'_>, rhs: &ty::TyKind<'_>) -> bool {
     match (lhs, rhs) {
         (ty::Bool, ty::Bool)
diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs
index 6eeb093eae9..f777939c67d 100644
--- a/tests/ui/eta.rs
+++ b/tests/ui/eta.rs
@@ -88,6 +88,14 @@ fn test_redundant_closures_containing_method_calls() {
     let c = Some(TestStruct { some_ref: &i })
         .as_ref()
         .map(|c| c.to_ascii_uppercase());
+
+    fn test_different_borrow_levels<T>(t: &[&T])
+    where
+        T: TestTrait,
+    {
+        t.iter().filter(|x| x.trait_foo_ref());
+        t.iter().map(|x| x.trait_foo_ref());
+    }
 }
 
 fn meta<F>(f: F)