about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/eta_reduction.rs7
-rw-r--r--tests/ui/eta.fixed19
-rw-r--r--tests/ui/eta.rs19
3 files changed, 45 insertions, 0 deletions
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 263bff4873c..d23c0c225e1 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
+use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -169,11 +170,17 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
     if params.len() != call_args.len() {
         return false;
     }
+    let binding_modes = cx.typeck_results().pat_binding_modes();
     std::iter::zip(params, call_args).all(|(param, arg)| {
         match param.pat.kind {
             PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
             _ => return false,
         }
+        // checks that parameters are not bound as `ref` or `ref mut`
+        if let Some(BindingMode::BindByReference(_)) = binding_modes.get(param.pat.hir_id) {
+            return false;
+        }
+
         match *cx.typeck_results().expr_adjustments(arg) {
             [] => true,
             [
diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed
index 618f80cdcf8..5aedbea381f 100644
--- a/tests/ui/eta.fixed
+++ b/tests/ui/eta.fixed
@@ -256,3 +256,22 @@ fn arc_fp() {
     (0..5).map(|n| arc(n));
     Some(4).map(|n| ref_arc(n));
 }
+
+// #8460 Don't replace closures with params bounded as `ref`
+mod bind_by_ref {
+    struct A;
+    struct B;
+
+    impl From<&A> for B {
+        fn from(A: &A) -> Self {
+            B
+        }
+    }
+
+    fn test() {
+        // should not lint
+        Some(A).map(|a| B::from(&a));
+        // should not lint
+        Some(A).map(|ref a| B::from(a));
+    }
+}
diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs
index a759e6eb514..5fdf7fb9771 100644
--- a/tests/ui/eta.rs
+++ b/tests/ui/eta.rs
@@ -256,3 +256,22 @@ fn arc_fp() {
     (0..5).map(|n| arc(n));
     Some(4).map(|n| ref_arc(n));
 }
+
+// #8460 Don't replace closures with params bounded as `ref`
+mod bind_by_ref {
+    struct A;
+    struct B;
+
+    impl From<&A> for B {
+        fn from(A: &A) -> Self {
+            B
+        }
+    }
+
+    fn test() {
+        // should not lint
+        Some(A).map(|a| B::from(&a));
+        // should not lint
+        Some(A).map(|ref a| B::from(a));
+    }
+}