summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-07-19 19:39:37 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-07-19 19:39:37 +0000
commit3ff758877fd994ebeb7a3a0a65fae4de3f66b8d7 (patch)
treef6853ae4320fd56b689494b45e2af5903049b96d /compiler/rustc_trait_selection/src
parent3811f40d2701b3a8923d2d46e36dd3a93a824b49 (diff)
downloadrust-3ff758877fd994ebeb7a3a0a65fae4de3f66b8d7.tar.gz
rust-3ff758877fd994ebeb7a3a0a65fae4de3f66b8d7.zip
More accurate suggestion for `-> Box<dyn Trait>` or `-> impl Trait`
When encountering `-> Trait`, suggest `-> Box<dyn Trait>` (instead of `-> Box<Trait>`.

If there's a single returned type within the `fn`, suggest `-> impl Trait`.
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs48
1 files changed, 34 insertions, 14 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index fa2acdd4a54..ffc8839435e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1793,25 +1793,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         err.children.clear();
 
         let span = obligation.cause.span;
-        if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
+        let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);
+
+        let mut visitor = ReturnsVisitor::default();
+        visitor.visit_body(&body);
+
+        let (pre, impl_span) = if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
             && snip.starts_with("dyn ")
         {
-            err.span_suggestion(
-                span.with_hi(span.lo() + BytePos(4)),
-                "return an `impl Trait` instead of a `dyn Trait`, \
-                if all returned values are the same type",
+            ("", span.with_hi(span.lo() + BytePos(4)))
+        } else {
+            ("dyn ", span.shrink_to_lo())
+        };
+        let alternatively = if visitor
+            .returns
+            .iter()
+            .map(|expr| self.typeck_results.as_ref().unwrap().expr_ty_adjusted_opt(expr))
+            .collect::<FxHashSet<_>>()
+            .len()
+            <= 1
+        {
+            err.span_suggestion_verbose(
+                impl_span,
+                "consider returning an `impl Trait` instead of a `dyn Trait`",
                 "impl ",
                 Applicability::MaybeIncorrect,
             );
-        }
-
-        let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);
-
-        let mut visitor = ReturnsVisitor::default();
-        visitor.visit_body(&body);
+            "alternatively, "
+        } else {
+            err.help("if there were a single returned type, you could use `impl Trait` instead");
+            ""
+        };
 
-        let mut sugg =
-            vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
+        let mut sugg = vec![
+            (span.shrink_to_lo(), format!("Box<{pre}")),
+            (span.shrink_to_hi(), ">".to_string()),
+        ];
         sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
             let span =
                 expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
@@ -1837,7 +1854,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }));
 
         err.multipart_suggestion(
-            "box the return type, and wrap all of the returned values in `Box::new`",
+            format!(
+                "{alternatively}box the return type, and wrap all of the returned values in \
+                 `Box::new`",
+            ),
             sugg,
             Applicability::MaybeIncorrect,
         );