From e1b340195a04bc079df3bda8e627ad6e64938d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Dec 2022 19:52:42 -0800 Subject: [PATCH] Suggest `#[derive(Clone)]` --- .../src/fn_ctxt/suggestions.rs | 10 +++++----- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- ...on-unconstrained-borrowed-type-param.fixed | 8 ++++++++ ...ne-on-unconstrained-borrowed-type-param.rs | 7 +++++++ ...n-unconstrained-borrowed-type-param.stderr | 20 ++++++++++++++++++- .../ui/typeck/explain_clone_autoref.stderr | 4 ++++ 6 files changed, 44 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 08ef2484776b..407d6ac8544c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -14,7 +14,7 @@ use rustc_infer::infer; use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{ - self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, Ty, + self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::symbol::sym; @@ -1278,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( @@ -1305,6 +1303,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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)]); } } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 5c0d5f32f0fd..6b3cc26fd761 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1848,7 +1848,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: &[( diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed index 3e5ded6738b3..4f9e93a47ed1 100644 --- a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed +++ b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed @@ -3,6 +3,14 @@ fn wat(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); } diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs index 1a5a38369ec5..89b077d671a5 100644 --- a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs +++ b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs @@ -3,6 +3,13 @@ fn wat(t: &T) -> T { t.clone() //~ ERROR E0308 } +struct Foo; + +fn wut(t: &Foo) -> Foo { + t.clone() //~ ERROR E0308 +} + fn main() { wat(&42); + wut(&Foo); } diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr index 01246955fae8..26ab515d9b4b 100644 --- a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr +++ b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr @@ -20,6 +20,24 @@ help: consider restricting type parameter `T` LL | fn wat(t: &T) -> T { | +++++++ -error: aborting due to previous error +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`. diff --git a/src/test/ui/typeck/explain_clone_autoref.stderr b/src/test/ui/typeck/explain_clone_autoref.stderr index faac680ea193..ff36e18d2830 100644 --- a/src/test/ui/typeck/explain_clone_autoref.stderr +++ b/src/test/ui/typeck/explain_clone_autoref.stderr @@ -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