Auto merge of #11792 - y21:issue11764, r=llogiq

[`map_identity`]: respect match ergonomics

Fixes #11764

Note: the original tests before this were slightly wrong themselves already and had to be changed. They were calling `map` on an iterator of `&(i32, i32)`s, so this PR would stop linting there, but they were meant to test something else unrelated to binding modes, so I just changed them to remove the references so that it iterates over owned values and they all bind by value. This way they continue to test what they checked for before: the identity function for tuple patterns.

changelog: [`map_identity`]: respect match ergonomics
This commit is contained in:
bors 2023-11-11 14:58:00 +00:00
commit d487579efd
4 changed files with 85 additions and 43 deletions

View File

@ -2023,6 +2023,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.
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> 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) {
(PatKind::Binding(_, id, _, _), _) => {
path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty()

View File

@ -24,28 +24,40 @@ fn main() {
fn issue7189() {
// should lint
let x = [(1, 2), (3, 4)];
let _ = x.iter();
let _ = x.iter();
let _ = x.iter();
let x = [(1, 2), (3, 4)].iter().copied();
let _ = x.clone();
let _ = x.clone();
let _ = x.clone();
let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))];
let _ = y.iter();
let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied();
let _ = y.clone();
// should not lint
let _ = x.iter().map(|(x, y)| (x, y, y));
let _ = x.iter().map(|(x, _y)| (x,));
let _ = x.iter().map(|(x, _)| (x,));
let _ = x.iter().map(|(x, ..)| (x,));
let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z)));
let _ = x.clone().map(|(x, y)| (x, y, y));
let _ = x.clone().map(|(x, _y)| (x,));
let _ = x.clone().map(|(x, _)| (x,));
let _ = x.clone().map(|(x, ..)| (x,));
let _ = y.clone().map(|(x, y, (z, _))| (x, y, (z, z)));
let _ = y
.iter()
.map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z)));
.clone()
.map(|(x, y, (z, _)): (i32, i32, (i32, (i32,)))| (x, y, (z, z)));
let _ = y
.iter()
.map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
.clone()
.map(|(x, y, (z, (w,))): (i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
}
fn not_identity(x: &u16) -> u16 {
*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() {
// should lint
let x = [(1, 2), (3, 4)];
let _ = x.iter().map(|(x, y)| (x, y));
let _ = x.iter().map(|(x, y)| {
let x = [(1, 2), (3, 4)].iter().copied();
let _ = x.clone().map(|(x, y)| (x, y));
let _ = x.clone().map(|(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.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied();
let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
// should not lint
let _ = x.iter().map(|(x, y)| (x, y, y));
let _ = x.iter().map(|(x, _y)| (x,));
let _ = x.iter().map(|(x, _)| (x,));
let _ = x.iter().map(|(x, ..)| (x,));
let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z)));
let _ = x.clone().map(|(x, y)| (x, y, y));
let _ = x.clone().map(|(x, _y)| (x,));
let _ = x.clone().map(|(x, _)| (x,));
let _ = x.clone().map(|(x, ..)| (x,));
let _ = y.clone().map(|(x, y, (z, _))| (x, y, (z, z)));
let _ = y
.iter()
.map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z)));
.clone()
.map(|(x, y, (z, _)): (i32, i32, (i32, (i32,)))| (x, y, (z, z)));
let _ = y
.iter()
.map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
.clone()
.map(|(x, y, (z, (w,))): (i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
}
fn not_identity(x: &u16) -> u16 {
*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`
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));
| ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
LL | let _ = x.clone().map(|(x, y)| (x, y));
| ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
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 | | });
| |______^ help: remove the call to `map`
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));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
LL | let _ = x.clone().map(|(x, y)| return (x, y));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
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,))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
LL | let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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