On E0308 caused by cloning a reference due to missing bounds, account for derive
On type errors where the difference is expecting an owned type and getting a reference, if the expression is a `.clone()` call and the type is annotated with `#[derive(Clone)]`, we now explain implicit bounds and suggest manually implementing `Clone`.
```
error[E0308]: mismatched types
--> $DIR/derive-implicit-bound-on-clone.rs:10:5
|
LL | fn clone_me<T, K>(x: &ContainsRc<T, K>) -> ContainsRc<T, K> {
| ---------------- expected `ContainsRc<T, K>` because of return type
LL | x.clone()
| ^^^^^^^^^ expected `ContainsRc<T, K>`, found `&ContainsRc<T, K>`
|
= note: expected struct `ContainsRc<_, _>`
found reference `&ContainsRc<_, _>`
note: `ContainsRc<T, K>` does not implement `Clone`, so `&ContainsRc<T, K>` was cloned instead
--> $DIR/derive-implicit-bound-on-clone.rs:10:5
|
LL | x.clone()
| ^
help: `Clone` is not implemented because the some trait bounds could not be satisfied
--> $DIR/derive-implicit-bound-on-clone.rs:5:19
|
LL | #[derive(Clone)]
| ----- in this derive macro expansion
LL | struct ContainsRc<T, K> {
| ^ ^ derive introduces an implicit unsatisfied trait bound `K: Clone`
| |
| derive introduces an implicit unsatisfied trait bound `T: Clone`
= help: consider manually implementing `Clone` to avoid the implict type parameter bounds
```
This commit is contained in:
parent
b88fb8a0b0
commit
085da0cee4
5 changed files with 166 additions and 14 deletions
|
|
@ -1932,25 +1932,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
None,
|
||||
);
|
||||
} else {
|
||||
let mut suggest_derive = true;
|
||||
if let Some(errors) =
|
||||
self.type_implements_trait_shallow(clone_trait_did, expected_ty, self.param_env)
|
||||
{
|
||||
let manually_impl = "consider manually implementing `Clone` to avoid the \
|
||||
implict type parameter bounds";
|
||||
match &errors[..] {
|
||||
[] => {}
|
||||
[error] => {
|
||||
diag.help(format!(
|
||||
"`Clone` is not implemented because the trait bound `{}` is \
|
||||
not satisfied",
|
||||
error.obligation.predicate,
|
||||
));
|
||||
// diag.note("{error:#?}");
|
||||
// diag.note(format!("{:#?} {:#?} {:#?}", error.obligation, error.obligation.cause, error.obligation.cause.code()));
|
||||
let msg = "`Clone` is not implemented because a trait bound is not \
|
||||
satisfied";
|
||||
if let traits::ObligationCauseCode::ImplDerived(data) =
|
||||
error.obligation.cause.code()
|
||||
{
|
||||
let mut span: MultiSpan = data.span.into();
|
||||
if self.tcx.is_automatically_derived(data.impl_or_alias_def_id) {
|
||||
span.push_span_label(
|
||||
data.span,
|
||||
format!(
|
||||
"derive introduces an implicit `{}` bound",
|
||||
error.obligation.predicate
|
||||
),
|
||||
);
|
||||
}
|
||||
diag.span_help(span, msg);
|
||||
if self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
|
||||
&& data.impl_or_alias_def_id.is_local()
|
||||
{
|
||||
diag.help(manually_impl);
|
||||
suggest_derive = false;
|
||||
}
|
||||
} else {
|
||||
diag.help(msg);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
diag.help(format!(
|
||||
"`Clone` is not implemented because the following trait bounds \
|
||||
could not be satisfied: {}",
|
||||
listify(&errors, |e| format!("`{}`", e.obligation.predicate))
|
||||
.unwrap(),
|
||||
));
|
||||
let unsatisfied_bounds: Vec<_> = errors
|
||||
.iter()
|
||||
.filter_map(|error| match error.obligation.cause.code() {
|
||||
traits::ObligationCauseCode::ImplDerived(data) => {
|
||||
let pre = if self
|
||||
.tcx
|
||||
.is_automatically_derived(data.impl_or_alias_def_id)
|
||||
{
|
||||
"derive introduces an implicit "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
Some((
|
||||
data.span,
|
||||
format!(
|
||||
"{pre}unsatisfied trait bound `{}`",
|
||||
error.obligation.predicate
|
||||
),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let msg = "`Clone` is not implemented because the some trait bounds \
|
||||
could not be satisfied";
|
||||
if errors.len() == unsatisfied_bounds.len() {
|
||||
let mut unsatisfied_bounds_spans: MultiSpan = unsatisfied_bounds
|
||||
.iter()
|
||||
.map(|(span, _)| *span)
|
||||
.collect::<Vec<Span>>()
|
||||
.into();
|
||||
for (span, label) in unsatisfied_bounds {
|
||||
unsatisfied_bounds_spans.push_span_label(span, label);
|
||||
}
|
||||
diag.span_help(unsatisfied_bounds_spans, msg);
|
||||
if errors.iter().all(|error| match error.obligation.cause.code() {
|
||||
traits::ObligationCauseCode::ImplDerived(data) => {
|
||||
self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
|
||||
&& data.impl_or_alias_def_id.is_local()
|
||||
}
|
||||
_ => false,
|
||||
}) {
|
||||
diag.help(manually_impl);
|
||||
suggest_derive = false;
|
||||
}
|
||||
} else {
|
||||
diag.help(format!(
|
||||
"{msg}: {}",
|
||||
listify(&errors, |e| format!("`{}`", e.obligation.predicate))
|
||||
.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
for error in errors {
|
||||
|
|
@ -1968,7 +2039,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.suggest_derive(diag, &vec![(trait_ref.upcast(self.tcx), None, None)]);
|
||||
if suggest_derive {
|
||||
self.suggest_derive(diag, &vec![(trait_ref.upcast(self.tcx), None, None)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` was cloned i
|
|||
|
|
||||
LL | let mut x: HashSet<Day> = v.clone();
|
||||
| ^
|
||||
= help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied
|
||||
help: `Clone` is not implemented because a trait bound is not satisfied
|
||||
--> $SRC_DIR/std/src/collections/hash/set.rs:LL:COL
|
||||
help: consider annotating `Day` with `#[derive(Clone)]`
|
||||
|
|
||||
LL + #[derive(Clone)]
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` was cloned i
|
|||
|
|
||||
LL | let mut x: HashSet<Day> = v.clone();
|
||||
| ^
|
||||
= help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied
|
||||
help: `Clone` is not implemented because a trait bound is not satisfied
|
||||
--> $SRC_DIR/std/src/collections/hash/set.rs:LL:COL
|
||||
help: consider annotating `Day` with `#[derive(Clone)]`
|
||||
|
|
||||
LL + #[derive(Clone)]
|
||||
|
|
|
|||
24
tests/ui/traits/derive-implicit-bound-on-clone.rs
Normal file
24
tests/ui/traits/derive-implicit-bound-on-clone.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Issue #146515
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ContainsRc<T, K> { //~ HELP `Clone` is not implemented
|
||||
value: Rc<(T, K)>,
|
||||
}
|
||||
|
||||
fn clone_me<T, K>(x: &ContainsRc<T, K>) -> ContainsRc<T, K> {
|
||||
x.clone() //~ ERROR E0308
|
||||
//~^ HELP consider manually implementing `Clone`
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ContainsRcSingle<T> { //~ HELP `Clone` is not implemented
|
||||
value: Rc<T>,
|
||||
}
|
||||
|
||||
fn clone_me_single<T>(x: &ContainsRcSingle<T>) -> ContainsRcSingle<T> {
|
||||
x.clone() //~ ERROR E0308
|
||||
//~^ HELP consider manually implementing `Clone`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
53
tests/ui/traits/derive-implicit-bound-on-clone.stderr
Normal file
53
tests/ui/traits/derive-implicit-bound-on-clone.stderr
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/derive-implicit-bound-on-clone.rs:10:5
|
||||
|
|
||||
LL | fn clone_me<T, K>(x: &ContainsRc<T, K>) -> ContainsRc<T, K> {
|
||||
| ---------------- expected `ContainsRc<T, K>` because of return type
|
||||
LL | x.clone()
|
||||
| ^^^^^^^^^ expected `ContainsRc<T, K>`, found `&ContainsRc<T, K>`
|
||||
|
|
||||
= note: expected struct `ContainsRc<_, _>`
|
||||
found reference `&ContainsRc<_, _>`
|
||||
note: `ContainsRc<T, K>` does not implement `Clone`, so `&ContainsRc<T, K>` was cloned instead
|
||||
--> $DIR/derive-implicit-bound-on-clone.rs:10:5
|
||||
|
|
||||
LL | x.clone()
|
||||
| ^
|
||||
help: `Clone` is not implemented because the some trait bounds could not be satisfied
|
||||
--> $DIR/derive-implicit-bound-on-clone.rs:5:19
|
||||
|
|
||||
LL | #[derive(Clone)]
|
||||
| ----- in this derive macro expansion
|
||||
LL | struct ContainsRc<T, K> {
|
||||
| ^ ^ derive introduces an implicit unsatisfied trait bound `K: Clone`
|
||||
| |
|
||||
| derive introduces an implicit unsatisfied trait bound `T: Clone`
|
||||
= help: consider manually implementing `Clone` to avoid the implict type parameter bounds
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/derive-implicit-bound-on-clone.rs:20:5
|
||||
|
|
||||
LL | fn clone_me_single<T>(x: &ContainsRcSingle<T>) -> ContainsRcSingle<T> {
|
||||
| ------------------- expected `ContainsRcSingle<T>` because of return type
|
||||
LL | x.clone()
|
||||
| ^^^^^^^^^ expected `ContainsRcSingle<T>`, found `&ContainsRcSingle<T>`
|
||||
|
|
||||
= note: expected struct `ContainsRcSingle<_>`
|
||||
found reference `&ContainsRcSingle<_>`
|
||||
note: `ContainsRcSingle<T>` does not implement `Clone`, so `&ContainsRcSingle<T>` was cloned instead
|
||||
--> $DIR/derive-implicit-bound-on-clone.rs:20:5
|
||||
|
|
||||
LL | x.clone()
|
||||
| ^
|
||||
help: `Clone` is not implemented because a trait bound is not satisfied
|
||||
--> $DIR/derive-implicit-bound-on-clone.rs:15:25
|
||||
|
|
||||
LL | #[derive(Clone)]
|
||||
| ----- in this derive macro expansion
|
||||
LL | struct ContainsRcSingle<T> {
|
||||
| ^ derive introduces an implicit `T: Clone` bound
|
||||
= help: consider manually implementing `Clone` to avoid the implict type parameter bounds
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue