diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 3a4fe334f888a..c3dc68a160b80 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1494,7 +1494,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found_ty: Ty<'tcx>, expr: &hir::Expr<'_>, ) { - let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; }; + let (segment, callee_expr, expr) = match expr.kind { + // When `expr` is `foo.clone()`, get `foo` and `clone`. + hir::ExprKind::MethodCall(segment, callee_expr, &[], _) => (segment, callee_expr, expr), + // When `expr` is `x` in `let x = foo.clone(); x`, get `foo` and `clone`. + hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { segments: [_], res: crate::Res::Local(binding), .. }, + )) => { + let Some(hir::Node::Pat( + hir::Pat { hir_id, kind: hir::PatKind::Binding(_, _, _, _), .. } + )) = self.tcx.hir().find(*binding) else { + return; + }; + let parent = self.tcx.hir().parent_id(*hir_id); + let Some(hir::Node::Local( + hir::Local { init: Some(init), .. } + )) = self.tcx.hir().find(parent) else { + return; + }; + let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = init.kind else { + return; + }; + (segment, callee_expr, *init) + } + _ => return, + }; let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; }; let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return }; let results = self.typeck_results.borrow(); diff --git a/tests/ui/typeck/explain_clone_autoref.rs b/tests/ui/typeck/explain_clone_autoref.rs index 4d21574700ad9..84ef4eb154cc5 100644 --- a/tests/ui/typeck/explain_clone_autoref.rs +++ b/tests/ui/typeck/explain_clone_autoref.rs @@ -11,3 +11,21 @@ fn clone_thing(nc: &NotClone) -> NotClone { //~| NOTE `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead //~| NOTE expected `NotClone`, found `&NotClone` } + +fn clone_thing2(nc: &NotClone) -> NotClone { + let nc: NotClone = nc.clone(); + //~^ ERROR mismatched type + //~| NOTE expected due to this + //~| NOTE `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead + //~| NOTE expected `NotClone`, found `&NotClone` + nc +} + +fn clone_thing3(nc: &NotClone) -> NotClone { + //~^ NOTE expected `NotClone` because of return type + let nc = nc.clone(); + //~^ NOTE `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead + nc + //~^ ERROR mismatched type + //~| NOTE expected `NotClone`, found `&NotClone` +} \ No newline at end of file diff --git a/tests/ui/typeck/explain_clone_autoref.stderr b/tests/ui/typeck/explain_clone_autoref.stderr index 38cb7fe551841..22b5c27134c8c 100644 --- a/tests/ui/typeck/explain_clone_autoref.stderr +++ b/tests/ui/typeck/explain_clone_autoref.stderr @@ -18,6 +18,45 @@ LL + #[derive(Clone)] LL | struct NotClone; | -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/explain_clone_autoref.rs:16:24 + | +LL | let nc: NotClone = nc.clone(); + | -------- ^^^^^^^^^^ expected `NotClone`, found `&NotClone` + | | + | expected due to this + | +note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead + --> $DIR/explain_clone_autoref.rs:16:24 + | +LL | let nc: NotClone = nc.clone(); + | ^^ +help: consider annotating `NotClone` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct NotClone; + | + +error[E0308]: mismatched types + --> $DIR/explain_clone_autoref.rs:28:5 + | +LL | fn clone_thing3(nc: &NotClone) -> NotClone { + | -------- expected `NotClone` because of return type +... +LL | nc + | ^^ expected `NotClone`, found `&NotClone` + | +note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead + --> $DIR/explain_clone_autoref.rs:26:14 + | +LL | let nc = nc.clone(); + | ^^ +help: consider annotating `NotClone` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct NotClone; + | + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`.