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 in redundant_closure when closure value's lifetime is constrained #4002

Closed
dtolnay opened this issue Apr 19, 2019 · 6 comments · Fixed by #7661
Closed

False positive in redundant_closure when closure value's lifetime is constrained #4002

dtolnay opened this issue Apr 19, 2019 · 6 comments · Fixed by #7661
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 I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied L-suggestion Lint: Improving, adding or fixing lint suggestions

Comments

@dtolnay
Copy link
Member

dtolnay commented Apr 19, 2019

pub struct Arg;

pub trait Trait {
    fn f(_: Arg);
}

fn take<T: 'static>(_: T) {}

pub fn f<G: Trait>() {
    take(|v| G::f(v));
}

Clippy recommends take(G::f):

warning: redundant closure found
  --> src/main.rs:10:10
   |
10 |     take(|v| G::f(v));
   |          ^^^^^^^^^^^ help: remove closure as shown: `G::f`
   |
   = note: #[warn(clippy::redundant_closure)] on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure

The original code compiles, while the code suggested by Clippy does not:

error[E0310]: the parameter type `G` may not live long enough
  --> src/main.rs:10:5
   |
9  | pub fn f<G: Trait>() {
   |          -- help: consider adding an explicit lifetime bound `G: 'static`...
10 |     take(G::f);
   |     ^^^^
   |
note: ...so that the type `fn(Arg) {<G as Trait>::f}` will meet its required lifetime bounds
  --> src/main.rs:10:5
   |
10 |     take(G::f);
   |     ^^^^

I believe the difference is that |v| G::f(v) is an ordinary 'static closure (Arg) -> () that captures nothing and G does not appear in its type, while G::f is according to the compiler a fn(Arg) {<G as Trait>::f} in which G does appear. Due to G appearing in its official type, the closure cannot be considered 'static unless G is 'static.

Mentioning @dgreid who encountered this in Chrome OS.


clippy 0.0.212 (fbb3a47 2019-04-14)

@dtolnay
Copy link
Member Author

dtolnay commented Apr 19, 2019

I believe this false positive is distinct from the other false positives so far reported against redundant_closure:

@Manishearth
Copy link
Member

I'm surprised we're getting so many new false positives for redundant_closure. We've had this lint for ages, I suspect something in rustc changed.

(It's probably worth bisecting at some point!)

@g-bartoszek
Copy link

@Manishearth It seems that majority of those problems are related to #3469. I covered the corner cases I found during implementation but it looks like there are more of them.

@matthiaskrgr matthiaskrgr added C-bug Category: Clippy is not doing the correct thing I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied labels Apr 19, 2019
@Manishearth
Copy link
Member

Ah, I see. That makes sense.

@illicitonion
Copy link
Contributor

Relatedly, the same happens if the mutability of references is different. Repro:

fn call<F: FnOnce(&mut String) -> String>(f: F) -> String {
    f(&mut "Hello".to_owned())
}

fn main() {
    call(|s| s.clone());
}
$ cargo clippy
    Checking rustplay v0.1.0 (/Users/dwagnerhall/tmp/rustplay)
warning: redundant closure found
 --> src/main.rs:7:10
  |
7 |     call(|s| s.clone());
  |          ^^^^^^^^^^^^^ help: remove closure as shown: `std::clone::Clone::clone`
  |
  = note: #[warn(clippy::redundant_closure)] on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure

    Finished dev [unoptimized + debuginfo] target(s) in 0.54s

Removing the closure:

fn call<F: FnOnce(&mut String) -> String>(f: F) -> String {
    f(&mut "Hello".to_owned())
}

fn main() {
    call(Clone::clone);
}
$ cargo check
    Checking rustplay v0.1.0 (/Users/dwagnerhall/tmp/rustplay)
error[E0631]: type mismatch in function arguments
 --> src/main.rs:6:5
  |
6 |     call(Clone::clone);
  |     ^^^^
  |     |
  |     expected signature of `fn(&mut std::string::String) -> _`
  |     found signature of `for<'r> fn(&'r _) -> _`
  |
note: required by `call`
 --> src/main.rs:1:1
  |
1 | fn call<F: FnOnce(&mut String) -> String>(f: F) -> String {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0631`.
error: Could not compile `rustplay`.

To learn more, run the command again with --verbose

@camsteffen
Copy link
Contributor

take(G::f as fn(Arg)) works. We could suggest that, but I think this is a rustc coercion bug.

@bors bors closed this as completed in a64b769 Sep 13, 2021
@rustbot rustbot added the I-false-positive Issue: The lint was triggered on code it shouldn't have label Sep 13, 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 I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied L-suggestion Lint: Improving, adding or fixing lint suggestions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants