Skip to content
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

Allow filter_map_identity when the closure is typed #12562

Merged
merged 2 commits into from
Mar 31, 2024
Merged

Conversation

m-rph
Copy link
Contributor

@m-rph m-rph commented Mar 25, 2024

This extends the filter_map_identity lint to support typed closures.

For untyped closures, we know that the program compiles, and therefore we can safely suggest using flatten.

For typed closures, they may participate in type resolution. In this case we use Applicability::MaybeIncorrect.

Details:
https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Should.20.60filter_map_identity.60.20lint.20when.20closures.20are.20typed.3F

changelog: filter_map_identity will now suggest using flatten for typed closures.

r? @y21 && @Centri3

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Mar 25, 2024
This extends the `filter_map_identity` lint to support typed closures.

For untyped closures, we know that the program compiles, and therefore
we can safely suggest using flatten.

For typed closures, they may participate in type resolution. In this case
we use `Applicability::MaybeIncorrect`.

Details:
https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Should.20.60filter_map_identity.60.20lint.20when.20closures.20are.20typed.3F
@y21
Copy link
Member

y21 commented Mar 26, 2024

Is there a reason that we'd only want to do this for filter_map_identity, and not for all callers of is_expr_untyped_identity_function?

But also, are we sure that type annotations can always be "reasonably" specified elsewhere when the closure is removed? I'm having a hard time coming up with a practical example where you can't. I think there's usually always somewhere where the type could be specified to make type inference happy. E.g.

fn accepts_iter(_: impl Iterator) {}

accepts_iter(iter::empty().map(|v: i32| v));

Removing the .map() as map_identity would suggest (if we made this change there as well) would break type inference, but the user can just write iter::empty::<i32>().

#9122 is a more practical FP where these "untyped" functions were introduced, but even here one can write Ok::<_, std::io::Error>(())

@m-rph
Copy link
Contributor Author

m-rph commented Mar 26, 2024

Is there a reason that we'd only want to do this for filter_map_identity, and not for all callers of is_expr_untyped_identity_function?

I was thinking we could introduce this change gradually, starting from less error prone cases such as this one, and slowly moving into more common ones while accounting for issues that can occur such as the one you've presented.

are we sure that type annotations can always be "reasonably" specified elsewhere when the closure is removed?

I have a hard time coming up with situations where this is exceptionally hard to be honest.

Even in the tests that I have added where I'd have expected the identity function to actually help with inference, rustc flatout refused to compile it, though that is certainly different to the map case.

For map specifically, we could perhaps suggest adding the type as in iter::empty::<i32>() ?

Copy link
Member

@y21 y21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me with the nit fixed, @Centri3 does this make sense to you as well?

return Some(Applicability::MachineApplicable);
}
if is_expr_identity_function(cx, expr) {
return Some(Applicability::MaybeIncorrect);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be Unspecified (or HasPlaceholders).

MaybeIncorrect suggestions should still compile.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've interpreted "valid Rust code" as it parsing correctly, everything else can fail I'm pretty sure

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember @xFrednet commenting about it here

But oh well, the fact that we have a different understanding is all the more reason that the documentation/naming for Applicability could be better

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rustfix somewhere has an issue to rename these variants to make the difference clearer. I think it's mostly stuck on finding better names:

rust-lang/cargo#13028

@y21
Copy link
Member

y21 commented Mar 26, 2024

For map specifically, we could perhaps suggest adding the type as in iter::empty::<i32>() ?

I'm not sure if special casing fn calls as the .map() receiver (which is only one out of many possible ways where the inference variable could have possibly come from) is worth the complexity that that adds, especially when the inferred type is not as trivial. E.g.

<std::iter::Empty<Option<_>> as Default>::default().flat_map(|v: Option<i32>| v)
//                       ^ i32 needs to go here

Copy link
Member

@Centri3 Centri3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really think we should pass this as is without some kind of backwards heuristic to type_certainty. I have no problems with the code itself, but if possible we should extend type_certainty to either look "inwards" (as it does currently), or "outwards".

I've seen FPs in the past caused by this, MREs will probably look contrived but this definitely can (and will) come up often in practice.

Let's at least run lintcheck on a lot of popular crates before we do merge as is, it'd be nice if it can select a lot of random ones in the top 1000

@m-rph
Copy link
Contributor Author

m-rph commented Mar 26, 2024

fwiw, running cargo lintcheck doesn't introduce any additional lints going from master to this PR. I will let it run with the --recursive option tonight.

I think we should first extend cargo lintcheck with some more crates before we take this any further.

@y21
Copy link
Member

y21 commented Mar 26, 2024

you can run cargo r --bin popular-crates lintcheck_crates.toml -n <number_of_crates> in the lintcheck dir locally to populate the toml file with the top n crates (but yes I agree we should definitely add more crates to the default lintcheck_crates.toml, because those 25 crates that it by default has aren't very useful on their own, not sure if we want to block this PR on that tho since it's not really a blocker?)

@Centri3
Copy link
Member

Centri3 commented Mar 26, 2024

I didn't know about that, though it still would be nice if it could choose them random (otherwise we're checking the same crates everytime)

