Rollup merge of #105679 - estebank:suggest-clone, r=compiler-errors

Suggest constraining type parameter with `Clone`

Fix #34896.
This commit is contained in:
Matthias Krüger 2022-12-15 22:02:58 +01:00 committed by GitHub
commit 86cedb4062
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 6 deletions

View file

@ -13,7 +13,9 @@ use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, Ty};
use rustc_middle::ty::{
self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
@ -1276,15 +1278,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
&& let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
// And the expected type doesn't implement `Clone`
&& !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
self.tcx,
traits::ObligationCause::dummy(),
self.param_env,
ty::Binder::dummy(self.tcx.mk_trait_ref(
clone_trait_did,
[expected_ty],
)),
trait_ref,
))
{
diag.span_note(
@ -1293,6 +1293,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
),
);
let owner = self.tcx.hir().enclosing_body_owner(expr.hir_id);
if let ty::Param(param) = expected_ty.kind()
&& let Some(generics) = self.tcx.hir().get_generics(owner)
{
suggest_constraining_type_params(
self.tcx,
generics,
diag,
vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
);
} else {
self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
}
}
}

View file

@ -1852,7 +1852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_derive(err, &preds);
}
fn suggest_derive(
pub fn suggest_derive(
&self,
err: &mut Diagnostic,
unsatisfied_predicates: &[(

View file

@ -0,0 +1,16 @@
// run-rustfix
fn wat<T: Clone>(t: &T) -> T {
t.clone() //~ ERROR E0308
}
#[derive(Clone)]
struct Foo;
fn wut(t: &Foo) -> Foo {
t.clone() //~ ERROR E0308
}
fn main() {
wat(&42);
wut(&Foo);
}

View file

@ -0,0 +1,15 @@
// run-rustfix
fn wat<T>(t: &T) -> T {
t.clone() //~ ERROR E0308
}
struct Foo;
fn wut(t: &Foo) -> Foo {
t.clone() //~ ERROR E0308
}
fn main() {
wat(&42);
wut(&Foo);
}

View file

@ -0,0 +1,43 @@
error[E0308]: mismatched types
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
|
LL | fn wat<T>(t: &T) -> T {
| - - expected `T` because of return type
| |
| this type parameter
LL | t.clone()
| ^^^^^^^^^ expected type parameter `T`, found `&T`
|
= note: expected type parameter `T`
found reference `&T`
note: `T` does not implement `Clone`, so `&T` was cloned instead
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
|
LL | t.clone()
| ^
help: consider restricting type parameter `T`
|
LL | fn wat<T: Clone>(t: &T) -> T {
| +++++++
error[E0308]: mismatched types
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
|
LL | fn wut(t: &Foo) -> Foo {
| --- expected `Foo` because of return type
LL | t.clone()
| ^^^^^^^^^ expected struct `Foo`, found `&Foo`
|
note: `Foo` does not implement `Clone`, so `&Foo` was cloned instead
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
|
LL | t.clone()
| ^
help: consider annotating `Foo` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -12,6 +12,10 @@ note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
|
LL | nc.clone()
| ^^
help: consider annotating `NotClone` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error: aborting due to previous error