-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
.last()
to .next_back()
requires a mutable receiver
#14140
Conversation
Commits logically separated for easier review. |
5dfa493
to
fb033f1
Compare
Rebased |
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 one thing: I suppose we shouldn't just change it to be mutable in the suggestion? I'm not sure if there'd be any case that doesn't work/causes an error considering .last()
will already consume it.
Good question, let me try that, I'll switch to @rustbot author in the meantime. On an unrelated topic, I also realized that this lint should probably not be |
fb033f1
to
dd54d79
Compare
In the case of a structure or a tuple, |
dd54d79
to
33c9b51
Compare
33c9b51
to
e3dc09b
Compare
While it does change the meaning of the code, wouldn't any access already be a compiler error? If this doesn't always hold true I'll merge this |
Yes. I was just trying to say that if you own a struct or a tuple which isn't mutable, All other cases have been handled by making the object mutable when it designates the iterator. |
@Centri3 For cases where we don't want to make the structure or tuple mutable, we could still consume its value by creating a temporary that would be dropped at the end of the statement. For example, something like: fn f(x: (u32, RangeInclusive::<u32>)) -> u32 {
x.0 + x.1.last().unwrap()
} could be replaced by fn f(x: (u32, RangeInclusive::<u32>)) -> u32 {
x.0 + { x.1 }.next_back().unwrap()
} instead of not linting it. This is also an operation that would be also useful when fixing #14238. |
e3dc09b
to
99d6f9d
Compare
I've implemented the |
Well, ok, now one other thing: is suggesting to use a block really what we wanna do? I don't really recall ever seeing this intentionally done and honestly seems useless at a first glance (especially to beginners who may not understand the intricacies of this). I do not know how to properly state our thoughts! But I believe you understand. I believe we should lint this, but I want to bring up: Is this really worth it over just making it |
Agreed. Although this is a pattern I sometimes use in my code, this may not be common. Some others use
I will test alternatives when I get a chance. @rustbot author |
99d6f9d
to
90a87a6
Compare
90a87a6
to
7f560e9
Compare
In the case where `iter` is a `DoubleEndedIterator`, replacing a call to `iter.last()` (which consumes `iter`) by `iter.next_back()` (which requires a mutable reference to `iter`) cannot be done when `iter` Is not a mutable binding or a mutable reference. When `iter` is a local binding, it can be made mutable by fixing its definition site.
7f560e9
to
0fb429f
Compare
}, | ||
); | ||
if droppable_elements { | ||
diag.note("this might cause unretrieved elements to be dropped after the retrieved one"); |
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.
diag.note("this might cause unretrieved elements to be dropped after the retrieved one"); | |
diag.note("this change will alter drop order which may be undesirable"); |
I find this note to be unhelpful and too wordy. I think it doesn't put enough emphasis on the specific issue being drop order and even confuses me.
Feel free to make your own. Assuming this is the only change made ( 😅 ) I am happy with this version
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.
Feel free to make your own. Assuming this is the only change made ( 😅 ) I am happy with this version
I went with this change, and it has been pushed.
I also find this to be an ok alternative to suggest. |
`iter.last()` will drop all elements of `iter` in order, while `iter.next_back()` will drop the non-last elements of `iter` when `iter` goes out of scope since `.next_back()` does not consume its argument. When the transformation proposed by `double_ended_iterator_last` would concern an iterator whose element type has a significant drop, a note is added to warn about the possible drop order change, and the suggestion is switched from `MachineApplicable` to `MaybeIncorrect`.
0fb429f
to
dcd643a
Compare
In the case where
iter
is aDoubleEndedIterator
, replacing a call toiter.last()
(which consumesiter
) byiter.next_back()
(which requires a mutable reference toiter
) cannot be done wheniter
is a non-mutable binding which is not a mutable reference. When possible, a local immutable binding is made into a mutable one.Also, the applicability is switched to
MaybeIncorrect
and a note is added to the output when the element types have a significant drop, because the drop order will potentially be modified because.next_back()
does not consume the iterator nor the elements before the last one.Fix #14139
changelog: [
double_ended_iterator_last
]: do not trigger on non-reference immutable receiver, and warn about possible drop order change