@m-rph
Copy link
Contributor Author

m-rph commented Mar 28, 2024

What I did:

  1. Downloaded top 200 crates via cargo r --bin popular-crates lintcheck_crates.toml -n 200
  2. Ran cargo lintcheck
  3. Switched to PR: git switch 12501
  4. Ran cargo lintcheck again

Result:

Stats:

((empty))

Thus no errors were introduced from this.

Should I increase the number to say top 500?

@Centri3
Copy link
Member

Centri3 commented Mar 28, 2024

Top 200 is probably enough for now.

@m-rph
Copy link
Contributor Author

m-rph commented Mar 28, 2024

Is the new applicability okay?

@m-rph m-rph requested review from y21, Centri3 and xFrednet March 29, 2024 11:01
@y21
Copy link
Member

y21 commented Mar 29, 2024

Yeah, looks fine to me. I'd say its ready to go, but I'll wait a bit to see if others have something to say

@xFrednet
Copy link
Member

The applicability also looks good to me(I haven't looked at anything else)

@y21
Copy link
Member

y21 commented Mar 31, 2024

Lets move this forward, thanks! LGTM

@bors r+

@bors
Copy link
Collaborator

bors commented Mar 31, 2024

📌 Commit 60937bf has been approved by y21

It is now in the queue for this repository.

@bors
Copy link
Collaborator

bors commented Mar 31, 2024

⌛ Testing commit 60937bf with merge 95338e7...

bors added a commit that referenced this pull request Mar 31, 2024
Allow `filter_map_identity` when the closure is typed

This extends the `filter_map_identity` lint to support typed closures.

For untyped closures, we know that the program compiles, and therefore we can safely suggest using flatten.

For typed closures, they may participate in type resolution. In this case we use `Applicability::MaybeIncorrect`.

Details:
https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Should.20.60filter_map_identity.60.20lint.20when.20closures.20are.20typed.3F

changelog: `filter_map_identity` will now suggest using flatten for typed closures.

r? `@y21` && `@Centri3`
@bors
Copy link
Collaborator

bors commented Mar 31, 2024

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: y21
Pushing 95338e7 to master...

@bors
Copy link
Collaborator

bors commented Mar 31, 2024

👀 Test was successful, but fast-forwarding failed: 422 1 review requesting changes and 1 approving review by reviewers with write access.

@xFrednet
Copy link
Member

@bors retry

bors added a commit that referenced this pull request Mar 31, 2024
Allow `filter_map_identity` when the closure is typed

This extends the `filter_map_identity` lint to support typed closures.

For untyped closures, we know that the program compiles, and therefore we can safely suggest using flatten.

For typed closures, they may participate in type resolution. In this case we use `Applicability::MaybeIncorrect`.

Details:
https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Should.20.60filter_map_identity.60.20lint.20when.20closures.20are.20typed.3F

changelog: `filter_map_identity` will now suggest using flatten for typed closures.

r? `@y21` && `@Centri3`
@bors
Copy link
Collaborator

bors commented Mar 31, 2024

⌛ Testing commit 60937bf with merge ecca4e3...

@bors
Copy link
Collaborator

bors commented Mar 31, 2024

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: y21
Pushing ecca4e3 to master...

@bors
Copy link
Collaborator

bors commented Mar 31, 2024

👀 Test was successful, but fast-forwarding failed: 422 1 review requesting changes and 1 approving review by reviewers with write access.

@xFrednet xFrednet dismissed Centri3’s stale review March 31, 2024 12:14

Let's see if this blocks bors?

@xFrednet
Copy link
Member

Third time's the charm?

@bors retry

@bors
Copy link
Collaborator

bors commented Mar 31, 2024

⌛ Testing commit 60937bf with merge 797d50d...

@bors
Copy link
Collaborator

bors commented Mar 31, 2024

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: y21
Pushing 797d50d to master...

@bors bors merged commit 797d50d into rust-lang:master Mar 31, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants