Skip to content
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

Uplift clippy::clone_double_ref to rustc #109451

Closed
fee1-dead opened this issue Mar 21, 2023 · 5 comments
Closed

Uplift clippy::clone_double_ref to rustc #109451

fee1-dead opened this issue Mar 21, 2023 · 5 comments
Labels
A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@fee1-dead
Copy link
Member

In #109429, a snippet of code involves cloning references outputted a confusing compiler error:

use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::BuildHasher;
use std::hash::Hash;

pub struct Hash128_1;

impl BuildHasher for Hash128_1 {
    type Hasher = DefaultHasher;
    fn build_hasher(&self) -> DefaultHasher { DefaultHasher::default() }
}

#[allow(unused)]
pub fn hashmap_copy<T, U>(
    map: &HashMap<T, U, Hash128_1>,
) where T: Hash + Clone, U: Clone
{
    let mut copy: Vec<U> = map.clone().into_values().collect();
}

pub fn make_map() -> HashMap<String, i64, Hash128_1>
{
    HashMap::with_hasher(Hash128_1)
}
error[E0507]: cannot move out of a shared reference
  --> src/lib.rs:19:28
   |
19 |     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

Changing the diagnostic to provide help when we are trying to use a function that takes self after a .clone() call is nontrivial, since this is MIR borrowck and to my knowledge it is hard to know if it comes from the return value of a .clone() call.

Ideally we should have an error/warning like the one from clippy:

error: using `clone` on a double-reference; this will copy the reference of type `&HashMap<T, U, Hash128_1>` instead of cloning the inner type
  --> src/lib.rs:19:28
   |
19 |     let mut copy: Vec<U> = map.clone().into_values().collect();
   |                            ^^^^^^^^^^^

I think there are other ways this can be confusing, so uplifting can help with many issues related to this and not just the example I linked.


cc @rust-lang/lang: would uplifting be a good idea? I'd be willing to work on this if this gets approval.

@rustbot label +A-lint +T-compiler +T-lang +D-newcomer-roadblock

@rustbot rustbot added A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Mar 21, 2023
@scottmcm scottmcm added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. I-libs-api-nominated The issue / PR has been nominated for discussion during a libs-api team meeting. labels Mar 21, 2023
@scottmcm
Copy link
Member

Personally this seems good, but I think I'd actually rather get @rust-lang/libs-api's take on it, rather than lang.

Do you consider this a reasonable use of clone? Or should it be linted?

Also, I wonder if this is something that would make more sense as an attribute on the impl or something, so it could be a general feature instead of clone-specific. For example, I'd put u32: TryFrom<u8> (and everything using that blanket impl from From) in the same "look, you can technically call try_from here, but in non-generic non-macro code you never should" bucket as calling clone on a reference.

@dtolnay
Copy link
Member

dtolnay commented Mar 21, 2023

I support uplifting this. I've hit the same issue repeatedly too; it is covered in https://dtolnay.github.io/rust-quiz/30.

@Zannick
Copy link

Zannick commented Mar 21, 2023

For example, I'd put u32: TryFrom<u8> (and everything using that blanket impl from From) in the same "look, you can technically call try_from here, but in non-generic non-macro code you never should" bucket as calling clone on a reference.

From a beginner's perspective, clone and other methods are always called on a ref, but it isn't obvious when calling a ref method that you are calling it on a double-ref, because it's implicitly deref'ed (I guess?). So my understanding was that you call clone on a reference to get a copy of the inner non-Copy type. In this case, the issue isn't truly the call on the double-ref but the Clone impl I want not being usable.

error: using clone on a double-reference; this will copy the reference of type &HashMap<T, U, Hash128_1> instead of cloning the inner type

For additional clarity, I would suggest something more like:

note: T is not Clone; using clone on &T will copy the reference instead of cloning the inner type

@jyn514 jyn514 removed the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Mar 25, 2023
@m-ou-se m-ou-se removed the I-libs-api-nominated The issue / PR has been nominated for discussion during a libs-api team meeting. label Mar 28, 2023
@m-ou-se
Copy link
Member

m-ou-se commented Mar 28, 2023

This issue briefly came up in the libs-api meeting.

should it be linted?

Yes, this seems like a very useful lint to us. :)

@fee1-dead fee1-dead self-assigned this Mar 30, 2023
@fee1-dead fee1-dead removed their assignment Jul 7, 2023
@fee1-dead
Copy link
Member Author

This is done as suspicious_double_ref_op and noop_method_call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants