Skip to content

Commit b19b5be

Browse files
committed
In <&NotClone as Clone>::clone() call, account for bindings
Address rust-lang#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; | ```
1 parent 54d6738 commit b19b5be

File tree

3 files changed

+84
-2
lines changed

3 files changed

+84
-2
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14941494
found_ty: Ty<'tcx>,
14951495
expr: &hir::Expr<'_>,
14961496
) {
1497-
let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; };
1497+
let (segment, callee_expr, expr) = match expr.kind {
1498+
// When `expr` is `foo.clone()`, get `foo` and `clone`.
1499+
hir::ExprKind::MethodCall(segment, callee_expr, &[], _) => (segment, callee_expr, expr),
1500+
// When `expr` is `x` in `let x = foo.clone(); x`, get `foo` and `clone`.
1501+
hir::ExprKind::Path(hir::QPath::Resolved(
1502+
None,
1503+
hir::Path { segments: [_], res: crate::Res::Local(binding), .. },
1504+
)) => {
1505+
let Some(hir::Node::Pat(
1506+
hir::Pat { hir_id, kind: hir::PatKind::Binding(_, _, _, _), .. }
1507+
)) = self.tcx.hir().find(*binding) else {
1508+
return;
1509+
};
1510+
let parent = self.tcx.hir().parent_id(*hir_id);
1511+
let Some(hir::Node::Local(
1512+
hir::Local { init: Some(init), .. }
1513+
)) = self.tcx.hir().find(parent) else {
1514+
return;
1515+
};
1516+
let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = init.kind else {
1517+
return;
1518+
};
1519+
(segment, callee_expr, *init)
1520+
}
1521+
_ => return,
1522+
};
14981523
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
14991524
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
15001525
let results = self.typeck_results.borrow();

tests/ui/typeck/explain_clone_autoref.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,21 @@ fn clone_thing(nc: &NotClone) -> NotClone {
1111
//~| NOTE `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
1212
//~| NOTE expected `NotClone`, found `&NotClone`
1313
}
14+
15+
fn clone_thing2(nc: &NotClone) -> NotClone {
16+
let nc: NotClone = nc.clone();
17+
//~^ ERROR mismatched type
18+
//~| NOTE expected due to this
19+
//~| NOTE `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
20+
//~| NOTE expected `NotClone`, found `&NotClone`
21+
nc
22+
}
23+
24+
fn clone_thing3(nc: &NotClone) -> NotClone {
25+
//~^ NOTE expected `NotClone` because of return type
26+
let nc = nc.clone();
27+
//~^ NOTE `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
28+
nc
29+
//~^ ERROR mismatched type
30+
//~| NOTE expected `NotClone`, found `&NotClone`
31+
}

tests/ui/typeck/explain_clone_autoref.stderr

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,45 @@ LL + #[derive(Clone)]
1818
LL | struct NotClone;
1919
|
2020

21-
error: aborting due to previous error
21+
error[E0308]: mismatched types
22+
--> $DIR/explain_clone_autoref.rs:16:24
23+
|
24+
LL | let nc: NotClone = nc.clone();
25+
| -------- ^^^^^^^^^^ expected `NotClone`, found `&NotClone`
26+
| |
27+
| expected due to this
28+
|
29+
note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
30+
--> $DIR/explain_clone_autoref.rs:16:24
31+
|
32+
LL | let nc: NotClone = nc.clone();
33+
| ^^
34+
help: consider annotating `NotClone` with `#[derive(Clone)]`
35+
|
36+
LL + #[derive(Clone)]
37+
LL | struct NotClone;
38+
|
39+
40+
error[E0308]: mismatched types
41+
--> $DIR/explain_clone_autoref.rs:28:5
42+
|
43+
LL | fn clone_thing3(nc: &NotClone) -> NotClone {
44+
| -------- expected `NotClone` because of return type
45+
...
46+
LL | nc
47+
| ^^ expected `NotClone`, found `&NotClone`
48+
|
49+
note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
50+
--> $DIR/explain_clone_autoref.rs:26:14
51+
|
52+
LL | let nc = nc.clone();
53+
| ^^
54+
help: consider annotating `NotClone` with `#[derive(Clone)]`
55+
|
56+
LL + #[derive(Clone)]
57+
LL | struct NotClone;
58+
|
59+
60+
error: aborting due to 3 previous errors
2261

2362
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)