_Originally posted by @simonbuchan in https://github.com/rust-lang/rust/issues/26925#issuecomment-593708712_
I think I would be a lot happier with the current situation with "just" adding more information to the compiler diagnostic.
At the moment, you get something like:
error[E0599]: no method named `clone` found for type `Ptr<Foo>` in the current scope
--> src/main.rs:9:15
|
2 | struct Ptr<T>(*mut T);
| ---------------------- method `clone` not found for this
...
9 | let b = a.clone();
| ^^^^^ method not found in `Ptr<Foo>`
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`Ptr<Foo> : std::clone::Clone`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `std::clone::Clone`
or
error[E0382]: use of moved value: `a`
--> src/main.rs:10:15
|
8 | let a = Ptr(&mut foo);
| - move occurs because `a` has type `Ptr<Foo>`, which does not implement the `Copy` trait
9 | let b = a;
| - value moved here
10 | let ptr = a.0;
| ^^^ value used here after move
Neither of these tell you that the reason Ptr doesn't implement Copy or Clone, despite #[derive(Copy, Clone)] being right there. I think some logic to add another sentence for this would get rid of the case where derive doesn't implement when it should, which I think newer users (like me!) would be more likely to hit.
This seems to be better on the latest nightly:
#[derive(Clone)]
struct Ptr<T>(*mut T);
fn foo<T>(ptr: Ptr<T>) {
ptr.clone()
}
fn main() {}
produces:
error[E0599]: no method named `clone` found for struct `Ptr<T>` in the current scope
--> bad_clone.rs:5:9
|
2 | struct Ptr<T>(*mut T);
| ----------------------
| |
| method `clone` not found for this
| doesn't satisfy `Ptr<T>: std::clone::Clone`
...
5 | ptr.clone()
| ^^^^^ method not found in `Ptr<T>`
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`T: std::clone::Clone`
which is required by `Ptr<T>: std::clone::Clone`
help: consider restricting the type parameter to satisfy the trait bound
|
2 | struct Ptr<T>(*mut T) where T: std::clone::Clone;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
Much better! I think we can close this.
Agreed. It might be nice to put in a reference to #26925, but this is much more likely to get a new user on the right track faster. At worst, they might assume that any impl of Clone must have all parameters be Clone too, but that's a lot easier to learn.
Reopening to track remaining concerns raised by @simonbuchan (either fix or decide not to fix).
I found a case which I feel should trigger the improved error message but doesn't on URLO. I tried to simplify it as much as I could and came up with this:
// main.rs
use std::marker::PhantomData;
#[derive(Clone)]
pub struct Inner<C> {
phantom: PhantomData<C>,
}
struct Cloner<C> {
phantom: PhantomData<C>,
}
impl<C> Cloner<C>
where
C: Clone,
{
pub fn call_clone(&self, c: &C) -> C {
c.clone()
}
}
fn clear_error<C>() {
let inner: Inner<C> = Inner {
phantom: PhantomData,
};
let cloner = Cloner {
phantom: PhantomData,
};
cloner.call_clone(&inner);
}
fn confusing_error<C>() {
let inner = Inner {
phantom: PhantomData,
};
let cloner: Cloner<Inner<C>> = Cloner {
phantom: PhantomData,
};
cloner.call_clone(&inner);
}
fn main() {}
clear_error outputs a very clear error message:
error[E0277]: the trait bound `C: std::clone::Clone` is not satisfied
--> src\main.rs:28:23
|
28 | cloner.call_clone(&inner);
| ^^^^^^ the trait `std::clone::Clone` is not implemented for `C`
|
= note: required because of the requirements on the impl of `std::clone::Clone` for `Inner<C>`
help: consider restricting type parameter `C`
|
21 | fn clear_error<C: std::clone::Clone>() {
| ^^^^^^^^^^^^^^^^^^^
while confusing_error's message is less helpful:
error[E0599]: no method named `call_clone` found for struct `Cloner<Inner<C>>` in the current scope
--> src\main.rs:38:12
|
4 | pub struct Inner<C> {
| ------------------- doesn't satisfy `Inner<C>: std::clone::Clone`
...
8 | struct Cloner<C> {
| ---------------- method `call_clone` not found for this
...
38 | cloner.call_clone(&inner);
| ^^^^^^^^^^ method not found in `Cloner<Inner<C>>`
|
= note: the method `call_clone` exists but the following trait bounds were not satisfied:
`Inner<C>: std::clone::Clone`
Most helpful comment
This seems to be better on the latest nightly:
produces: