about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2024-01-13 13:14:16 +0100
committerSamuel Tardieu <sam@rfc1149.net>2024-01-13 13:19:55 +0100
commite02535696948a921937e4768421cf4cf9b8e7a53 (patch)
tree124fcb26223e1104aad70ac118a8c134a8f5b1b9
parenta71211d0b52c01f1b37fe544e0e13fd1bdc31979 (diff)
downloadrust-e02535696948a921937e4768421cf4cf9b8e7a53.tar.gz
rust-e02535696948a921937e4768421cf4cf9b8e7a53.zip
from_over_into: suggest a correct conversion to ()
-rw-r--r--clippy_lints/src/from_over_into.rs9
-rw-r--r--tests/ui/from_over_into.fixed8
-rw-r--r--tests/ui/from_over_into.rs8
-rw-r--r--tests/ui/from_over_into.stderr16
4 files changed, 37 insertions, 4 deletions
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index fa1f98ba013..93527bcdf5c 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -6,8 +6,8 @@ use clippy_utils::source::snippet_opt;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_path, Visitor};
 use rustc_hir::{
-    GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty,
-    TyKind,
+    FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path,
+    PathSegment, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter::OnlyBodies;
@@ -181,6 +181,9 @@ fn convert_to_from(
     let from = snippet_opt(cx, self_ty.span)?;
     let into = snippet_opt(cx, target_ty.span)?;
 
+    let return_type = matches!(sig.decl.output, FnRetTy::Return(_))
+        .then_some(String::from("Self"))
+        .unwrap_or_default();
     let mut suggestions = vec![
         // impl Into<T> for U  ->  impl From<T> for U
         //      ~~~~                    ~~~~
@@ -199,7 +202,7 @@ fn convert_to_from(
         (self_ident.span, format!("val: {from}")),
         // fn into(self) -> T  ->  fn into(self) -> Self
         //                  ~                       ~~~~
-        (sig.decl.output.span(), String::from("Self")),
+        (sig.decl.output.span(), return_type),
     ];
 
     let mut finder = SelfFinder {
diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed
index 18d285693e6..4a68505ee0b 100644
--- a/tests/ui/from_over_into.fixed
+++ b/tests/ui/from_over_into.fixed
@@ -89,4 +89,12 @@ fn msrv_1_41() {
     }
 }
 
+fn issue_12138() {
+    struct Hello;
+
+    impl From<Hello> for () {
+        fn from(val: Hello) {}
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs
index 779ef709e92..bf3ed0c2b64 100644
--- a/tests/ui/from_over_into.rs
+++ b/tests/ui/from_over_into.rs
@@ -89,4 +89,12 @@ fn msrv_1_41() {
     }
 }
 
+fn issue_12138() {
+    struct Hello;
+
+    impl Into<()> for Hello {
+        fn into(self) {}
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr
index 784843ce5fd..f1370ed844f 100644
--- a/tests/ui/from_over_into.stderr
+++ b/tests/ui/from_over_into.stderr
@@ -86,5 +86,19 @@ LL ~         fn from(val: Vec<T>) -> Self {
 LL ~             FromOverInto(val)
    |
 
-error: aborting due to 6 previous errors
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into.rs:95:5
+   |
+LL |     impl Into<()> for Hello {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
+           https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
+help: replace the `Into` implementation with `From<issue_12138::Hello>`
+   |
+LL ~     impl From<Hello> for () {
+LL ~         fn from(val: Hello) {}
+   |
+
+error: aborting due to 7 previous errors