From b19b5be58c30156f22aca3e6c519984651750451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Jun 2023 19:17:32 +0000 Subject: [PATCH] In `<&NotClone as Clone>::clone()` call, account for bindings Address #112857: ``` 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; | ``` --- .../src/fn_ctxt/suggestions.rs | 27 +++++++++++- tests/ui/typeck/explain_clone_autoref.rs | 18 ++++++++ tests/ui/typeck/explain_clone_autoref.stderr | 41 ++++++++++++++++++- 3 files changed, 84 insertions(+), 2 deletions(-) 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`.