On E0308 caused by cloning a reference due to missing bounds, account for derive

On type errors where the difference is expecting an owned type and getting a reference, if the expression is a `.clone()` call and the type is annotated with `#[derive(Clone)]`, we now explain implicit bounds and suggest manually implementing `Clone`.

```
error[E0308]: mismatched types
  --> $DIR/derive-implicit-bound-on-clone.rs:10:5
   |
LL | fn clone_me<T, K>(x: &ContainsRc<T, K>) -> ContainsRc<T, K> {
   |                                            ---------------- expected `ContainsRc<T, K>` because of return type
LL |     x.clone()
   |     ^^^^^^^^^ expected `ContainsRc<T, K>`, found `&ContainsRc<T, K>`
   |
   = note: expected struct `ContainsRc<_, _>`
           found reference `&ContainsRc<_, _>`
note: `ContainsRc<T, K>` does not implement `Clone`, so `&ContainsRc<T, K>` was cloned instead
  --> $DIR/derive-implicit-bound-on-clone.rs:10:5
   |
LL |     x.clone()
   |     ^
help: `Clone` is not implemented because the some trait bounds could not be satisfied
  --> $DIR/derive-implicit-bound-on-clone.rs:5:19
   |
LL | #[derive(Clone)]
   |          ----- in this derive macro expansion
LL | struct ContainsRc<T, K> {
   |                   ^  ^ derive introduces an implicit unsatisfied trait bound `K: Clone`
   |                   |
   |                   derive introduces an implicit unsatisfied trait bound `T: Clone`
   = help: consider manually implementing `Clone` to avoid the implict type parameter bounds
```
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 3e4c194..285288e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1932,25 +1932,96 @@ pub(crate) fn note_type_is_not_clone(
                     None,
                 );
             } else {
+                let mut suggest_derive = true;
                 if let Some(errors) =
                     self.type_implements_trait_shallow(clone_trait_did, expected_ty, self.param_env)
                 {
+                    let manually_impl = "consider manually implementing `Clone` to avoid the \
+                        implict type parameter bounds";
                     match &errors[..] {
                         [] => {}
                         [error] => {
-                            diag.help(format!(
-                                "`Clone` is not implemented because the trait bound `{}` is \
-                                 not satisfied",
-                                error.obligation.predicate,
-                            ));
+                            // diag.note("{error:#?}");
+                            // diag.note(format!("{:#?} {:#?} {:#?}", error.obligation, error.obligation.cause, error.obligation.cause.code()));
+                            let msg = "`Clone` is not implemented because a trait bound is not \
+                                satisfied";
+                            if let traits::ObligationCauseCode::ImplDerived(data) =
+                                error.obligation.cause.code()
+                            {
+                                let mut span: MultiSpan = data.span.into();
+                                if self.tcx.is_automatically_derived(data.impl_or_alias_def_id) {
+                                    span.push_span_label(
+                                        data.span,
+                                        format!(
+                                            "derive introduces an implicit `{}` bound",
+                                            error.obligation.predicate
+                                        ),
+                                    );
+                                }
+                                diag.span_help(span, msg);
+                                if self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
+                                    && data.impl_or_alias_def_id.is_local()
+                                {
+                                    diag.help(manually_impl);
+                                    suggest_derive = false;
+                                }
+                            } else {
+                                diag.help(msg);
+                            }
                         }
                         _ => {
-                            diag.help(format!(
-                                "`Clone` is not implemented because the following trait bounds \
-                                 could not be satisfied: {}",
-                                listify(&errors, |e| format!("`{}`", e.obligation.predicate))
-                                    .unwrap(),
-                            ));
+                            let unsatisfied_bounds: Vec<_> = errors
+                                .iter()
+                                .filter_map(|error| match error.obligation.cause.code() {
+                                    traits::ObligationCauseCode::ImplDerived(data) => {
+                                        let pre = if self
+                                            .tcx
+                                            .is_automatically_derived(data.impl_or_alias_def_id)
+                                        {
+                                            "derive introduces an implicit "
+                                        } else {
+                                            ""
+                                        };
+                                        Some((
+                                            data.span,
+                                            format!(
+                                                "{pre}unsatisfied trait bound `{}`",
+                                                error.obligation.predicate
+                                            ),
+                                        ))
+                                    }
+                                    _ => None,
+                                })
+                                .collect();
+                            let msg = "`Clone` is not implemented because the some trait bounds \
+                                could not be satisfied";
+                            if errors.len() == unsatisfied_bounds.len() {
+                                let mut unsatisfied_bounds_spans: MultiSpan = unsatisfied_bounds
+                                    .iter()
+                                    .map(|(span, _)| *span)
+                                    .collect::<Vec<Span>>()
+                                    .into();
+                                for (span, label) in unsatisfied_bounds {
+                                    unsatisfied_bounds_spans.push_span_label(span, label);
+                                }
+                                diag.span_help(unsatisfied_bounds_spans, msg);
+                                if errors.iter().all(|error| match error.obligation.cause.code() {
+                                    traits::ObligationCauseCode::ImplDerived(data) => {
+                                        self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
+                                            && data.impl_or_alias_def_id.is_local()
+                                    }
+                                    _ => false,
+                                }) {
+                                    diag.help(manually_impl);
+                                    suggest_derive = false;
+                                }
+                            } else {
+                                diag.help(format!(
+                                    "{msg}: {}",
+                                    listify(&errors, |e| format!("`{}`", e.obligation.predicate))
+                                        .unwrap(),
+                                ));
+                            }
                         }
                     }
                     for error in errors {
@@ -1968,7 +2039,9 @@ pub(crate) fn note_type_is_not_clone(
                         }
                     }
                 }
-                self.suggest_derive(diag, &vec![(trait_ref.upcast(self.tcx), None, None)]);
+                if suggest_derive {
+                    self.suggest_derive(diag, &vec![(trait_ref.upcast(self.tcx), None, None)]);
+                }
             }
         }
     }
diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr
index 301f3c3..5de99cc 100644
--- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr
+++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr
@@ -13,7 +13,8 @@
    |
 LL |             let mut x: HashSet<Day> = v.clone();
    |                                       ^
-   = help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied
+help: `Clone` is not implemented because a trait bound is not satisfied
+  --> $SRC_DIR/std/src/collections/hash/set.rs:LL:COL
 help: consider annotating `Day` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr
index 301f3c3..5de99cc 100644
--- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr
+++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr
@@ -13,7 +13,8 @@
    |
 LL |             let mut x: HashSet<Day> = v.clone();
    |                                       ^
-   = help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied
+help: `Clone` is not implemented because a trait bound is not satisfied
+  --> $SRC_DIR/std/src/collections/hash/set.rs:LL:COL
 help: consider annotating `Day` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/traits/derive-implicit-bound-on-clone.rs b/tests/ui/traits/derive-implicit-bound-on-clone.rs
new file mode 100644
index 0000000..a4c9e88
--- /dev/null
+++ b/tests/ui/traits/derive-implicit-bound-on-clone.rs
@@ -0,0 +1,24 @@
+// Issue #146515
+use std::rc::Rc;
+
+#[derive(Clone)]
+struct ContainsRc<T, K> { //~ HELP `Clone` is not implemented
+    value: Rc<(T, K)>,
+}
+
+fn clone_me<T, K>(x: &ContainsRc<T, K>) -> ContainsRc<T, K> {
+    x.clone() //~ ERROR E0308
+    //~^ HELP consider manually implementing `Clone`
+}
+
+#[derive(Clone)]
+struct ContainsRcSingle<T> { //~ HELP `Clone` is not implemented
+    value: Rc<T>,
+}
+
+fn clone_me_single<T>(x: &ContainsRcSingle<T>) -> ContainsRcSingle<T> {
+    x.clone() //~ ERROR E0308
+    //~^ HELP consider manually implementing `Clone`
+}
+
+fn main() {}
diff --git a/tests/ui/traits/derive-implicit-bound-on-clone.stderr b/tests/ui/traits/derive-implicit-bound-on-clone.stderr
new file mode 100644
index 0000000..0cec4ef
--- /dev/null
+++ b/tests/ui/traits/derive-implicit-bound-on-clone.stderr
@@ -0,0 +1,53 @@
+error[E0308]: mismatched types
+  --> $DIR/derive-implicit-bound-on-clone.rs:10:5
+   |
+LL | fn clone_me<T, K>(x: &ContainsRc<T, K>) -> ContainsRc<T, K> {
+   |                                            ---------------- expected `ContainsRc<T, K>` because of return type
+LL |     x.clone()
+   |     ^^^^^^^^^ expected `ContainsRc<T, K>`, found `&ContainsRc<T, K>`
+   |
+   = note: expected struct `ContainsRc<_, _>`
+           found reference `&ContainsRc<_, _>`
+note: `ContainsRc<T, K>` does not implement `Clone`, so `&ContainsRc<T, K>` was cloned instead
+  --> $DIR/derive-implicit-bound-on-clone.rs:10:5
+   |
+LL |     x.clone()
+   |     ^
+help: `Clone` is not implemented because the some trait bounds could not be satisfied
+  --> $DIR/derive-implicit-bound-on-clone.rs:5:19
+   |
+LL | #[derive(Clone)]
+   |          ----- in this derive macro expansion
+LL | struct ContainsRc<T, K> {
+   |                   ^  ^ derive introduces an implicit unsatisfied trait bound `K: Clone`
+   |                   |
+   |                   derive introduces an implicit unsatisfied trait bound `T: Clone`
+   = help: consider manually implementing `Clone` to avoid the implict type parameter bounds
+
+error[E0308]: mismatched types
+  --> $DIR/derive-implicit-bound-on-clone.rs:20:5
+   |
+LL | fn clone_me_single<T>(x: &ContainsRcSingle<T>) -> ContainsRcSingle<T> {
+   |                                                   ------------------- expected `ContainsRcSingle<T>` because of return type
+LL |     x.clone()
+   |     ^^^^^^^^^ expected `ContainsRcSingle<T>`, found `&ContainsRcSingle<T>`
+   |
+   = note: expected struct `ContainsRcSingle<_>`
+           found reference `&ContainsRcSingle<_>`
+note: `ContainsRcSingle<T>` does not implement `Clone`, so `&ContainsRcSingle<T>` was cloned instead
+  --> $DIR/derive-implicit-bound-on-clone.rs:20:5
+   |
+LL |     x.clone()
+   |     ^
+help: `Clone` is not implemented because a trait bound is not satisfied
+  --> $DIR/derive-implicit-bound-on-clone.rs:15:25
+   |
+LL | #[derive(Clone)]
+   |          ----- in this derive macro expansion
+LL | struct ContainsRcSingle<T> {
+   |                         ^ derive introduces an implicit `T: Clone` bound
+   = help: consider manually implementing `Clone` to avoid the implict type parameter bounds
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.