Skip to content

suspicious_map oddity #5253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
matthiaskrgr opened this issue Mar 2, 2020 · 8 comments · Fixed by #6831
Closed

suspicious_map oddity #5253

matthiaskrgr opened this issue Mar 2, 2020 · 8 comments · Fixed by #6831
Labels
C-bug Category: Clippy is not doing the correct thing C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages

Comments

@matthiaskrgr
Copy link
Member

fn count_and_sum(numbers: &Vec<u32>) -> (usize, u32)   {
	let mut sum: u32 = 0;
	let count = numbers.iter().map(|n| sum += n).count();

	(count, sum)
}

In this example, we use map to process all values and do something with them that involves another mutable variable or function, in the end, we use count() to get the total number of items processed.

The lint explanation says

Maybe map was confused with filter. If the map call is intentional, this should be rewritten. Or, if you intend to drive the iterator to completion, you can just use for_each instead.

But a filter is not useful here. Using for_each is out of option since for_each().count() does not work since for_each() does not return anything.

I'm not sure if inspect() is the right choice here, at least it is not noted in the lints description.

@flip1995
Copy link
Member

flip1995 commented Mar 3, 2020

I guess we should bail out, if some expr in the map closure is an assignment to an UpVar.

@flip1995 flip1995 added C-bug Category: Clippy is not doing the correct thing C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages labels Mar 3, 2020
@jpospychala
Copy link
Contributor

Similar issue is not only with assignment but also a function, like

fn count_and_sum(numbers: &Vec<u32>) -> (usize, u32)   {
  let mut sum: u32 = 0;
  let mut sum_mut = |n| sum += n;
  let count = numbers.iter().map(|n| sum_mut(*n)).count();
  (count, sum)
}

Another case is filter.map.count, where count actually makes some sense.

let count = numbers.iter().filter(|n| **n > 2).map(|n| sum +n).count();

Overall, I do like the current lint message, calling count on map is at least confusing and worth reconsidering.

@mathstuf
Copy link
Contributor

Can clippy just check if the argument to map is FnMut as a heuristic?

@mathstuf
Copy link
Contributor

I'm going to take a stab at it.

@mathstuf
Copy link
Contributor

I think I've made progress. Writing a test now.

@mathstuf
Copy link
Contributor

mathstuf commented Mar 26, 2020

You know, maybe inspect() is the right thing to do here. In fact, any map() argument returning () is probably better served via inspect().

Meh. Brain fart. inspect() isn't strictly better.

mathstuf added a commit to mathstuf/rust-clippy that referenced this issue Mar 26, 2020
If the closure in the `map` call ends up mutating a variable, the call
is assumed to no longer be suspicious.

Given just a function name or path, there's no way to detect that there
is interiour mutability, so the lint still fires in that case. However,
it is now documented as a known problem.

Closes: rust-lang#5253
@mathstuf
Copy link
Contributor

See #5375. Still a hole, but the "common" case of a literal closure should no longer be a false positive.

mathstuf added a commit to mathstuf/rust-clippy that referenced this issue Mar 26, 2020
If the closure in the `map` call ends up mutating a variable, the call
is assumed to no longer be suspicious.

Given just a function name or path, there's no way to detect that there
is interiour mutability, so the lint still fires in that case. However,
it is now documented as a known problem.

Fixes rust-lang#5253
mathstuf added a commit to mathstuf/rust-clippy that referenced this issue Mar 26, 2020
If the closure in the `map` call ends up mutating a variable, the call
is assumed to no longer be suspicious.

Given just a function name or path, there's no way to detect that there
is interiour mutability, so the lint still fires in that case. However,
it is now documented as a known problem.

Fixes rust-lang#5253
mathstuf added a commit to mathstuf/rust-clippy that referenced this issue Mar 26, 2020
If the closure in the `map` call ends up mutating a variable, the call
is assumed to no longer be suspicious.

Given just a function name or path, there's no way to detect that there
is interiour mutability, so the lint still fires in that case. However,
it is now documented as a known problem.

Fixes rust-lang#5253
mathstuf added a commit to mathstuf/rust-clippy that referenced this issue Mar 26, 2020
If the closure in the `map` call ends up mutating a variable, the call
is assumed to no longer be suspicious.

Given just a function name or path, there's no way to detect that there
is interiour mutability, so the lint still fires in that case. However,
it is now documented as a known problem.

Fixes rust-lang#5253
@vallentin
Copy link
Contributor

vallentin commented Jan 13, 2021

Ran into a similar case, that undesirably triggered this lint. I essentially want to perform a count_for_each() where the closure consumes the item. So since count_for_each() is not a thing, I did map().count().

My example can be boiled down to the following, which also triggers the lint:

let v = vec![
    String::from("foo"),
    String::from("bar"),
    String::from("baz"),
];

let count = v
    .into_iter()
    .map(|item| {
        println!("{}", item);
    })
    .count();

println!("Processed {} items", count);

In my actual code, the map closure moves the item of course.

camsteffen pushed a commit to camsteffen/rust-clippy that referenced this issue Mar 2, 2021
If the closure in the `map` call ends up mutating a variable, the call
is assumed to no longer be suspicious.

Given just a function name or path, there's no way to detect that there
is interiour mutability, so the lint still fires in that case. However,
it is now documented as a known problem.

Fixes rust-lang#5253
bors added a commit that referenced this issue Mar 15, 2021
Fix suspicious_map false positives

changelog: Fix suspicious_map false positives

Fixes #5253
Replaces #5375
bors added a commit that referenced this issue Mar 15, 2021
Fix suspicious_map false positives

changelog: Fix suspicious_map false positives

Fixes #5253
Replaces #5375
@bors bors closed this as completed in 0e042d2 Mar 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages
Projects
None yet
5 participants