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

False positive with use_self and generics #3410

Closed
daboross opened this issue Nov 4, 2018 · 7 comments · Fixed by #6179
Closed

False positive with use_self and generics #3410

daboross opened this issue Nov 4, 2018 · 7 comments · Fixed by #6179
Labels
C-bug Category: Clippy is not doing the correct thing I-false-positive Issue: The lint was triggered on code it shouldn't have

Comments

@daboross
Copy link

daboross commented Nov 4, 2018

As far as I can tell, the use_self is incorrectly ignoring generic parameters when implementing traits for some types with generics.

Here's my example:

pub trait PhaseTransform<T>: Sized {
    fn transform_from(v: T) -> Self;
}

pub struct IntermediatePhase;

pub struct FinalPhase;

impl PhaseTransform<Vec<IntermediatePhase>> for Vec<FinalPhase> {
    fn transform_from(_: Vec<IntermediatePhase>) -> Self {
        unimplemented!()
    }
}

impl<T> PhaseTransform<Vec<IntermediatePhase>> for Vec<T>
where
    T: PhaseTransform<FinalPhase>,
{
    fn transform_from(intermediates: Vec<IntermediatePhase>) -> Self {
        <Vec<FinalPhase>>::transform_from(intermediates)
            .into_iter()
            .map(PhaseTransform::transform_from)
            .collect()
    }
}

This, as far as I can tell, uses Self as much as possible. But with -W clippy::pedantic, clippy warns of three more places where it thinks I should be able to use Self:

$ cargo clippy -- -W clippy::pedantic
    Checking clippy-false-positive-test v0.1.0 (/home/daboross/clippy-false-positive-test)                                              
warning: unnecessary structure name repetition                                                                                          
  --> src/lib.rs:10:26                                                                                                                  
   |                                                                                                                                    
10 |     fn transform_from(_: Vec<IntermediatePhase>) -> Self {                                                                         
   |                          ^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`                                           
   |                                                                                                                                    
   = note: `-W clippy::use-self` implied by `-W clippy::pedantic`                                                                       
   = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.212/index.html#use_self                   
                                                                                                                                        
warning: unnecessary structure name repetition                                                                                          
  --> src/lib.rs:19:38                                                                                                                  
   |                                                                                                                                    
19 |     fn transform_from(intermediates: Vec<IntermediatePhase>) -> Self {                                                             
   |                                      ^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`                               
   |                                                                                                                                    
   = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.212/index.html#use_self                   
                                                                                                                                        
warning: unnecessary structure name repetition                                                                                          
  --> src/lib.rs:20:10                                                                                                                  
   |                                                                                                                                    
20 |         <Vec<FinalPhase>>::transform_from(intermediates)                                                                           
   |          ^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`                                                                  
   |                                                                                                                                    
   = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.212/index.html#use_self                   
                                                                                                                                        
    Finished dev [unoptimized + debuginfo] target(s) in 0.21s

There are two mistakes: it's treating Vec<IntermediatePhase> as Vec<FinalPhase>, and it's treating Vec<FinalPhase> as Vec<T>.

Hope the example is minimal enough - my original trigger was with a custom trait like this, and it seemed hard to come up with any other reasonable use case which caused this situation.

Clippy version:

$ cargo clippy -V                    
clippy 0.0.212 (b1d0343 2018-10-19)

Related to #1993.

@flip1995 flip1995 added the C-bug Category: Clippy is not doing the correct thing label Nov 4, 2018
@ghost
Copy link

ghost commented Nov 7, 2018

Here is a another example that doesn't involve traits.

#![warn(clippy::use_self)]
#![allow(dead_code)]

struct S<T> {
    t: T
}

impl S<u64> {
    fn foo(_: S<u32>) {
        let _: S<u32>;
    }
}
warning: unnecessary structure name repetition
 --> src/main.rs:9:15
  |
9 |     fn foo(_: S<u32>) {
  |               ^^^^^^ help: use the applicable keyword: `Self`
  |
note: lint level defined here
 --> src/main.rs:1:9
  |
1 | #![warn(clippy::use_self)]
  |         ^^^^^^^^^^^^^^^^
  = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.212/index.html#use_self

warning: unnecessary structure name repetition
  --> src/main.rs:10:16
   |
10 |         let _: S<u32>;
   |                ^^^^^^ help: use the applicable keyword: `Self`
   |
   = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.212/index.html#use_self

Playground

The problem is that the code checks if two paths refer to the same type by comparing the defs but this doesn't account for generics.

https://github.com/rust-lang-nursery/rust-clippy/blob/4c3408c61d1042bf0585de440041ee7edfc5b350/clippy_lints/src/use_self.rs#L221

I couldn't find a way to get the actual type including type parameters for a general path. Maybe someone has a suggestion.

I can see how to handle this for types in function signatures though. I'll submit a PR for that later.

@ghost ghost mentioned this issue Nov 10, 2018
bors bot added a commit that referenced this issue Nov 10, 2018
3423: Fix `use_self` false positive r=flip1995 a=mikerite

This fixes the first error reported in issue #3410.

Co-authored-by: Michael Wright <[email protected]>
@zroug
Copy link

zroug commented Nov 13, 2018

Not involving generics but another false positive:

#![warn(clippy::use_self)]
#![allow(dead_code)]

#[derive(Clone)]
struct S;

impl S {
    fn foo() {
        impl Copy for S {}
    }
}

fn main() {}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=b33a49bdb926b36be6c2fbad5defe205

warning: unnecessary structure name repetition
 --> src/main.rs:9:23
  |
9 |         impl Copy for S {}
  |                       ^ help: use the applicable keyword: `Self`
  |

With generics, the error also happens with associated types:

#![warn(clippy::use_self)]
#![allow(dead_code)]

struct S<T1, T2> {
    t1: T1,
    t2: T2,
}

impl<T1: Copy, T2: Copy> Iterator for S<T1, T2> {
    type Item = S<T2, T1>;
    fn next(&mut self) -> Option<Self::Item> {
        Some(S {
            t1: self.t2,
            t2: self.t1,
        })
    }
}

fn main() {}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=42f001263b6139a9333c08290ccd188c

warning: unnecessary structure name repetition
  --> src/main.rs:10:17
   |
10 |     type Item = S<T2, T1>;
   |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
   |

warning: unnecessary structure name repetition
  --> src/main.rs:12:14
   |
12 |         Some(S {
   |              ^ help: use the applicable keyword: `Self`
   |

(Both warnings are wrong.)

@zroug
Copy link

zroug commented Nov 13, 2018

I couldn't find a way to get the actual type including type parameters for a general path. Maybe someone has a suggestion.

I don't know how to do that but there is a pull request #1997. There was no activity for a long time but there is a bit of discussion.

@eddyb
Copy link
Member

eddyb commented Apr 7, 2020

IMO clippy should just use hir_ty_to_ty until a query alternative is provided.
This should be considered an essential operation and clippy should make use of it as much as possible.

It's unnecessary to compare hir::Tys in intricate manners when you can just get a Ty and == it.

tnielens pushed a commit to tnielens/rust-clippy that referenced this issue Apr 20, 2020
@tnielens
Copy link
Contributor

I started working on this based on the recommendation and example committed by @eddyb .

tnielens pushed a commit to tnielens/rust-clippy that referenced this issue Apr 23, 2020
tnielens pushed a commit to tnielens/rust-clippy that referenced this issue Apr 23, 2020
tnielens pushed a commit to tnielens/rust-clippy that referenced this issue Apr 24, 2020
tnielens added a commit to tnielens/rust-clippy that referenced this issue Apr 26, 2020
tnielens added a commit to tnielens/rust-clippy that referenced this issue Apr 26, 2020
tnielens added a commit to tnielens/rust-clippy that referenced this issue Apr 26, 2020
tnielens added a commit to tnielens/rust-clippy that referenced this issue Apr 26, 2020
tnielens added a commit to tnielens/rust-clippy that referenced this issue Apr 27, 2020
flip1995 pushed a commit to flip1995/rust-clippy that referenced this issue Apr 29, 2020
bors added a commit that referenced this issue Oct 13, 2020
…itive, r=<try>

rework use_self impl based on ty::Ty comparison #3410

`use_self` lint refactoring. As suggested by `@eddyb` , implement the lint based on `ty::Ty` comparison instead of `hir::Path` checks.

This PR introduces negative regressions. The cases were covered in the previous implementation. See the test file.

It fixes #3410, #2843, #3859, #4734 and #4140. Should fix #4143 (example doesn't compile). #4305 false positive seems also fixed but the uitest fails to compile the unmodified test case in `use_self.rs.fixed`. Implements #5078.
Generally the implementation checks are done at mir level and offers higher guarantees against false positives. It is probably fixing other unreported false positives.

changelog: fix use_self generics false positives
@phansch phansch added the I-false-positive Issue: The lint was triggered on code it shouldn't have label Dec 21, 2020
bors added a commit that referenced this issue Jan 19, 2021
Rework use_self impl based on ty::Ty comparison #3410 | Take 2

This builds on top of #5531

I already reviewed and approved the commits by `@montrivo.` So only the review of my commits should be necessary.

I would also appreciate your review `@montrivo,` since you are familiar with the challenges here.

Fixes #3410 and Fixes #4143 (same problem)
Fixes #2843
Fixes #3859
Fixes #4734 and fixes #6221
Fixes #4305
Fixes #5078 (even at expression level now 🎉)
Fixes #3881 and Fixes #4887 (same problem)
Fixes #3909

Not yet: #4140 (test added)

All the credit for the fixes goes to `@montrivo.` I only refactored and copy and pasted his code.

changelog: rewrite [`use_self`] lint and fix multiple (8) FPs. One to go.
@kawogi
Copy link

kawogi commented Jan 26, 2021

I think this is the same problem in a slightly different shape:

#![warn(clippy::use_self)]

pub trait Trait<T> {
    fn my_fn(_: T);
}

impl<T> Trait<T> for bool {
    fn my_fn(_: T) {
        println!("clippy: unnecessary structure name repetition");
        let _positive: bool = false;
    }
}

The false positive gets triggered twice: once somewhere in the macro (match by accident) and once in the declaration.

@CAD97
Copy link
Contributor

CAD97 commented Jan 26, 2021

I think that one's different. You could say let positive: Self = false, but that's also probably not better. This lint should probably not fire for primitive types.

E.g. even in the body of an impl for !, it's probably better to refer to ! than Self. For uN you could make a case to use Self (using the same impl for multiple uN), but primitives are much more likely to be mentioned when it doesn't matter that they're Self, just that they're the primitive type.

bors added a commit that referenced this issue Feb 10, 2021
Rework use_self impl based on ty::Ty comparison #3410 | Take 2

This builds on top of #5531

I already reviewed and approved the commits by `@montrivo.` So only the review of my commits should be necessary.

I would also appreciate your review `@montrivo,` since you are familiar with the challenges here.

Fixes #3410 and Fixes #4143 (same problem)
Fixes #2843
Fixes #3859
Fixes #4734 and fixes #6221
Fixes #4305
Fixes #5078 (even at expression level now 🎉)
Fixes #3881 and Fixes #4887 (same problem)
Fixes #3909

Not yet: #4140 (test added)

All the credit for the fixes goes to `@montrivo.` I only refactored and copy and pasted his code.

changelog: rewrite [`use_self`] lint and fix multiple (8) FPs. One to go.
@bors bors closed this as completed in 605e9ba Feb 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing I-false-positive Issue: The lint was triggered on code it shouldn't have
Projects
None yet
8 participants