rust-lang / rust-clippy

A bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/
https://rust-lang.github.io/rust-clippy/
Other
11.34k stars 1.53k forks source link

needless_borrowed_reference for lambdas not immediately typed #11566

Open Wolvereness opened 1 year ago

Wolvereness commented 1 year ago

Summary

needless_borrowedreference triggers when a lambda is passed to construct a struct, where the type-restriction is only enforced for an implementation. When the type-restriction is eager (like directly to a function), it doesn't appear to trigger. The lint is a false positive because when applying the lint's suggestion, the compiler does not backward-infer that the closure should be a tuple-reference rather than a tuple. The lifetime is specific to the struct and return-type, which can't be (easily) expressed in lambda typing, thus adding `: &(,)` wont work. There are workarounds to properly type the lambda, but are inappropriate fixes.

Lint Name

needless_borrowed_reference

Reproducer

I tried this code:

(playground)

#![deny(clippy::needless_borrowed_reference)]
#![allow(dead_code)]

struct Wrap<'a, L, R>(&'a (L,), R);

trait Callable {
    fn call(&self);
}

impl<
    'a,
    T,
    F: Fn(&'a (T,)) -> V,
    V,
> Callable for Wrap<'a, T, F> {
    fn call(&self) {}
}

fn test() {
    Wrap(&("blah",), |&(ref v,)| v).call();
}

I saw this happen:

    Checking playground v0.0.1 (/playground)
error: dereferencing a tuple pattern where every element takes a reference
  --> src/lib.rs:20:23
   |
20 |     Wrap(&("blah",), |&(ref v,)| v).call();
   |                       ^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
note: the lint level is defined here
  --> src/lib.rs:1:9
   |
1  | #![deny(clippy::needless_borrowed_reference)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: try removing the `&` and `ref` parts
   |
20 -     Wrap(&("blah",), |&(ref v,)| v).call();
20 +     Wrap(&("blah",), |(v,)| v).call();
   |

I expected to see this happen:

Version

0.1.74 (2023-09-24 37390d6)

Additional Labels

No response

coolreader18 commented 7 months ago

Getting this same issue - notably, the suggestion fails to compile (I think there's an issue tag for that?), since without the & rustc assumes it's not a reference at all.