Skip to content

Commit e1c9d10

Browse files
[flake8-comprehensions] Do not emit unnecessary-map diagnostic when lambda has different arity (C417) (#15802)
1 parent 23c9884 commit e1c9d10

File tree

3 files changed

+60
-85
lines changed

3 files changed

+60
-85
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C417.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
set(map(lambda x: x % 2 == 0, nums))
77
dict(map(lambda v: (v, v**2), nums))
88
dict(map(lambda v: [v, v**2], nums))
9-
map(lambda: "const", nums)
9+
1010
map(lambda _: 3.0, nums)
1111
_ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
1212
all(map(lambda v: isinstance(v, dict), nums))
1313
filter(func, map(lambda v: v, nums))
14-
list(map(lambda x, y: x * y, nums))
14+
1515

1616
# When inside f-string, then the fix should be surrounded by whitespace
1717
_ = f"{set(map(lambda x: x % 2 == 0, nums))}"
@@ -49,11 +49,24 @@ def func(arg1: int, arg2: int = 4):
4949
map(lambda x: x, (x, y, z))
5050

5151
# See https://github.com/astral-sh/ruff/issues/14808
52-
# The following should be Ok since
52+
# The following should be Ok since
5353
# named expressions are a syntax error inside comprehensions
5454
a = [1, 2, 3]
5555
b = map(lambda x: x, c := a)
5656
print(c)
5757

5858
# Check nested as well
5959
map(lambda x:x, [c:=a])
60+
61+
62+
# https://github.com/astral-sh/ruff/issues/15796
63+
map(lambda: "const", nums)
64+
list(map(lambda x, y: x * y, nums))
65+
66+
67+
map(lambda: 1, "xyz")
68+
map(lambda x, y: x, [(1, 2), (3, 4)])
69+
list(map(lambda: 1, "xyz"))
70+
list(map(lambda x, y: x, [(1, 2), (3, 4)]))
71+
list(map(lambda: 1, "xyz"))
72+
list(map(lambda x, y: x, [(1, 2), (3, 4)]))

crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_map.rs

+32-24
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,7 @@ pub(crate) fn unnecessary_map(
111111
return;
112112
}
113113

114-
if parameters.as_ref().is_some_and(|parameters| {
115-
late_binding(parameters, body)
116-
|| parameters
117-
.iter_non_variadic_params()
118-
.any(|param| param.default.is_some())
119-
|| parameters.vararg.is_some()
120-
|| parameters.kwarg.is_some()
121-
}) {
114+
if !lambda_has_expected_arity(parameters.as_deref(), body) {
122115
return;
123116
}
124117
}
@@ -153,14 +146,7 @@ pub(crate) fn unnecessary_map(
153146
return;
154147
};
155148

156-
if parameters.as_ref().is_some_and(|parameters| {
157-
late_binding(parameters, body)
158-
|| parameters
159-
.iter_non_variadic_params()
160-
.any(|param| param.default.is_some())
161-
|| parameters.vararg.is_some()
162-
|| parameters.kwarg.is_some()
163-
}) {
149+
if !lambda_has_expected_arity(parameters.as_deref(), body) {
164150
return;
165151
}
166152
}
@@ -205,14 +191,7 @@ pub(crate) fn unnecessary_map(
205191
return;
206192
}
207193

208-
if parameters.as_ref().is_some_and(|parameters| {
209-
late_binding(parameters, body)
210-
|| parameters
211-
.iter_non_variadic_params()
212-
.any(|param| param.default.is_some())
213-
|| parameters.vararg.is_some()
214-
|| parameters.kwarg.is_some()
215-
}) {
194+
if !lambda_has_expected_arity(parameters.as_deref(), body) {
216195
return;
217196
}
218197
}
@@ -232,6 +211,35 @@ pub(crate) fn unnecessary_map(
232211
checker.diagnostics.push(diagnostic);
233212
}
234213

214+
/// A lambda as the first argument to `map()` has the "expected" arity when:
215+
///
216+
/// * It has exactly one parameter
217+
/// * That parameter is not variadic
218+
/// * That parameter does not have a default value
219+
fn lambda_has_expected_arity(parameters: Option<&Parameters>, body: &Expr) -> bool {
220+
let Some(parameters) = parameters else {
221+
return false;
222+
};
223+
224+
let [parameter] = &parameters.args[..] else {
225+
return false;
226+
};
227+
228+
if parameter.default.is_some() {
229+
return false;
230+
}
231+
232+
if parameters.vararg.is_some() || parameters.kwarg.is_some() {
233+
return false;
234+
}
235+
236+
if late_binding(parameters, body) {
237+
return false;
238+
}
239+
240+
true
241+
}
242+
235243
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
236244
pub(crate) enum ObjectType {
237245
Generator,

crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C417_C417.py.snap

+12-58
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ C417.py:6:1: C417 [*] Unnecessary `map()` usage (rewrite using a set comprehensi
8282
6 |+{x % 2 == 0 for x in nums}
8383
7 7 | dict(map(lambda v: (v, v**2), nums))
8484
8 8 | dict(map(lambda v: [v, v**2], nums))
85-
9 9 | map(lambda: "const", nums)
85+
9 9 |
8686

8787
C417.py:7:1: C417 [*] Unnecessary `map()` usage (rewrite using a dict comprehension)
8888
|
@@ -91,7 +91,6 @@ C417.py:7:1: C417 [*] Unnecessary `map()` usage (rewrite using a dict comprehens
9191
7 | dict(map(lambda v: (v, v**2), nums))
9292
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
9393
8 | dict(map(lambda v: [v, v**2], nums))
94-
9 | map(lambda: "const", nums)
9594
|
9695
= help: Replace `map()` with a dict comprehension
9796

@@ -102,7 +101,7 @@ C417.py:7:1: C417 [*] Unnecessary `map()` usage (rewrite using a dict comprehens
102101
7 |-dict(map(lambda v: (v, v**2), nums))
103102
7 |+{v: v**2 for v in nums}
104103
8 8 | dict(map(lambda v: [v, v**2], nums))
105-
9 9 | map(lambda: "const", nums)
104+
9 9 |
106105
10 10 | map(lambda _: 3.0, nums)
107106

108107
C417.py:8:1: C417 [*] Unnecessary `map()` usage (rewrite using a dict comprehension)
@@ -111,7 +110,7 @@ C417.py:8:1: C417 [*] Unnecessary `map()` usage (rewrite using a dict comprehens
111110
7 | dict(map(lambda v: (v, v**2), nums))
112111
8 | dict(map(lambda v: [v, v**2], nums))
113112
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
114-
9 | map(lambda: "const", nums)
113+
9 |
115114
10 | map(lambda _: 3.0, nums)
116115
|
117116
= help: Replace `map()` with a dict comprehension
@@ -122,35 +121,14 @@ C417.py:8:1: C417 [*] Unnecessary `map()` usage (rewrite using a dict comprehens
122121
7 7 | dict(map(lambda v: (v, v**2), nums))
123122
8 |-dict(map(lambda v: [v, v**2], nums))
124123
8 |+{v: v**2 for v in nums}
125-
9 9 | map(lambda: "const", nums)
124+
9 9 |
126125
10 10 | map(lambda _: 3.0, nums)
127126
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
128127

129-
C417.py:9:1: C417 [*] Unnecessary `map()` usage (rewrite using a generator expression)
130-
|
131-
7 | dict(map(lambda v: (v, v**2), nums))
132-
8 | dict(map(lambda v: [v, v**2], nums))
133-
9 | map(lambda: "const", nums)
134-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
135-
10 | map(lambda _: 3.0, nums)
136-
11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
137-
|
138-
= help: Replace `map()` with a generator expression
139-
140-
Unsafe fix
141-
6 6 | set(map(lambda x: x % 2 == 0, nums))
142-
7 7 | dict(map(lambda v: (v, v**2), nums))
143-
8 8 | dict(map(lambda v: [v, v**2], nums))
144-
9 |-map(lambda: "const", nums)
145-
9 |+("const" for _ in nums)
146-
10 10 | map(lambda _: 3.0, nums)
147-
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
148-
12 12 | all(map(lambda v: isinstance(v, dict), nums))
149-
150128
C417.py:10:1: C417 [*] Unnecessary `map()` usage (rewrite using a generator expression)
151129
|
152130
8 | dict(map(lambda v: [v, v**2], nums))
153-
9 | map(lambda: "const", nums)
131+
9 |
154132
10 | map(lambda _: 3.0, nums)
155133
| ^^^^^^^^^^^^^^^^^^^^^^^^ C417
156134
11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
@@ -161,7 +139,7 @@ C417.py:10:1: C417 [*] Unnecessary `map()` usage (rewrite using a generator expr
161139
Unsafe fix
162140
7 7 | dict(map(lambda v: (v, v**2), nums))
163141
8 8 | dict(map(lambda v: [v, v**2], nums))
164-
9 9 | map(lambda: "const", nums)
142+
9 9 |
165143
10 |-map(lambda _: 3.0, nums)
166144
10 |+(3.0 for _ in nums)
167145
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
@@ -170,7 +148,6 @@ C417.py:10:1: C417 [*] Unnecessary `map()` usage (rewrite using a generator expr
170148

171149
C417.py:11:13: C417 [*] Unnecessary `map()` usage (rewrite using a generator expression)
172150
|
173-
9 | map(lambda: "const", nums)
174151
10 | map(lambda _: 3.0, nums)
175152
11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
176153
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
@@ -181,13 +158,13 @@ C417.py:11:13: C417 [*] Unnecessary `map()` usage (rewrite using a generator exp
181158

182159
Unsafe fix
183160
8 8 | dict(map(lambda v: [v, v**2], nums))
184-
9 9 | map(lambda: "const", nums)
161+
9 9 |
185162
10 10 | map(lambda _: 3.0, nums)
186163
11 |-_ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
187164
11 |+_ = "".join((x in nums and "1" or "0" for x in range(123)))
188165
12 12 | all(map(lambda v: isinstance(v, dict), nums))
189166
13 13 | filter(func, map(lambda v: v, nums))
190-
14 14 | list(map(lambda x, y: x * y, nums))
167+
14 14 |
191168

192169
C417.py:12:5: C417 [*] Unnecessary `map()` usage (rewrite using a generator expression)
193170
|
@@ -196,18 +173,17 @@ C417.py:12:5: C417 [*] Unnecessary `map()` usage (rewrite using a generator expr
196173
12 | all(map(lambda v: isinstance(v, dict), nums))
197174
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
198175
13 | filter(func, map(lambda v: v, nums))
199-
14 | list(map(lambda x, y: x * y, nums))
200176
|
201177
= help: Replace `map()` with a generator expression
202178

203179
Unsafe fix
204-
9 9 | map(lambda: "const", nums)
180+
9 9 |
205181
10 10 | map(lambda _: 3.0, nums)
206182
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
207183
12 |-all(map(lambda v: isinstance(v, dict), nums))
208184
12 |+all((isinstance(v, dict) for v in nums))
209185
13 13 | filter(func, map(lambda v: v, nums))
210-
14 14 | list(map(lambda x, y: x * y, nums))
186+
14 14 |
211187
15 15 |
212188

213189
C417.py:13:14: C417 [*] Unnecessary `map()` usage (rewrite using a generator expression)
@@ -216,7 +192,6 @@ C417.py:13:14: C417 [*] Unnecessary `map()` usage (rewrite using a generator exp
216192
12 | all(map(lambda v: isinstance(v, dict), nums))
217193
13 | filter(func, map(lambda v: v, nums))
218194
| ^^^^^^^^^^^^^^^^^^^^^^ C417
219-
14 | list(map(lambda x, y: x * y, nums))
220195
|
221196
= help: Replace `map()` with a generator expression
222197

@@ -226,31 +201,10 @@ C417.py:13:14: C417 [*] Unnecessary `map()` usage (rewrite using a generator exp
226201
12 12 | all(map(lambda v: isinstance(v, dict), nums))
227202
13 |-filter(func, map(lambda v: v, nums))
228203
13 |+filter(func, (v for v in nums))
229-
14 14 | list(map(lambda x, y: x * y, nums))
204+
14 14 |
230205
15 15 |
231206
16 16 | # When inside f-string, then the fix should be surrounded by whitespace
232207

233-
C417.py:14:1: C417 [*] Unnecessary `map()` usage (rewrite using a list comprehension)
234-
|
235-
12 | all(map(lambda v: isinstance(v, dict), nums))
236-
13 | filter(func, map(lambda v: v, nums))
237-
14 | list(map(lambda x, y: x * y, nums))
238-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
239-
15 |
240-
16 | # When inside f-string, then the fix should be surrounded by whitespace
241-
|
242-
= help: Replace `map()` with a list comprehension
243-
244-
Unsafe fix
245-
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
246-
12 12 | all(map(lambda v: isinstance(v, dict), nums))
247-
13 13 | filter(func, map(lambda v: v, nums))
248-
14 |-list(map(lambda x, y: x * y, nums))
249-
14 |+[x * y for x, y in nums]
250-
15 15 |
251-
16 16 | # When inside f-string, then the fix should be surrounded by whitespace
252-
17 17 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}"
253-
254208
C417.py:17:8: C417 [*] Unnecessary `map()` usage (rewrite using a set comprehension)
255209
|
256210
16 | # When inside f-string, then the fix should be surrounded by whitespace
@@ -261,7 +215,7 @@ C417.py:17:8: C417 [*] Unnecessary `map()` usage (rewrite using a set comprehens
261215
= help: Replace `map()` with a set comprehension
262216

263217
Unsafe fix
264-
14 14 | list(map(lambda x, y: x * y, nums))
218+
14 14 |
265219
15 15 |
266220
16 16 | # When inside f-string, then the fix should be surrounded by whitespace
267221
17 |-_ = f"{set(map(lambda x: x % 2 == 0, nums))}"

0 commit comments

Comments
 (0)