diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 4aee22a4afc3be6d56c75d6520beb200e90f3575..fafc970977009d1fe142c798049956cdef61ecec 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,3 +1,4 @@ +use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::BOOL_THEN; use clippy_utils::source::snippet_opt; @@ -7,10 +8,9 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Binder; use rustc_span::{sym, Span}; -use super::FILTER_MAP_BOOL_THEN; - pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { if !in_external_macro(cx.sess(), expr.span) && is_trait_method(cx, expr, sym::Iterator) @@ -21,7 +21,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & // `inputs` and `params` here as we need both the type and the span && let param_ty = closure.fn_decl.inputs[0] && let param = body.params[0] - && is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs()) + // Issue #11309 + && let param_ty = cx.tcx.liberate_late_bound_regions( + closure.def_id.to_def_id(), + Binder::bind_with_vars( + cx.typeck_results().node_type(param_ty.hir_id), + cx.tcx.late_bound_vars(cx.tcx.hir().local_def_id_to_hir_id(closure.def_id)), + ), + ) + && is_copy(cx, param_ty) && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind && let ExprKind::Closure(then_closure) = then_arg.kind && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value) diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed index 3e72fee4b072a8f9d6a44751baf3c795664bfb58..b85e3659a4c773691425af56f419e778820eaf8b 100644 --- a/tests/ui/filter_map_bool_then.fixed +++ b/tests/ui/filter_map_bool_then.fixed @@ -4,6 +4,7 @@ clippy::clone_on_copy, clippy::map_identity, clippy::unnecessary_lazy_evaluations, + clippy::unnecessary_filter_map, unused )] #![warn(clippy::filter_map_bool_then)] @@ -29,9 +30,14 @@ fn main() { .copied() .filter(|&i| i != 1000) .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1); + // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`, + // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`), + // we can lint this and still get the same input type. + let v = vec![NonCopy, NonCopy]; + v.clone().iter().filter(|&i| (i == &NonCopy)).map(|i| i); // Do not lint let v = vec![NonCopy, NonCopy]; - v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); + v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i)); external! { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); @@ -42,3 +48,7 @@ fn main() { v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); } } + +fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str> { + iter.filter_map(|(_, s): (&str, _)| Some(s)).collect() +} diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs index 38a04e57de456731f324b3600e5655176158643b..c009b4e6ebeb05918491b07f38c668ea7ef290f2 100644 --- a/tests/ui/filter_map_bool_then.rs +++ b/tests/ui/filter_map_bool_then.rs @@ -4,6 +4,7 @@ clippy::clone_on_copy, clippy::map_identity, clippy::unnecessary_lazy_evaluations, + clippy::unnecessary_filter_map, unused )] #![warn(clippy::filter_map_bool_then)] @@ -29,9 +30,14 @@ fn main() { .copied() .filter(|&i| i != 1000) .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); - // Do not lint + // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`, + // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`), + // we can lint this and still get the same input type. let v = vec![NonCopy, NonCopy]; v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); + // Do not lint + let v = vec![NonCopy, NonCopy]; + v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i)); external! { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); @@ -42,3 +48,7 @@ fn main() { v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); } } + +fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str> { + iter.filter_map(|(_, s): (&str, _)| Some(s)).collect() +} diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr index b411cd83dfd2934531ec2c1833e77ad27f189692..b47f8eac7f00594b3a8b30eaf3652a92f1465a8c 100644 --- a/tests/ui/filter_map_bool_then.stderr +++ b/tests/ui/filter_map_bool_then.stderr @@ -1,5 +1,5 @@ error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:19:22 + --> $DIR/filter_map_bool_then.rs:20:22 | LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` @@ -7,28 +7,34 @@ LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); = note: `-D clippy::filter-map-bool-then` implied by `-D warnings` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:20:27 + --> $DIR/filter_map_bool_then.rs:21:27 | LL | v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:23:10 + --> $DIR/filter_map_bool_then.rs:24:10 | LL | .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:27:10 + --> $DIR/filter_map_bool_then.rs:28:10 | LL | .filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:31:10 + --> $DIR/filter_map_bool_then.rs:32:10 | LL | .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)` -error: aborting due to 5 previous errors +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:37:22 + | +LL | v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i == &NonCopy)).map(|i| i)` + +error: aborting due to 6 previous errors