about summary refs log tree commit diff
diff options
context:
space:
mode:
authordswij <dharmasw@outlook.com>2025-07-06 09:58:44 +0000
committerGitHub <noreply@github.com>2025-07-06 09:58:44 +0000
commit8d688c6f6059e9bb736b01e011137b760d692fda (patch)
tree4b722197b0d0b682f5c6f44b4394503ab3e561d1
parent7c39d378e55331f2f181974a3740e9ade45790c4 (diff)
parent8ceb91e1c7f3d644ca26f45ae63dac2216f98a4e (diff)
downloadrust-8d688c6f6059e9bb736b01e011137b760d692fda.tar.gz
rust-8d688c6f6059e9bb736b01e011137b760d692fda.zip
Do not remove `as` if it changes the type (#15182)
While `expr as T` can be removed as a statement if `expr` has no
side-effect, the `as T` part alone cannot be removed if the type of
`expr` would be ambiguous without the cast.

changelog: [`unnecessary_operation`]: do not remove casts if they are
useful to type the expression

Fixes rust-lang/rust-clippy#15173
-rw-r--r--clippy_lints/src/no_effect.rs6
-rw-r--r--tests/ui/unnecessary_operation.fixed13
-rw-r--r--tests/ui/unnecessary_operation.rs13
3 files changed, 30 insertions, 2 deletions
diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs
index 02c48166131..72e6503e7e4 100644
--- a/clippy_lints/src/no_effect.rs
+++ b/clippy_lints/src/no_effect.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::has_drop;
+use clippy_utils::ty::{expr_type_is_certain, has_drop};
 use clippy_utils::{
     in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
 };
@@ -340,11 +340,13 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
         },
         ExprKind::Array(v) | ExprKind::Tup(v) => Some(v.iter().collect()),
         ExprKind::Repeat(inner, _)
-        | ExprKind::Cast(inner, _)
         | ExprKind::Type(inner, _)
         | ExprKind::Unary(_, inner)
         | ExprKind::Field(inner, _)
         | ExprKind::AddrOf(_, _, inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
+        ExprKind::Cast(inner, _) if expr_type_is_certain(cx, inner) => {
+            reduce_expression(cx, inner).or_else(|| Some(vec![inner]))
+        },
         ExprKind::Struct(_, fields, ref base) => {
             if has_drop(cx, cx.typeck_results().expr_ty(expr)) {
                 None
diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed
index 645b56fe95e..ac9fa4de20a 100644
--- a/tests/ui/unnecessary_operation.fixed
+++ b/tests/ui/unnecessary_operation.fixed
@@ -144,3 +144,16 @@ const fn foo() {
     assert!([42, 55].len() > get_usize());
     //~^ unnecessary_operation
 }
+
+fn issue15173() {
+    // No lint as `Box::new(None)` alone would be ambiguous
+    Box::new(None) as Box<Option<i32>>;
+}
+
+#[expect(clippy::redundant_closure_call)]
+fn issue15173_original<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) {
+    Box::new(move |value| {
+        (|_| handler.clone()())(value);
+        None
+    }) as Box<dyn Fn(i32) -> Option<i32>>;
+}
diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs
index 97e90269c5c..a3e6c6288ad 100644
--- a/tests/ui/unnecessary_operation.rs
+++ b/tests/ui/unnecessary_operation.rs
@@ -150,3 +150,16 @@ const fn foo() {
     [42, 55][get_usize()];
     //~^ unnecessary_operation
 }
+
+fn issue15173() {
+    // No lint as `Box::new(None)` alone would be ambiguous
+    Box::new(None) as Box<Option<i32>>;
+}
+
+#[expect(clippy::redundant_closure_call)]
+fn issue15173_original<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) {
+    Box::new(move |value| {
+        (|_| handler.clone()())(value);
+        None
+    }) as Box<dyn Fn(i32) -> Option<i32>>;
+}