-
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
add lint manual_unwrap_or #6123
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
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.
Left some thoughts
6964d54
to
eba5886
Compare
@ebroto all your remarks should be addressed. |
795e34a
to
7b3074f
Compare
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 some very minor nits. Also we should rebase to get rid of the merge commits.
7b3074f
to
5cd2689
Compare
Last comments were addressed. |
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.
So, I've been playing with the lint a bit and I think I found a problematic case.
The unwrap_or/else
methods take self
by value, while match
does not need to move the scrutinee. If the scrutinee is mutable and is modified in the None
arm, after applying the lint we get a use-after-move
error:
struct NonCopyable;
fn main() {
let mut option: Option<NonCopyable> = None;
match option {
Some(x) => x,
None => {
option = Some(NonCopyable);
// some more code ...
option.unwrap()
},
};
}
is turned into:
struct NonCopyable;
fn main() {
let mut option: Option<NonCopyable> = None;
option.unwrap_or_else(|| {
option = Some(NonCopyable);
// some more code ...
option.unwrap()
});
}
I see at least two options:
- We check that the
T
inOption<T>
isCopy
, otherwise we bail out - We check that the
None
arm is not modifying the scrutinee.
I'm more hesitant about making the lint enabled by default for now, I think we might be missing other stuff when turning an arm value into a closure. What do you think?
Great catch! @ebroto Here is another problem related to ownership: fn main() {
let option: Option<&str> = None;
match option {
Some(s) => s,
None => &format!("{} {}!", "hello", "world"),
};
option.unwrap_or_else(|| {
// compilation error here, it can't return a reference to a value owned by the closure body
&format!("{} {}!", "hello", "world")
});
} Indeed, the risk of hitting an ownership bug is high no matter what exception rules we put in place. |
Oh, right, that one is more probable :) Indeed, let's be safe and lint only the |
d5de6c5
to
094da21
Compare
094da21
to
690a6a6
Compare
The unwrap_or_else suggestions are removed. |
@bors r+ Thanks! |
📌 Commit 690a6a6 has been approved by |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Implements partially #5923.
changelog: add lint manual_unwrap_or