Skip to content

Commit 62b1646

Browse files
authored
Rollup merge of rust-lang#105679 - estebank:suggest-clone, r=compiler-errors
Suggest constraining type parameter with `Clone` Fix rust-lang#34896.
2 parents 567d887 + 0fb8d84 commit 62b1646

6 files changed

+102
-8
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use rustc_hir_analysis::astconv::AstConv;
1313
use rustc_infer::infer;
1414
use rustc_infer::traits::{self, StatementAsExpression};
1515
use rustc_middle::lint::in_external_macro;
16-
use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
16+
use rustc_middle::ty::{
17+
self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
18+
};
1719
use rustc_session::errors::ExprParenthesesNeeded;
1820
use rustc_span::symbol::sym;
1921
use rustc_span::Span;
@@ -1276,17 +1278,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12761278
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
12771279
// Check that we're in fact trying to clone into the expected type
12781280
&& self.can_coerce(*pointee_ty, expected_ty)
1281+
&& let predicate = ty::Binder::dummy(ty::TraitRef {
1282+
def_id: clone_trait_did,
1283+
substs: self.tcx.mk_substs([expected_ty.into()].iter()),
1284+
})
1285+
.without_const()
1286+
.to_predicate(self.tcx)
12791287
// And the expected type doesn't implement `Clone`
12801288
&& !self.predicate_must_hold_considering_regions(&traits::Obligation {
12811289
cause: traits::ObligationCause::dummy(),
12821290
param_env: self.param_env,
12831291
recursion_depth: 0,
1284-
predicate: ty::Binder::dummy(ty::TraitRef {
1285-
def_id: clone_trait_did,
1286-
substs: self.tcx.mk_substs([expected_ty.into()].iter()),
1287-
})
1288-
.without_const()
1289-
.to_predicate(self.tcx),
1292+
predicate,
12901293
})
12911294
{
12921295
diag.span_note(
@@ -1295,6 +1298,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12951298
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
12961299
),
12971300
);
1301+
let owner = self.tcx.hir().enclosing_body_owner(expr.hir_id);
1302+
if let ty::Param(param) = expected_ty.kind()
1303+
&& let Some(generics) = self.tcx.hir().get_generics(owner)
1304+
{
1305+
suggest_constraining_type_params(
1306+
self.tcx,
1307+
generics,
1308+
diag,
1309+
vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
1310+
);
1311+
} else {
1312+
self.suggest_derive(diag, &[(predicate, None, None)]);
1313+
}
12981314
}
12991315
}
13001316

compiler/rustc_hir_typeck/src/method/suggest.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1853,7 +1853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18531853
self.suggest_derive(err, &preds);
18541854
}
18551855

1856-
fn suggest_derive(
1856+
pub fn suggest_derive(
18571857
&self,
18581858
err: &mut Diagnostic,
18591859
unsatisfied_predicates: &[(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-rustfix
2+
fn wat<T: Clone>(t: &T) -> T {
3+
t.clone() //~ ERROR E0308
4+
}
5+
6+
#[derive(Clone)]
7+
struct Foo;
8+
9+
fn wut(t: &Foo) -> Foo {
10+
t.clone() //~ ERROR E0308
11+
}
12+
13+
fn main() {
14+
wat(&42);
15+
wut(&Foo);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
fn wat<T>(t: &T) -> T {
3+
t.clone() //~ ERROR E0308
4+
}
5+
6+
struct Foo;
7+
8+
fn wut(t: &Foo) -> Foo {
9+
t.clone() //~ ERROR E0308
10+
}
11+
12+
fn main() {
13+
wat(&42);
14+
wut(&Foo);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
3+
|
4+
LL | fn wat<T>(t: &T) -> T {
5+
| - - expected `T` because of return type
6+
| |
7+
| this type parameter
8+
LL | t.clone()
9+
| ^^^^^^^^^ expected type parameter `T`, found `&T`
10+
|
11+
= note: expected type parameter `T`
12+
found reference `&T`
13+
note: `T` does not implement `Clone`, so `&T` was cloned instead
14+
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
15+
|
16+
LL | t.clone()
17+
| ^
18+
help: consider restricting type parameter `T`
19+
|
20+
LL | fn wat<T: Clone>(t: &T) -> T {
21+
| +++++++
22+
23+
error[E0308]: mismatched types
24+
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
25+
|
26+
LL | fn wut(t: &Foo) -> Foo {
27+
| --- expected `Foo` because of return type
28+
LL | t.clone()
29+
| ^^^^^^^^^ expected struct `Foo`, found `&Foo`
30+
|
31+
note: `Foo` does not implement `Clone`, so `&Foo` was cloned instead
32+
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
33+
|
34+
LL | t.clone()
35+
| ^
36+
help: consider annotating `Foo` with `#[derive(Clone)]`
37+
|
38+
LL | #[derive(Clone)]
39+
|
40+
41+
error: aborting due to 2 previous errors
42+
43+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/typeck/explain_clone_autoref.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
1212
|
1313
LL | nc.clone()
1414
| ^^
15+
help: consider annotating `NotClone` with `#[derive(Clone)]`
16+
|
17+
LL | #[derive(Clone)]
18+
|
1519

1620
error: aborting due to previous error
1721

0 commit comments

Comments
 (0)