-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New lint missing_iterator_fold
#12211
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
New lint missing_iterator_fold
#12211
Conversation
`cargo dev new_lint --name=missing_iterator_fold --pass=late`
|
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @blyxyas (or someone else) soon. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
|
a77a1b0 to
84b52f8
Compare
blyxyas
left a comment
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.
Very good first iteration! Thanks for the contribution, I have some small questions and nits, but this is a very good state.
|
|
||
| impl LateLintPass<'_> for MissingIteratorFold { | ||
| fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { | ||
| if rustc_middle::lint::in_external_macro(cx.sess(), item.span) { |
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.
We generally import this function
| .map(|assoc| assoc.ident.name.as_str()) | ||
| .any(|name| name == "fold"); |
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 map can be removed to avoid walking over the iterator (and allocating memory) more than necessary
| .map(|assoc| assoc.ident.name.as_str()) | |
| .any(|name| name == "fold"); | |
| .any(|assoc| assoc.ident.name.as_str() == "fold"); |
| /// ``` | ||
| #[clippy::version = "1.77.0"] | ||
| pub MISSING_ITERATOR_FOLD, | ||
| nursery, |
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.
Hmmmm... what category do you think that this should be? I'm thinking about perf, but the lint may be too demanding to be put in perf
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 is definitely about performance but there is also pedantic because this is "rather strict".
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.
Is this actually actionable in all cases? As in, can you always provide a more useful implementation than the default fold implementation? Because if not, I'd go as far as saying it could be a restriction lint. For example, std's Range Iterator implementation also does not implement fold and I'm not sure how/why it should
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 don't see a reason why specialize fold would necessarily improve performance in the general case. It certainly is in some cases but not all.
This is definitely a lint that should be allowed in some cases after some consideration (and benchmark). This is exactly our case at rust-itertools.
Not sure why either about Range (while RangeInclusive does if I remember well).
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 updated the category to restriction.
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.
Just for the sake of completion, could you add another struct but implement fold, just to make sure that it doesn't lint then?
|
@blyxyas Hi! Each point was addressed. Is there anything else or should I just squash my commits? (and rebase?) Should I suggest a blank |
I don't think so, that would prompt users to just leave it unchanged.
Hmmmm... These should be the same lint imo. Creating 3 - 4 lints just for slightly different methods would be... Also, do you have an example where manually implementing |
|
rust-itertools/itertools#775 had benchmarks 34 times faster but that's the exception. Most other Have a single lint for However, I clearly understand that you don't want a bunch of lints.
Leading to a total of three lints (in a same lint pass). Most I think that specialize those are good practices and can have huge impact on the EDIT: Maybe merge EDIT 2: |
|
Before this PR, I took advice on zulip and the discussion here eventually took place back on zulip. |
fixes #12209
Specialize
foldmight improve performance of methods relying on it and other iterator adaptors callingfold.changelog: [
missing_iterator_fold]: Check thatIteratorimplementations specialize thefoldmethod.I am still questioning myself about the lint name, is "missing" appropriate?
I am unsure if
in_external_macrocheck is needed or not in this situation.Note: I would (later) suggest similar lints for
DoubleEndedIterator::rfold(andIterator::try_fold/DoubleEndedIterator::try_rfoldexcept they currently can't be specialized on Rust stable since the traitTryis still unstable) andIterator::size_hint. All those lints could solved with a singleLateLintPass.