summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs228
-rw-r--r--tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr20
-rw-r--r--tests/ui/extern/unsized-extern-derefmove.stderr8
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr9
-rw-r--r--tests/ui/inference/deref-suggestion.stderr9
-rw-r--r--tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr9
-rw-r--r--tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr16
-rw-r--r--tests/ui/static/bad-const-type.stderr9
-rw-r--r--tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.fixed14
-rw-r--r--tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.rs12
-rw-r--r--tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr58
-rw-r--r--tests/ui/suggestions/issue-52820.stderr11
-rw-r--r--tests/ui/suggestions/issue-53692.stderr23
-rw-r--r--tests/ui/suggestions/issue-59819.stderr10
-rw-r--r--tests/ui/suggestions/issue-83943.stderr9
-rw-r--r--tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr9
-rw-r--r--tests/ui/switched-expectations.stderr9
-rw-r--r--tests/ui/typeck/conversion-methods.stderr30
19 files changed, 316 insertions, 179 deletions
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 5746c28a2ab..a128f8d31a1 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1165,7 +1165,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         self.push_suggestion(CodeSuggestion {
             substitutions,
             msg: self.subdiagnostic_message_to_diagnostic_message(msg),
-            style: SuggestionStyle::ShowCode,
+            style: SuggestionStyle::ShowAlways,
             applicability,
         });
         self
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 3e64573aa03..8c9eb41568f 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1321,7 +1321,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
             let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
 
-            let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) =
+            let (ref_inner_ty_satisfies_pred, ref_inner_ty_is_mut) =
                 if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code()
                     && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
                 {
@@ -1333,117 +1333,139 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     (false, false)
                 };
 
-            if imm_ref_self_ty_satisfies_pred
-                || mut_ref_self_ty_satisfies_pred
-                || ref_inner_ty_satisfies_pred
-            {
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    // We don't want a borrowing suggestion on the fields in structs,
-                    // ```
-                    // struct Foo {
-                    //  the_foos: Vec<Foo>
-                    // }
-                    // ```
-                    if !matches!(
-                        span.ctxt().outer_expn_data().kind,
-                        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
-                    ) {
-                        return false;
-                    }
-                    if snippet.starts_with('&') {
-                        // This is already a literal borrow and the obligation is failing
-                        // somewhere else in the obligation chain. Do not suggest non-sense.
-                        return false;
-                    }
-                    // We have a very specific type of error, where just borrowing this argument
-                    // might solve the problem. In cases like this, the important part is the
-                    // original type obligation, not the last one that failed, which is arbitrary.
-                    // Because of this, we modify the error to refer to the original obligation and
-                    // return early in the caller.
-
-                    let msg = format!(
-                        "the trait bound `{}` is not satisfied",
-                        self.tcx.short_string(old_pred, err.long_ty_path()),
-                    );
-                    let self_ty_str =
-                        self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path());
-                    if has_custom_message {
-                        err.note(msg);
-                    } else {
-                        err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];
-                    }
-                    err.span_label(
-                        span,
-                        format!(
-                            "the trait `{}` is not implemented for `{self_ty_str}`",
-                            old_pred.print_modifiers_and_trait_path()
-                        ),
-                    );
+            let is_immut = imm_ref_self_ty_satisfies_pred
+                || (ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut);
+            let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut;
+            if !is_immut && !is_mut {
+                return false;
+            }
+            let Ok(_snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {
+                return false;
+            };
+            // We don't want a borrowing suggestion on the fields in structs
+            // ```
+            // #[derive(Clone)]
+            // struct Foo {
+            //     the_foos: Vec<Foo>
+            // }
+            // ```
+            if !matches!(
+                span.ctxt().outer_expn_data().kind,
+                ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+            ) {
+                return false;
+            }
+            // We have a very specific type of error, where just borrowing this argument
+            // might solve the problem. In cases like this, the important part is the
+            // original type obligation, not the last one that failed, which is arbitrary.
+            // Because of this, we modify the error to refer to the original obligation and
+            // return early in the caller.
 
-                    if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
-                        err.span_suggestions(
-                            span.shrink_to_lo(),
-                            "consider borrowing here",
-                            ["&".to_string(), "&mut ".to_string()],
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
-                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
-                        let sugg_msg = format!(
-                            "consider{} borrowing here",
-                            if is_mut { " mutably" } else { "" }
-                        );
+            let mut label = || {
+                let msg = format!(
+                    "the trait bound `{}` is not satisfied",
+                    self.tcx.short_string(old_pred, err.long_ty_path()),
+                );
+                let self_ty_str =
+                    self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path());
+                if has_custom_message {
+                    err.note(msg);
+                } else {
+                    err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];
+                }
+                err.span_label(
+                    span,
+                    format!(
+                        "the trait `{}` is not implemented for `{self_ty_str}`",
+                        old_pred.print_modifiers_and_trait_path()
+                    ),
+                );
+            };
 
