-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve compiler error for missing Clone trait bound #76643
Comments
Hmm, if the code compiled than clippy would help here (https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy), but since it doesn't compile, clippy doesn't get a chance to try 🙁 |
Newcomer here - I just ran into the same problem with code that looks like this (this is as much as I can reduce it) //Oops, I forgot a #[derive(Clone)]
struct MyStruct;
impl MyStruct {
fn my_clone(&self) -> MyStruct {
self.clone()
}
} leading to
Here is a particularly confusing error, where rustc is suggesting I remove a //Oops, I forgot a #[derive(Clone)]
struct MyStruct {
stuff: Vec<u8>
}
impl MyStruct {
fn clone_then_push_then_get_len(&self) -> usize {
let mut x = self.clone();
x.stuff.push(3);
x.stuff.len()
}
}
fn main() {
let my = MyStruct {
stuff: vec![1, 2]
};
println!("{}", my.clone_then_push_then_get_len());
println!("{}", my.stuff.len());
}
(This came up when I was trying to write a So it's not really related to function trait bounds in specific - I believe the error message is confusing because Clone is implemented for all shared references |
I believe only the last case needs some changes. |
Tweak `.clone()` suggestion to work in more cases When going through auto-deref, the `<T as Clone>` impl sometimes needs to be specified for rustc to actually clone the value and not the reference. ``` error[E0507]: cannot move out of dereference of `S` --> $DIR/needs-clone-through-deref.rs:15:18 | LL | for _ in self.clone().into_iter() {} | ^^^^^^^^^^^^ ----------- value moved due to this method call | | | move occurs because value has type `Vec<usize>`, which does not implement the `Copy` trait | note: `into_iter` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: you can `clone` the value and consume it, but this might not be your desired behavior | LL | for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {} | ++++++++++++++++++++++++++++++ + ``` When encountering a move error, look for implementations of `Clone` for the moved type. If there is one, check if all its obligations are met. If they are, we suggest cloning without caveats. If they aren't, we suggest cloning while mentioning the unmet obligations, potentially suggesting `#[derive(Clone)]` when appropriate. ``` error[E0507]: cannot move out of a shared reference --> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28 | LL | let mut copy: Vec<U> = map.clone().into_values().collect(); | ^^^^^^^^^^^ ------------- value moved due to this method call | | | move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait | note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied | LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect(); | ++++++++++++++++++++++++++++++++++++++++++++ + help: consider annotating `Hash128_1` with `#[derive(Clone)]` | LL + #[derive(Clone)] LL | pub struct Hash128_1; | ``` Fix rust-lang#109429. When encountering multiple mutable borrows, suggest cloning and adding derive annotations as needed. ``` error[E0596]: cannot borrow `sm.x` as mutable, as it is behind a `&` reference --> $DIR/accidentally-cloning-ref-borrow-error.rs:32:9 | LL | foo(&mut sm.x); | ^^^^^^^^^ `sm` is a `&` reference, so the data it refers to cannot be borrowed as mutable | help: `Str` doesn't implement `Clone`, so this call clones the reference `&Str` --> $DIR/accidentally-cloning-ref-borrow-error.rs:31:21 | LL | let mut sm = sr.clone(); | ^^^^^^^ help: consider annotating `Str` with `#[derive(Clone)]` | LL + #[derive(Clone)] LL | struct Str { | help: consider specifying this binding's type | LL | let mut sm: &mut Str = sr.clone(); | ++++++++++ ``` Fix rust-lang#34629. Fix rust-lang#76643. Fix rust-lang#91532.
I just faced a compiler error when trying to clone a hashmap parameterized by a non-clone type. The error was a bit cryptic, about not expecting a reference, until I realized I've forgot to add the
T: Clone
trait bound. Here is a minimal function reproducing my issue:And here is the error I got:
The code is available in the playground here. I was wondering if the compiler could deduce that the mistake here could be a missing trait bound and give that hint to the developer.
The text was updated successfully, but these errors were encountered: