Skip to content

Commit 3c3ee9b

Browse files
authored
{flat_,}map_identity: recognize |[x, y]| [x, y] as an identity function as well (#15229)
changelog: [`map_identity`,`flat_map_identity`]: also recognize `|[x, y]| [x, y]` fixes #15198
2 parents 3d7188d + e610584 commit 3c3ee9b

File tree

7 files changed

+75
-5
lines changed

7 files changed

+75
-5
lines changed

clippy_utils/src/lib.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
18961896
/// * `|x| { return x }`
18971897
/// * `|x| { return x; }`
18981898
/// * `|(x, y)| (x, y)`
1899+
/// * `|[x, y]| [x, y]`
18991900
///
19001901
/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
19011902
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
@@ -1906,9 +1907,9 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
19061907
.get(pat.hir_id)
19071908
.is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
19081909
{
1909-
// If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics,
1910-
// the inner patterns become references. Don't consider this the identity function
1911-
// as that changes types.
1910+
// If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
1911+
// due to match ergonomics, the inner patterns become references. Don't consider this
1912+
// the identity function as that changes types.
19121913
return false;
19131914
}
19141915

@@ -1921,6 +1922,13 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
19211922
{
19221923
pats.iter().zip(tup).all(|(pat, expr)| check_pat(cx, pat, expr))
19231924
},
1925+
(PatKind::Slice(before, slice, after), ExprKind::Array(arr))
1926+
if slice.is_none() && before.len() + after.len() == arr.len() =>
1927+
{
1928+
(before.iter().chain(after))
1929+
.zip(arr)
1930+
.all(|(pat, expr)| check_pat(cx, pat, expr))
1931+
},
19241932
_ => false,
19251933
}
19261934
}

tests/ui/flat_map_identity.fixed

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,16 @@ fn main() {
1616
let _ = iterator.flatten();
1717
//~^ flat_map_identity
1818
}
19+
20+
fn issue15198() {
21+
let x = [[1, 2], [3, 4]];
22+
// don't lint: this is an `Iterator<Item = &[i32, i32]>`
23+
// match ergonomics makes the binding patterns into references
24+
// so that its type changes to `Iterator<Item = [&i32, &i32]>`
25+
let _ = x.iter().flat_map(|[x, y]| [x, y]);
26+
let _ = x.iter().flat_map(|x| [x[0]]);
27+
28+
// no match ergonomics for `[i32, i32]`
29+
let _ = x.iter().copied().flatten();
30+
//~^ flat_map_identity
31+
}

tests/ui/flat_map_identity.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,16 @@ fn main() {
1616
let _ = iterator.flat_map(|x| return x);
1717
//~^ flat_map_identity
1818
}
19+
20+
fn issue15198() {
21+
let x = [[1, 2], [3, 4]];
22+
// don't lint: this is an `Iterator<Item = &[i32, i32]>`
23+
// match ergonomics makes the binding patterns into references
24+
// so that its type changes to `Iterator<Item = [&i32, &i32]>`
25+
let _ = x.iter().flat_map(|[x, y]| [x, y]);
26+
let _ = x.iter().flat_map(|x| [x[0]]);
27+
28+
// no match ergonomics for `[i32, i32]`
29+
let _ = x.iter().copied().flat_map(|[x, y]| [x, y]);
30+
//~^ flat_map_identity
31+
}

tests/ui/flat_map_identity.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,11 @@ error: use of `flat_map` with an identity function
1919
LL | let _ = iterator.flat_map(|x| return x);
2020
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
2121

22-
error: aborting due to 3 previous errors
22+
error: use of `flat_map` with an identity function
23+
--> tests/ui/flat_map_identity.rs:29:31
24+
|
25+
LL | let _ = x.iter().copied().flat_map(|[x, y]| [x, y]);
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
27+
28+
error: aborting due to 4 previous errors
2329

tests/ui/map_identity.fixed

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,15 @@ fn issue13904() {
8787
let _ = { it }.next();
8888
//~^ map_identity
8989
}
90+
91+
// same as `issue11764`, but for arrays
92+
fn issue15198() {
93+
let x = [[1, 2], [3, 4]];
94+
// don't lint: `&[i32; 2]` becomes `[&i32; 2]`
95+
let _ = x.iter().map(|[x, y]| [x, y]);
96+
let _ = x.iter().map(|x| [x[0]]).map(|[x]| x);
97+
98+
// no match ergonomics for `[i32, i32]`
99+
let _ = x.iter().copied();
100+
//~^ map_identity
101+
}

tests/ui/map_identity.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,15 @@ fn issue13904() {
9393
let _ = { it }.map(|x| x).next();
9494
//~^ map_identity
9595
}
96+
97+
// same as `issue11764`, but for arrays
98+
fn issue15198() {
99+
let x = [[1, 2], [3, 4]];
100+
// don't lint: `&[i32; 2]` becomes `[&i32; 2]`
101+
let _ = x.iter().map(|[x, y]| [x, y]);
102+
let _ = x.iter().map(|x| [x[0]]).map(|[x]| x);
103+
104+
// no match ergonomics for `[i32, i32]`
105+
let _ = x.iter().copied().map(|[x, y]| [x, y]);
106+
//~^ map_identity
107+
}

tests/ui/map_identity.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,11 @@ error: unnecessary map of the identity function
8787
LL | let _ = { it }.map(|x| x).next();
8888
| ^^^^^^^^^^^ help: remove the call to `map`
8989

90-
error: aborting due to 13 previous errors
90+
error: unnecessary map of the identity function
91+
--> tests/ui/map_identity.rs:105:30
92+
|
93+
LL | let _ = x.iter().copied().map(|[x, y]| [x, y]);
94+
| ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
95+
96+
error: aborting due to 14 previous errors
9197

0 commit comments

Comments
 (0)