[map_identity]: respect match ergonomics

This commit is contained in:
y21 2023-11-11 13:48:26 +01:00
parent 34b7d1559f
commit b2cf8f7a24
4 changed files with 85 additions and 43 deletions

View file

@ -2034,6 +2034,18 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead. /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool { fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
if cx
.typeck_results()
.pat_binding_modes()
.get(pat.hir_id)
.is_some_and(|mode| matches!(mode, BindingMode::BindByReference(_)))
{
// If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics,
// the inner patterns become references. Don't consider this the identity function
// as that changes types.
return false;
}
match (pat.kind, expr.kind) { match (pat.kind, expr.kind) {
(PatKind::Binding(_, id, _, _), _) => { (PatKind::Binding(_, id, _, _), _) => {
path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty() path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty()

View file

@ -24,28 +24,40 @@ fn main() {
fn issue7189() { fn issue7189() {
// should lint // should lint
let x = [(1, 2), (3, 4)]; let x = [(1, 2), (3, 4)].iter().copied();
let _ = x.iter(); let _ = x.clone();
let _ = x.iter(); let _ = x.clone();
let _ = x.iter(); let _ = x.clone();
let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))]; let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied();
let _ = y.iter(); let _ = y.clone();
// should not lint // should not lint
let _ = x.iter().map(|(x, y)| (x, y, y)); let _ = x.clone().map(|(x, y)| (x, y, y));
let _ = x.iter().map(|(x, _y)| (x,)); let _ = x.clone().map(|(x, _y)| (x,));
let _ = x.iter().map(|(x, _)| (x,)); let _ = x.clone().map(|(x, _)| (x,));
let _ = x.iter().map(|(x, ..)| (x,)); let _ = x.clone().map(|(x, ..)| (x,));
let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z))); let _ = y.clone().map(|(x, y, (z, _))| (x, y, (z, z)));
let _ = y let _ = y
.iter() .clone()
.map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z))); .map(|(x, y, (z, _)): (i32, i32, (i32, (i32,)))| (x, y, (z, z)));
let _ = y let _ = y
.iter() .clone()
.map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,)))); .map(|(x, y, (z, (w,))): (i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
} }
fn not_identity(x: &u16) -> u16 { fn not_identity(x: &u16) -> u16 {
*x *x
} }
fn issue11764() {
let x = [(1, 2), (3, 4)];
// don't lint: this is an `Iterator<Item = &(i32, i32)>`
// match ergonomics makes the binding patterns into references
// so that its type changes to `Iterator<Item = (&i32, &i32)>`
let _ = x.iter().map(|(x, y)| (x, y));
let _ = x.iter().map(|x| (x.0,)).map(|(x,)| x);
// no match ergonomics for `(i32, i32)`
let _ = x.iter().copied();
}

View file

@ -26,30 +26,42 @@ fn main() {
fn issue7189() { fn issue7189() {
// should lint // should lint
let x = [(1, 2), (3, 4)]; let x = [(1, 2), (3, 4)].iter().copied();
let _ = x.iter().map(|(x, y)| (x, y)); let _ = x.clone().map(|(x, y)| (x, y));
let _ = x.iter().map(|(x, y)| { let _ = x.clone().map(|(x, y)| {
return (x, y); return (x, y);
}); });
let _ = x.iter().map(|(x, y)| return (x, y)); let _ = x.clone().map(|(x, y)| return (x, y));
let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))]; let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied();
let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,)))); let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
// should not lint // should not lint
let _ = x.iter().map(|(x, y)| (x, y, y)); let _ = x.clone().map(|(x, y)| (x, y, y));
let _ = x.iter().map(|(x, _y)| (x,)); let _ = x.clone().map(|(x, _y)| (x,));
let _ = x.iter().map(|(x, _)| (x,)); let _ = x.clone().map(|(x, _)| (x,));
let _ = x.iter().map(|(x, ..)| (x,)); let _ = x.clone().map(|(x, ..)| (x,));
let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z))); let _ = y.clone().map(|(x, y, (z, _))| (x, y, (z, z)));
let _ = y let _ = y
.iter() .clone()
.map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z))); .map(|(x, y, (z, _)): (i32, i32, (i32, (i32,)))| (x, y, (z, z)));
let _ = y let _ = y
.iter() .clone()
.map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,)))); .map(|(x, y, (z, (w,))): (i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
} }
fn not_identity(x: &u16) -> u16 { fn not_identity(x: &u16) -> u16 {
*x *x
} }
fn issue11764() {
let x = [(1, 2), (3, 4)];
// don't lint: this is an `Iterator<Item = &(i32, i32)>`
// match ergonomics makes the binding patterns into references
// so that its type changes to `Iterator<Item = (&i32, &i32)>`
let _ = x.iter().map(|(x, y)| (x, y));
let _ = x.iter().map(|x| (x.0,)).map(|(x,)| x);
// no match ergonomics for `(i32, i32)`
let _ = x.iter().copied().map(|(x, y)| (x, y));
}

View file

@ -41,31 +41,37 @@ LL | let _: Result<u32, u32> = Ok(1).map_err(|a| a);
| ^^^^^^^^^^^^^^^ help: remove the call to `map_err` | ^^^^^^^^^^^^^^^ help: remove the call to `map_err`
error: unnecessary map of the identity function error: unnecessary map of the identity function
--> $DIR/map_identity.rs:30:21 --> $DIR/map_identity.rs:30:22
| |
LL | let _ = x.iter().map(|(x, y)| (x, y)); LL | let _ = x.clone().map(|(x, y)| (x, y));
| ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
error: unnecessary map of the identity function error: unnecessary map of the identity function
--> $DIR/map_identity.rs:31:21 --> $DIR/map_identity.rs:31:22
| |
LL | let _ = x.iter().map(|(x, y)| { LL | let _ = x.clone().map(|(x, y)| {
| _____________________^ | ______________________^
LL | | return (x, y); LL | | return (x, y);
LL | | }); LL | | });
| |______^ help: remove the call to `map` | |______^ help: remove the call to `map`
error: unnecessary map of the identity function error: unnecessary map of the identity function
--> $DIR/map_identity.rs:34:21 --> $DIR/map_identity.rs:34:22
| |
LL | let _ = x.iter().map(|(x, y)| return (x, y)); LL | let _ = x.clone().map(|(x, y)| return (x, y));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
error: unnecessary map of the identity function error: unnecessary map of the identity function
--> $DIR/map_identity.rs:37:21 --> $DIR/map_identity.rs:37:22
| |
LL | let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,)))); LL | let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
error: aborting due to 10 previous errors error: unnecessary map of the identity function
--> $DIR/map_identity.rs:66:30
|
LL | let _ = x.iter().copied().map(|(x, y)| (x, y));
| ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
error: aborting due to 11 previous errors