about summary refs log tree commit diff
diff options
context:
space:
mode:
authordswij <dharmasw@outlook.com>2025-03-26 05:08:33 +0000
committerGitHub <noreply@github.com>2025-03-26 05:08:33 +0000
commit939d5f93eb62f3237f4b35fbaba1226b3340b3e6 (patch)
tree1ec4b9363fc6fb13392f6fe868e03b82a208babb
parent4517b4260f0add8ecb4761ed7ca537a6d22f7ec3 (diff)
parent8bc164b81824a1d13a6cb10ebe6d169cea82916e (diff)
downloadrust-939d5f93eb62f3237f4b35fbaba1226b3340b3e6.tar.gz
rust-939d5f93eb62f3237f4b35fbaba1226b3340b3e6.zip
fix: `option_if_let_else` suggests wrongly when coercion requires explicit cast (#14389)
Closes #11059

changelog: `option_if_let_else`: fix wrong suggestion when coersion
requires explicit cast
-rw-r--r--clippy_lints/src/option_if_let_else.rs13
-rw-r--r--tests/ui/option_if_let_else.fixed14
-rw-r--r--tests/ui/option_if_let_else.rs14
3 files changed, 39 insertions, 2 deletions
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index f37f3a12d4e..9487cec87ef 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -4,8 +4,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_copy;
 use clippy_utils::{
-    CaptureKind, can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context,
-    is_res_lang_ctor, peel_blocks, peel_hir_expr_while,
+    CaptureKind, can_move_expr_to_closure, eager_or_lazy, expr_requires_coercion, higher, is_else_clause,
+    is_in_const_context, is_res_lang_ctor, peel_blocks, peel_hir_expr_while,
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -212,6 +212,15 @@ fn try_get_option_occurrence<'tcx>(
             }
         }
 
+        let some_body_ty = cx.typeck_results().expr_ty(some_body);
+        let none_body_ty = cx.typeck_results().expr_ty(none_body);
+        // Check if coercion is needed for the `None` arm. If so, we cannot suggest because it will
+        // introduce a type mismatch. A special case is when both arms have the same type, then
+        // coercion is fine.
+        if some_body_ty != none_body_ty && expr_requires_coercion(cx, none_body) {
+            return None;
+        }
+
         let mut app = Applicability::Unspecified;
 
         let (none_body, is_argless_call) = match none_body.kind {
diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed
index ee309889601..fe3ac9e8f92 100644
--- a/tests/ui/option_if_let_else.fixed
+++ b/tests/ui/option_if_let_else.fixed
@@ -288,3 +288,17 @@ mod issue13964 {
         };
     }
 }
+
+mod issue11059 {
+    use std::fmt::Debug;
+
+    fn box_coercion_unsize(o: Option<i32>) -> Box<dyn Debug> {
+        if let Some(o) = o { Box::new(o) } else { Box::new("foo") }
+    }
+
+    static S: String = String::new();
+
+    fn deref_with_overload(o: Option<&str>) -> &str {
+        if let Some(o) = o { o } else { &S }
+    }
+}
diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs
index 525a5df4371..5b7498bc8e2 100644
--- a/tests/ui/option_if_let_else.rs
+++ b/tests/ui/option_if_let_else.rs
@@ -351,3 +351,17 @@ mod issue13964 {
         };
     }
 }
+
+mod issue11059 {
+    use std::fmt::Debug;
+
+    fn box_coercion_unsize(o: Option<i32>) -> Box<dyn Debug> {
+        if let Some(o) = o { Box::new(o) } else { Box::new("foo") }
+    }
+
+    static S: String = String::new();
+
+    fn deref_with_overload(o: Option<&str>) -> &str {
+        if let Some(o) = o { o } else { &S }
+    }
+}