On "this .clone() is on the reference", provide more info
When encountering a case where `let x: T = (val: &T).clone();` and `T: !Clone`, already mention that the reference is being cloned. We now also suggest `#[derive(Clone)]` not only on `T` but also on type parameters to satisfy blanket implementations. ``` error[E0308]: mismatched types --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:17:39 | LL | let mut x: HashSet<Day> = v.clone(); | ------------ ^^^^^^^^^ expected `HashSet<Day>`, found `&HashSet<Day>` | | | expected due to this | = note: expected struct `HashSet<Day>` found reference `&HashSet<Day>` note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` was cloned instead --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:17:39 | LL | let mut x: HashSet<Day> = v.clone(); | ^ = help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied help: consider annotating `Day` with `#[derive(Clone)]` | LL + #[derive(Clone)] LL | enum Day { | ``` Case taken from # #41825.
This commit is contained in:
parent
1c69c6ab08
commit
a754fcaa43
4 changed files with 158 additions and 1 deletions
|
@ -21,7 +21,7 @@ use rustc_hir::{
|
||||||
StmtKind, TyKind, WherePredicate,
|
StmtKind, TyKind, WherePredicate,
|
||||||
};
|
};
|
||||||
use rustc_hir_analysis::astconv::AstConv;
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
use rustc_infer::traits::{self, StatementAsExpression};
|
use rustc_infer::traits::{self, StatementAsExpression, TraitEngineExt};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::middle::stability::EvalResult;
|
use rustc_middle::middle::stability::EvalResult;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
|
@ -34,6 +34,7 @@ use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
use rustc_trait_selection::solve::FulfillmentCtxt;
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
||||||
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
|
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||||
|
@ -1619,6 +1620,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
self.infcx.probe(|_snapshot| {
|
||||||
|
if let ty::Adt(def, args) = expected_ty.kind()
|
||||||
|
&& let Some((def_id, _imp)) = self
|
||||||
|
.tcx
|
||||||
|
.all_impls(clone_trait_did)
|
||||||
|
.filter_map(|def_id| {
|
||||||
|
self.tcx.impl_trait_ref(def_id).map(|r| (def_id, r))
|
||||||
|
})
|
||||||
|
.map(|(def_id, imp)| (def_id, imp.skip_binder()))
|
||||||
|
.filter(|(_, imp)| match imp.self_ty().peel_refs().kind() {
|
||||||
|
ty::Adt(i_def, _) if i_def.did() == def.did() => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
{
|
||||||
|
let mut fulfill_cx = FulfillmentCtxt::new(&self.infcx);
|
||||||
|
// We get all obligations from the impl to talk about specific
|
||||||
|
// trait bounds.
|
||||||
|
let obligations = self
|
||||||
|
.tcx
|
||||||
|
.predicates_of(def_id)
|
||||||
|
.instantiate(self.tcx, args)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(clause, span)| {
|
||||||
|
traits::Obligation::new(
|
||||||
|
self.tcx,
|
||||||
|
traits::ObligationCause::misc(span, self.body_id),
|
||||||
|
self.param_env,
|
||||||
|
clause,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
fulfill_cx.register_predicate_obligations(&self.infcx, obligations);
|
||||||
|
let errors = fulfill_cx.select_all_or_error(&self.infcx);
|
||||||
|
match &errors[..] {
|
||||||
|
[] => {}
|
||||||
|
[error] => {
|
||||||
|
diag.help(format!(
|
||||||
|
"`Clone` is not implemented because the trait bound `{}` is \
|
||||||
|
not satisfied",
|
||||||
|
error.obligation.predicate,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
[errors @ .., last] => {
|
||||||
|
diag.help(format!(
|
||||||
|
"`Clone` is not implemented because the following trait bounds \
|
||||||
|
could not be satisfied: {} and `{}`",
|
||||||
|
errors
|
||||||
|
.iter()
|
||||||
|
.map(|e| format!("`{}`", e.obligation.predicate))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
last.obligation.predicate,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for error in errors {
|
||||||
|
if let traits::FulfillmentErrorCode::CodeSelectionError(
|
||||||
|
traits::SelectionError::Unimplemented,
|
||||||
|
) = error.code
|
||||||
|
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
|
||||||
|
error.obligation.predicate.kind().skip_binder()
|
||||||
|
{
|
||||||
|
self.infcx.err_ctxt().suggest_derive(
|
||||||
|
&error.obligation,
|
||||||
|
diag,
|
||||||
|
error.obligation.predicate.kind().rebind(pred),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
|
self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![allow(unused_variables, dead_code)]
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
#[derive(Debug,Eq,PartialEq,Hash)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum Day {
|
||||||
|
Mon,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Class {
|
||||||
|
days: BTreeMap<u32, HashSet<Day>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Class {
|
||||||
|
fn do_stuff(&self) {
|
||||||
|
for (_, v) in &self.days {
|
||||||
|
let mut x: HashSet<Day> = v.clone(); //~ ERROR
|
||||||
|
let y: Vec<Day> = x.drain().collect();
|
||||||
|
println!("{:?}", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fail() {
|
||||||
|
let c = Class { days: BTreeMap::new() };
|
||||||
|
c.do_stuff();
|
||||||
|
}
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![allow(unused_variables, dead_code)]
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
#[derive(Debug,Eq,PartialEq,Hash)]
|
||||||
|
enum Day {
|
||||||
|
Mon,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Class {
|
||||||
|
days: BTreeMap<u32, HashSet<Day>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Class {
|
||||||
|
fn do_stuff(&self) {
|
||||||
|
for (_, v) in &self.days {
|
||||||
|
let mut x: HashSet<Day> = v.clone(); //~ ERROR
|
||||||
|
let y: Vec<Day> = x.drain().collect();
|
||||||
|
println!("{:?}", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fail() {
|
||||||
|
let c = Class { days: BTreeMap::new() };
|
||||||
|
c.do_stuff();
|
||||||
|
}
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,25 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:18:39
|
||||||
|
|
|
||||||
|
LL | let mut x: HashSet<Day> = v.clone();
|
||||||
|
| ------------ ^^^^^^^^^ expected `HashSet<Day>`, found `&HashSet<Day>`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected struct `HashSet<Day>`
|
||||||
|
found reference `&HashSet<Day>`
|
||||||
|
note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` was cloned instead
|
||||||
|
--> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:18:39
|
||||||
|
|
|
||||||
|
LL | let mut x: HashSet<Day> = v.clone();
|
||||||
|
| ^
|
||||||
|
= help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied
|
||||||
|
help: consider annotating `Day` with `#[derive(Clone)]`
|
||||||
|
|
|
||||||
|
LL + #[derive(Clone)]
|
||||||
|
LL | enum Day {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue