-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
single_match: Don't lint non-exhaustive matches; support tuples #8322
Conversation
This commit changes the behavior of `single_match` lint. After that, we won't lint non-exhaustive matches like this: ```rust match Some(v) { Some(a) => println!("${:?}", a), None => {}, } ``` The rationale is that, because the type of `a` could be changed, so the user can get non-exhaustive match after applying the suggested lint (see rust-lang#8282 (comment) for context). We also will lint `match` constructions with tuples. When we see the tuples on the both arms, we will check them both at the same time, and if they form exhaustive match, we could display the warning. Closes rust-lang#8282
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @llogiq (or someone else) soon. Please see the contribution instructions for more information. |
This is not finished yet, because I need some time to restore logic that calls I'm publishing this PR now to discuss overall design of changes, because there was some discussion in #8282. I'm open to ideas if there are better suggestions to implementing this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I commented where I found shorter ways or was befuddled with the implementation. In general, this should be mostly merge-worthy already apart from the nitpick comments I added.
clippy_lints/src/matches.rs
Outdated
match (&left.kind, &right.kind) { | ||
(PatKind::Wild, _) | (_, PatKind::Wild) => true, | ||
(PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => { | ||
// We don't actually know the position and presence of the `..` (dotdot) operator in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This puzzles me. Why don't we know at which argument #no is the ..
? And why do we need the span for this? It seems like a very roundabout way to implement this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point is that we don't know the actual number of the patterns replaced by ..
.
For example:
match (Some(E::V), Some(E::V), Some(E::V), Some(E::V)) {
(Some(E::V), .., None) => todo!(), // `..` replaces [1, 2]
(.., None) => todo!(), // `..` replaces [0, 1, 2]
}
We want to iterate to the both arms at the same time, to make sure that the elements with the same index form the exhaustive match. So, the logic implemented here basically evaluates the maximum possible length of the patterns and traverses both arms, considering entries in ..
as wildcards (_
).
Probably, the most simple solution would be to run the lint iff the second arm contains only wildcards. But this will make the lint a bit less accurate, because we won't be able to generate warnings in some cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case shouldn't, position
- and rposition
ing the ..
pattern in the subpatterns be enough? Also "span" has a different meaning in most lints, so the naming could be improved (if needed at all).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed the naming to make it differ from rustc
's Span
s.
I'm not sure if we want to remove these variables at all, because this would complicate the loop in places when we need to evaluate the relative offset from the current pattern to the ..
position.
404e262
to
a0c5087
Compare
Just a note that the term "exhaustive match" doesn't really make sense like I thought it did when I posted the issue. All |
8c320be
to
a8fdf5c
Compare
Thank you! @bors r+ |
📌 Commit a8fdf5c has been approved by |
single_match: Don't lint non-exhaustive matches; support tuples `single_match` lint: * Don't lint exhaustive enum patterns without a wild. Rationale: The definition of the enum could be changed, so the user can get non-exhaustive match after applying the suggested lint (see #8282 (comment) for context). * Lint `match` constructions with tuples (as suggested at #8282 (comment)) Closes #8282
💔 Test failed - checks-action_test |
The changelog entries were missing in the PR description, I added them now based on the current description 🙃 @bors retry |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Btw, does this work with tuple structs ( |
No, this PR doesn't implement any additional logic with structs. I think, we could process them just like tuples, i.e.: // lint: S(_, _) forms exhaustive match, so it could be removed
match s {
S(42, a) => dummy(a),
S(_, _) => {},
}
// lint: S(..) forms exhaustive match, so it could be removed
match s {
S(42, a) => dummy(a),
S(..) => {},
} Am I right? |
Yes. It should generally work with all |
These changes allow `single_match` lint to suggest the simplification of `match` constructions for structs with the same name that forms an exhaustive match. For example: ```rust // lint: S(_, _) forms an exhaustive match, so it could be removed match s { S(42, _a) => {}, S(_, _) => {}, } ``` See: rust-lang#8322 (comment)
I added support for tuple structs in #8395. |
single_match
lint:Rationale: The definition of the enum could be changed, so the user can get non-exhaustive match after applying the suggested lint (see
single_match
should not lint exhaustivematch
#8282 (comment) for context).match
constructions with tuples (as suggested atsingle_match
should not lint exhaustivematch
#8282 (comment))Closes #8282
changelog: [
single_match
]: Don't lint exhaustive enum patterns without a wild.changelog: [
single_match
]: Lintmatch
constructions with tuples