-                        // Issue #109436, we need to add parentheses properly for method calls
-                        // for example, `foo.into()` should be `(&foo).into()`
-                        if let Some(_) =
-                            self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50))
-                        {
-                            err.multipart_suggestion_verbose(
-                                sugg_msg,
-                                vec![
-                                    (span.shrink_to_lo(), format!("({sugg_prefix}")),
-                                    (span.shrink_to_hi(), ")".to_string()),
-                                ],
-                                Applicability::MaybeIncorrect,
-                            );
-                            return true;
-                        }
+            let mut sugg_prefixes = vec![];
+            if is_immut {
+                sugg_prefixes.push("&");
+            }
+            if is_mut {
+                sugg_prefixes.push("&mut ");
+            }
+            let sugg_msg = format!(
+                "consider{} borrowing here",
+                if is_mut && !is_immut { " mutably" } else { "" },
+            );
 
-                        // Issue #104961, we need to add parentheses properly for compound expressions
-                        // for example, `x.starts_with("hi".to_string() + "you")`
-                        // should be `x.starts_with(&("hi".to_string() + "you"))`
-                        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id)
-                        else {
-                            return false;
-                        };
-                        let mut expr_finder = FindExprBySpan::new(span, self.tcx);
-                        expr_finder.visit_expr(body.value);
-                        let Some(expr) = expr_finder.result else {
-                            return false;
-                        };
-                        let needs_parens = expr_needs_parens(expr);
+            // Issue #104961, we need to add parentheses properly for compound expressions
+            // for example, `x.starts_with("hi".to_string() + "you")`
+            // should be `x.starts_with(&("hi".to_string() + "you"))`
+            let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
+                return false;
+            };
+            let mut expr_finder = FindExprBySpan::new(span, self.tcx);
+            expr_finder.visit_expr(body.value);
 
-                        let span = if needs_parens { span } else { span.shrink_to_lo() };
-                        let suggestions = if !needs_parens {
-                            vec![(span.shrink_to_lo(), sugg_prefix)]
-                        } else {
+            if let Some(ty) = expr_finder.ty_result {
+                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(ty.hir_id)
+                    && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, _)) = expr.kind
+                    && ty.span == span
+                {
+                    // We've encountered something like `str::from("")`, where the intended code
+                    // was likely `<&str>::from("")`. #143393.
+                    label();
+                    err.multipart_suggestions(
+                        sugg_msg,
+                        sugg_prefixes.into_iter().map(|sugg_prefix| {
                             vec![
-                                (span.shrink_to_lo(), format!("{sugg_prefix}(")),
-                                (span.shrink_to_hi(), ")".to_string()),
+                                (span.shrink_to_lo(), format!("<{sugg_prefix}")),
+                                (span.shrink_to_hi(), ">".to_string()),
                             ]
-                        };
-                        err.multipart_suggestion_verbose(
-                            sugg_msg,
-                            suggestions,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
+                        }),
+                        Applicability::MaybeIncorrect,
+                    );
                     return true;
                 }
+                return false;
             }
-            return false;
+            let Some(expr) = expr_finder.result else {
+                return false;
+            };
+            if let hir::ExprKind::AddrOf(_, _, _) = expr.kind {
+                return false;
+            }
+            let needs_parens_post = expr_needs_parens(expr);
+            let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) {
+                Node::Expr(e)
+                    if let hir::ExprKind::MethodCall(_, base, _, _) = e.kind
+                        && base.hir_id == expr.hir_id =>
+                {
+                    true
+                }
+                _ => false,
+            };
+
+            label();
+            let suggestions = sugg_prefixes.into_iter().map(|sugg_prefix| {
+                match (needs_parens_pre, needs_parens_post) {
+                    (false, false) => vec![(span.shrink_to_lo(), sugg_prefix.to_string())],
+                    // We have something like `foo.bar()`, where we want to bororw foo, so we need
+                    // to suggest `(&mut foo).bar()`.
+                    (false, true) => vec![
+                        (span.shrink_to_lo(), format!("{sugg_prefix}(")),
+                        (span.shrink_to_hi(), ")".to_string()),
+                    ],
+                    // Issue #109436, we need to add parentheses properly for method calls
+                    // for example, `foo.into()` should be `(&foo).into()`
+                    (true, false) => vec![
+                        (span.shrink_to_lo(), format!("({sugg_prefix}")),
+                        (span.shrink_to_hi(), ")".to_string()),
+                    ],
+                    (true, true) => vec![
+                        (span.shrink_to_lo(), format!("({sugg_prefix}(")),
+                        (span.shrink_to_hi(), "))".to_string()),
+                    ],
+                }
+            });
+            err.multipart_suggestions(sugg_msg, suggestions, Applicability::MaybeIncorrect);
+            return true;
         };
 
         if let ObligationCauseCode::ImplDerived(cause) = &*code {
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
index 6d6bc157771..825b9e94158 100644
--- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
+++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
@@ -2,25 +2,37 @@ error[E0277]: the size for values of type `Opaque` cannot be known
   --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:43
    |
 LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
-   |                               ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |                               ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque`
    |                               |
    |                               required by a bound introduced by this call
    |
-   = help: the trait `MetaSized` is not implemented for `Opaque`
+   = note: the trait bound `Opaque: MetaSized` is not satisfied
 note: required by a bound in `std::intrinsics::size_of_val`
   --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL | const _SIZE: usize = unsafe { size_of_val(&(&4 as *const i32 as *const Opaque)) };
+   |                                           ++                                 +
+LL | const _SIZE: usize = unsafe { size_of_val(&mut (&4 as *const i32 as *const Opaque)) };
+   |                                           ++++++                                 +
 
 error[E0277]: the size for values of type `Opaque` cannot be known
   --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:45
    |
 LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
-   |                                ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |                                ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque`
    |                                |
    |                                required by a bound introduced by this call
    |
-   = help: the trait `MetaSized` is not implemented for `Opaque`
+   = note: the trait bound `Opaque: MetaSized` is not satisfied
 note: required by a bound in `std::intrinsics::align_of_val`
   --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL | const _ALIGN: usize = unsafe { align_of_val(&(&4 as *const i32 as *const Opaque)) };
+   |                                             ++                                 +
+LL | const _ALIGN: usize = unsafe { align_of_val(&mut (&4 as *const i32 as *const Opaque)) };
+   |                                             ++++++                                 +
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/extern/unsized-extern-derefmove.stderr b/tests/ui/extern/unsized-extern-derefmove.stderr
index d6be76a9d62..a9efc2e66e3 100644
--- a/tests/ui/extern/unsized-extern-derefmove.stderr
+++ b/tests/ui/extern/unsized-extern-derefmove.stderr
@@ -21,10 +21,10 @@ note: required by a bound in `Box::<T>::from_raw`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
 help: consider borrowing here
    |
-LL |     Box::from_raw(&0 as *mut _)
-   |                   +
-LL |     Box::from_raw(&mut 0 as *mut _)
-   |                   ++++
+LL |     Box::from_raw(&(0 as *mut _))
+   |                   ++           +
+LL |     Box::from_raw(&mut (0 as *mut _))
+   |                   ++++++           +
 
 error[E0277]: the size for values of type `Device` cannot be known
   --> $DIR/unsized-extern-derefmove.rs:11:5
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr
index 856c92217b9..4c429624e0b 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr
@@ -4,9 +4,12 @@ error[E0308]: mismatched types
 LL |     async fn woopsie_async(&self) -> String {
    |                                      ------ expected `String` because of return type
 LL |         42
-   |         ^^- help: try using a conversion method: `.to_string()`
-   |         |
-   |         expected `String`, found integer
+   |         ^^ expected `String`, found integer
+   |
+help: try using a conversion method
+   |
+LL |         42.to_string()
+   |           ++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/inference/deref-suggestion.stderr b/tests/ui/inference/deref-suggestion.stderr
index 8ccd28198af..027902a9f31 100644
--- a/tests/ui/inference/deref-suggestion.stderr
+++ b/tests/ui/inference/deref-suggestion.stderr
@@ -2,9 +2,8 @@ error[E0308]: mismatched types
   --> $DIR/deref-suggestion.rs:8:9
    |
 LL |     foo(s);
-   |     --- ^- help: try using a conversion method: `.to_string()`
-   |     |   |
-   |     |   expected `String`, found `&String`
+   |     --- ^ expected `String`, found `&String`
+   |     |
    |     arguments to this function are incorrect
    |
 note: function defined here
@@ -12,6 +11,10 @@ note: function defined here
    |
 LL | fn foo(_: String) {}
    |    ^^^ ---------
+help: try using a conversion method
+   |
+LL |     foo(s.to_string());
+   |          ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/deref-suggestion.rs:14:10
diff --git a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr
index ce2022374f7..9f31a731fed 100644
--- a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr
+++ b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr
@@ -38,9 +38,12 @@ error[E0308]: mismatched types
   --> $DIR/typo-in-repeat-expr-issue-80173.rs:32:29
    |
 LL |     let e = [String::new(), 10];
-   |                             ^^- help: try using a conversion method: `.to_string()`
-   |                             |
-   |                             expected `String`, found integer
+   |                             ^^ expected `String`, found integer
+   |
+help: try using a conversion method
+   |
+LL |     let e = [String::new(), 10.to_string()];
+   |                               ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/typo-in-repeat-expr-issue-80173.rs:36:19
diff --git a/tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr b/tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr
index 2da3925341e..7a3d8b43c2e 100644
--- a/tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr
+++ b/tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr
@@ -30,10 +30,10 @@ LL |     fn a(self: impl Receiver<Target=Self>) -> u32 {
    |                     ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::a`
 help: consider borrowing here
    |
-LL |     &foo.a();
-   |     +
-LL |     &mut foo.a();
-   |     ++++
+LL |     (&foo).a();
+   |     ++   +
+LL |     (&mut foo).a();
+   |     +++++    +
 
 error[E0277]: the trait bound `Foo: Deref` is not satisfied
   --> $DIR/arbitrary_self_types_generic_over_receiver.rs:21:9
@@ -48,10 +48,10 @@ LL |     fn b(self: impl Deref<Target=Self>) -> u32 {
    |                     ^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::b`
 help: consider borrowing here
    |
-LL |     &foo.b();
-   |     +
-LL |     &mut foo.b();
-   |     ++++
+LL |     (&foo).b();
+   |     ++   +
+LL |     (&mut foo).b();
+   |     +++++    +
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/static/bad-const-type.stderr b/tests/ui/static/bad-const-type.stderr
index 807cd2f7a25..8573a11ef29 100644
--- a/tests/ui/static/bad-const-type.stderr
+++ b/tests/ui/static/bad-const-type.stderr
@@ -2,9 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/bad-const-type.rs:1:20
    |
 LL | static i: String = 10;
-   |                    ^^- help: try using a conversion method: `.to_string()`
-   |                    |
-   |                    expected `String`, found integer
+   |                    ^^ expected `String`, found integer
+   |
+help: try using a conversion method
+   |
+LL | static i: String = 10.to_string();
+   |                      ++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.fixed b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.fixed
index 95fd920dec2..00b92b42bb5 100644
--- a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.fixed
+++ b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.fixed
@@ -4,14 +4,24 @@ struct S;
 trait Trait {
     fn foo() {}
 }
-impl Trait for &S {}
 impl Trait for &mut S {}
+trait Trait2 {
+    fn bar() {}
+}
+impl Trait2 for &S {}
+impl Trait2 for &mut S {}
 fn main() {
     let _ = <&str>::from("value");
     //~^ ERROR the trait bound `str: From<_>` is not satisfied
     //~| ERROR the size for values of type `str` cannot be known at compilation time
     let _ = <&mut S>::foo();
     //~^ ERROR the trait bound `S: Trait` is not satisfied
-    let _ = <&S>::foo();
+    let _ = <&mut S>::foo();
+    //~^ ERROR the trait bound `S: Trait` is not satisfied
+    let _ = <&mut S>::foo();
     //~^ ERROR the trait bound `S: Trait` is not satisfied
+    let _ = <&mut S>::bar();
+    //~^ ERROR the trait bound `S: Trait2` is not satisfied
+    let _ = <&S>::bar();
+    //~^ ERROR the trait bound `S: Trait2` is not satisfied
 }
diff --git a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.rs b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.rs
index f79d2465062..3059ccdffb4 100644
--- a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.rs
+++ b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.rs
@@ -4,8 +4,12 @@ struct S;
 trait Trait {
     fn foo() {}
 }
-impl Trait for &S {}
 impl Trait for &mut S {}
+trait Trait2 {
+    fn bar() {}
+}
+impl Trait2 for &S {}
+impl Trait2 for &mut S {}
 fn main() {
     let _ = &str::from("value");
     //~^ ERROR the trait bound `str: From<_>` is not satisfied
@@ -14,4 +18,10 @@ fn main() {
     //~^ ERROR the trait bound `S: Trait` is not satisfied
     let _ = &S::foo();
     //~^ ERROR the trait bound `S: Trait` is not satisfied
+    let _ = S::foo();
+    //~^ ERROR the trait bound `S: Trait` is not satisfied
+    let _ = &mut S::bar();
+    //~^ ERROR the trait bound `S: Trait2` is not satisfied
+    let _ = &S::bar();
+    //~^ ERROR the trait bound `S: Trait2` is not satisfied
 }
diff --git a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr
index ac96ec76da7..c2e2fe941a6 100644
--- a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr
+++ b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `str: From<_>` is not satisfied
-  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:10:14
+  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:14:14
    |
 LL |     let _ = &str::from("value");
    |              ^^^ the trait `From<_>` is not implemented for `str`
@@ -17,35 +17,71 @@ LL |     let _ = <&str>::from("value");
    |             +    +
 
 error[E0277]: the trait bound `S: Trait` is not satisfied
-  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:13:18
+  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:17:18
    |
 LL |     let _ = &mut S::foo();
    |                  ^ the trait `Trait` is not implemented for `S`
    |
-   = help: the following other types implement trait `Trait`:
-             &S
-             &mut S
+   = help: the trait `Trait` is implemented for `&mut S`
 help: you likely meant to call the associated function `foo` for type `&mut S`, but the code as written calls associated function `foo` on type `S`
    |
 LL |     let _ = <&mut S>::foo();
    |             +      +
 
 error[E0277]: the trait bound `S: Trait` is not satisfied
-  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:15:14
+  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:19:14
    |
 LL |     let _ = &S::foo();
    |              ^ the trait `Trait` is not implemented for `S`
    |
-   = help: the following other types implement trait `Trait`:
+   = help: the trait `Trait` is implemented for `&mut S`
+help: you likely meant to call the associated function `foo` for type `&S`, but the code as written calls associated function `foo` on type `S`
+   |
+LL -     let _ = &S::foo();
+LL +     let _ = <&mut S>::foo();
+   |
+
+error[E0277]: the trait bound `S: Trait` is not satisfied
+  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:21:13
+   |
+LL |     let _ = S::foo();
+   |             ^ the trait `Trait` is not implemented for `S`
+   |
+help: consider mutably borrowing here
+   |
+LL |     let _ = <&mut S>::foo();
+   |             +++++  +
+
+error[E0277]: the trait bound `S: Trait2` is not satisfied
+  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:23:18
+   |
+LL |     let _ = &mut S::bar();
+   |                  ^ the trait `Trait2` is not implemented for `S`
+   |
+   = help: the following other types implement trait `Trait2`:
              &S
              &mut S
-help: you likely meant to call the associated function `foo` for type `&S`, but the code as written calls associated function `foo` on type `S`
+help: you likely meant to call the associated function `bar` for type `&mut S`, but the code as written calls associated function `bar` on type `S`
+   |
+LL |     let _ = <&mut S>::bar();
+   |             +      +
+
+error[E0277]: the trait bound `S: Trait2` is not satisfied
+  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:25:14
+   |
+LL |     let _ = &S::bar();
+   |              ^ the trait `Trait2` is not implemented for `S`
+   |
+   = help: the following other types implement trait `Trait2`:
+             &S
+             &mut S
+help: you likely meant to call the associated function `bar` for type `&S`, but the code as written calls associated function `bar` on type `S`
    |
-LL |     let _ = <&S>::foo();
+LL |     let _ = <&S>::bar();
    |             +  +
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:10:14
+  --> $DIR/dont-suggest-borrowing-existing-borrow.rs:14:14
    |
 LL |     let _ = &str::from("value");
    |              ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -53,6 +89,6 @@ LL |     let _ = &str::from("value");
    = help: the trait `Sized` is not implemented for `str`
    = note: the return type of a function must have a statically known size
 
-error: aborting due to 4 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/issue-52820.stderr b/tests/ui/suggestions/issue-52820.stderr
index a67d7501417..de2c9542f61 100644
--- a/tests/ui/suggestions/issue-52820.stderr
+++ b/tests/ui/suggestions/issue-52820.stderr
@@ -13,10 +13,13 @@ error[E0308]: mismatched types
   --> $DIR/issue-52820.rs:13:17
    |
 LL |         brains: guts.clone(),
-   |                 ^^^^^-----^^
-   |                 |    |
-   |                 |    help: try using a conversion method: `to_string`
-   |                 expected `String`, found `&str`
+   |                 ^^^^^^^^^^^^ expected `String`, found `&str`
+   |
+help: try using a conversion method
+   |
+LL -         brains: guts.clone(),
+LL +         brains: guts.to_string(),
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/issue-53692.stderr b/tests/ui/suggestions/issue-53692.stderr
index 469a538411f..10ebb30a5b2 100644
--- a/tests/ui/suggestions/issue-53692.stderr
+++ b/tests/ui/suggestions/issue-53692.stderr
@@ -2,24 +2,31 @@ error[E0308]: mismatched types
   --> $DIR/issue-53692.rs:7:33
    |
 LL |     let items_clone: Vec<i32> = ref_items.clone();
-   |                      --------   ^^^^^^^^^^-----^^
-   |                      |          |         |
-   |                      |          |         help: try using a conversion method: `to_vec`
-   |                      |          expected `Vec<i32>`, found `&[i32]`
+   |                      --------   ^^^^^^^^^^^^^^^^^ expected `Vec<i32>`, found `&[i32]`
+   |                      |
    |                      expected due to this
    |
    = note: expected struct `Vec<i32>`
            found reference `&[i32]`
+help: try using a conversion method
+   |
+LL -     let items_clone: Vec<i32> = ref_items.clone();
+LL +     let items_clone: Vec<i32> = ref_items.to_vec();
+   |
 
 error[E0308]: mismatched types
   --> $DIR/issue-53692.rs:14:26
    |
 LL |     let string: String = s.clone();
-   |                 ------   ^^-----^^
-   |                 |        | |
-   |                 |        | help: try using a conversion method: `to_string`
-   |                 |        expected `String`, found `&str`
+   |                 ------   ^^^^^^^^^ expected `String`, found `&str`
+   |                 |
    |                 expected due to this
+   |
+help: try using a conversion method
+   |
+LL -     let string: String = s.clone();
+LL +     let string: String = s.to_string();
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/issue-59819.stderr b/tests/ui/suggestions/issue-59819.stderr
index 43acf9549c2..ab91961192f 100644
--- a/tests/ui/suggestions/issue-59819.stderr
+++ b/tests/ui/suggestions/issue-59819.stderr
@@ -28,10 +28,14 @@ error[E0308]: mismatched types
   --> $DIR/issue-59819.rs:34:21
    |
 LL |     let g: String = f;
-   |            ------   ^- help: try using a conversion method: `.to_string()`
-   |            |        |
-   |            |        expected `String`, found `Bar`
+   |            ------   ^ expected `String`, found `Bar`
+   |            |
    |            expected due to this
+   |
+help: try using a conversion method
+   |
+LL |     let g: String = f.to_string();
+   |                      ++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/suggestions/issue-83943.stderr b/tests/ui/suggestions/issue-83943.stderr
index 1a085368485..e714a126f4a 100644
--- a/tests/ui/suggestions/issue-83943.stderr
+++ b/tests/ui/suggestions/issue-83943.stderr
@@ -6,11 +6,14 @@ LL | |         "A".to_string()
    | |         --------------- expected because of this
 LL | |     } else {
 LL | |         "B"
-   | |         ^^^- help: try using a conversion method: `.to_string()`
-   | |         |
-   | |         expected `String`, found `&str`
+   | |         ^^^ expected `String`, found `&str`
 LL | |     };
    | |_____- `if` and `else` have incompatible types
+   |
+help: try using a conversion method
+   |
+LL |         "B".to_string()
+   |            ++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr
index c721ceb1146..ed94ebd27ff 100644
--- a/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr
+++ b/tests/ui/suggestions/only-suggest-removal-of-conversion-method-calls.stderr
@@ -5,9 +5,12 @@ LL | fn get_name() -> String {
    |                  ------ expected `String` because of return type
 ...
 LL |     your_name.trim()
-   |     ^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
-   |     |
-   |     expected `String`, found `&str`
+   |     ^^^^^^^^^^^^^^^^ expected `String`, found `&str`
+   |
+help: try using a conversion method
+   |
+LL |     your_name.trim().to_string()
+   |                     ++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/switched-expectations.stderr b/tests/ui/switched-expectations.stderr
index cc576747400..e235c2da1f7 100644
--- a/tests/ui/switched-expectations.stderr
+++ b/tests/ui/switched-expectations.stderr
@@ -2,9 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/switched-expectations.rs:3:30
    |
 LL |     let ref string: String = var;
-   |                              ^^^- help: try using a conversion method: `.to_string()`
-   |                              |
-   |                              expected `String`, found `i32`
+   |                              ^^^ expected `String`, found `i32`
+   |
+help: try using a conversion method
+   |
+LL |     let ref string: String = var.to_string();
+   |                                 ++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/conversion-methods.stderr b/tests/ui/typeck/conversion-methods.stderr
index a9b5078ccdd..fa8928f1454 100644
--- a/tests/ui/typeck/conversion-methods.stderr
+++ b/tests/ui/typeck/conversion-methods.stderr
@@ -2,28 +2,40 @@ error[E0308]: mismatched types
   --> $DIR/conversion-methods.rs:5:41
    |
 LL |     let _tis_an_instants_play: String = "'Tis a fond Ambush—";
-   |                                ------   ^^^^^^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
-   |                                |        |
-   |                                |        expected `String`, found `&str`
+   |                                ------   ^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `&str`
+   |                                |
    |                                expected due to this
+   |
+help: try using a conversion method
+   |
+LL |     let _tis_an_instants_play: String = "'Tis a fond Ambush—".to_string();
+   |                                                              ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/conversion-methods.rs:6:40
    |
 LL |     let _just_to_make_bliss: PathBuf = Path::new("/ern/her/own/surprise");
-   |                              -------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_path_buf()`
-   |                              |         |
-   |                              |         expected `PathBuf`, found `&Path`
+   |                              -------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `PathBuf`, found `&Path`
+   |                              |
    |                              expected due to this
+   |
+help: try using a conversion method
+   |
+LL |     let _just_to_make_bliss: PathBuf = Path::new("/ern/her/own/surprise").to_path_buf();
+   |                                                                          ++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/conversion-methods.rs:9:40
    |
 LL |     let _but_should_the_play: String = 2; // Perhaps surprisingly, we suggest .to_string() here
-   |                               ------   ^- help: try using a conversion method: `.to_string()`
-   |                               |        |
-   |                               |        expected `String`, found integer
+   |                               ------   ^ expected `String`, found integer
+   |                               |
    |                               expected due to this
+   |
+help: try using a conversion method
+   |
+LL |     let _but_should_the_play: String = 2.to_string(); // Perhaps surprisingly, we suggest .to_string() here
+   |                                         ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/conversion-methods.rs:12:47