-
Notifications
You must be signed in to change notification settings - Fork 1.7k
unwrap_or_else_default
-> unwrap_or_default
and improve resulting lint
#10120
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
Conversation
r? @flip1995 (rustbot has picked a reviewer for you, use r? to override) |
5864200
to
8b1c3e2
Compare
☔ The latest upstream changes (presumably #10184) made this pull request unmergeable. Please resolve the merge conflicts. |
@flip1995 Would it be helpful if I split this into two PRs: one for the false positive fix (the biggest change), and one for everything else? |
"try this" -> "try" Current help messages contain a mix of "try", "try this", and one "try this instead". In the spirit of #10631, this PR adopts the first, as it is the most concise. It also updates the `lint_message_conventions` test to catch cases of "try this". (Aside: #10120 unfairly contained multiple changes in one PR. I am trying to break that PR up into smaller pieces.) changelog: Make help messages more concise ("try this" -> "try").
Fix `unwrap_or_else_default` false positive This PR fixes a false positive in the handling of `unwrap_or_else` with a default value when the value is needed for type inference. An easy example to exhibit the false positive is the following: ```rust let option = None; option.unwrap_or_else(Vec::new).push(1); ``` The following code would not compile, because the fact that the value is a `Vec` has been lost: ```rust let option = None; option.unwrap_or_default().push(1); ``` The fix is to: - implement a heuristic to tell whether an expression's type can be determined purely from its subexpressions, and the arguments and locals they use; - apply the heuristic to `unwrap_or_else`'s receiver. The heuristic returns false when applied to `option` in the above example, but it returns true when applied to `option` in either of the following examples: ```rust let option: Option<Vec<u64>> = None; option.unwrap_or_else(Vec::new).push(1); ``` ```rust let option = None::<Vec<u64>>; option.unwrap_or_else(Vec::new).push(1); ``` (Aside: #10120 unfairly contained multiple changes in one PR. I am trying to break that PR up into smaller pieces.) --- changelog: FP: [`unwrap_or_else_default`]: No longer lints if the default value is needed for type inference
@flip1995 Is this PR more reasonable now? |
Sorry, I don't have time to review currently. It would take be too long, even though the PR size now looks better. r? @blyxyas do you mind taking over? |
Failed to set assignee to
|
I don't mind taking over. Even better, I will take over. Yeehaw 🤠 |
@bors delegate=blyxyas In case you're quicker with the review, than getting your bors rights. Thanks for taking over! :) |
Oh, rust-lang/team#1031 just got merged 🎉 |
Nice, now you have all the rights and with #11194 you'll be picked as a reviewer automatically in the future. |
@bors r? blyxyas |
The |
/// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and | ||
/// `Result` values. | ||
/// Checks for usages of the following functions with an argument that constructs a default value | ||
/// (e.g., `Default::default` or `String::new`): |
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.
/// (e.g., `Default::default` or `String::new`): | |
/// (e.g. `Default::default` or `String::new`): |
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.
Both are correct and used a similar amount of times in rustc (512 without the comma vs 680 with the comma). The preferred spelling differs from place to place though.
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 a personal preference, but I feel like it's weird to have 2 punctuation signs right next to each other and it kinda worsens readability.
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 personally find it easier to read as it keeps the punctuation mark only being used at the end of a sentence. That's subjective though ^^
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 feel like it's weird to have 2 punctuation signs right next to each other
@blyxyas Personally, I agree with you 100%.
But literally every English writing guide I have consulted says to put a ',' after "e.g.".
So I think the question comes down to: should Clippy comments follow English writing guides?
(And, to state the obvious, this is a total bike shed. 😀)
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'm fine with either. It's bikeshedding and won't cause confusion anyway.
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 American English, a comma is always placed after “i.e.” or “e.g.” In fact, this is a punctuation rule on which both the AP Style Book and the Chicago Manual of Style agree. However, in British English, a comma is not used after “i.e.” or “e.g.”
Mmmm... Guess it doesn't matter. It just looks weird, I don't know and honestly, it isn't that big of a problem.
We can continue designing the power plant, do what you consider the best 🤠
if let Some(sugg) = match (name, call_expr.is_some()) { | ||
("unwrap_or", true) | ("unwrap_or_else", false) => Some("unwrap_or_default"), | ||
("or_insert", true) | ("or_insert_with", false) => Some("or_default"), | ||
_ => None, | ||
}; |
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 if statement could be replaced by an early return (the compiler probably optimizes this, but just to be sure)
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 the change I made the one you had in mind?
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.
Yes :)
if body.params.is_empty() | ||
&& let hir::Expr{ kind, .. } = &body.value | ||
&& let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind | ||
&& ident == &symbol::Ident::from_str("to_string") |
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.
Unnecessary allocation here 🐄
&& ident == &symbol::Ident::from_str("to_string") | |
&& ident.name == sym::to_string |
I think this is pretty much ready. Just a final question, @xFrednet, what do you mean by "Not handles more functions" 😅 |
@blyxyas this confused me for a solid minute ^^. It's just the usual amount of typos in my artfully crafted changelog entries. You noticed it and passed the test 😉. Here have a Cookie: 🍪 |
Okis ^w^ |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Thanks very much for the review, @blyxyas. |
Resolves #10080 (though it doesn't implement exactly what's described there)
This PR does the following:
unwrap_or_else_default.rs
's code intoor_fun_call.rs
unwrap_or(/* default value */)
and similar, and moves it intounwrap_or_else_default
Entry::or_default
forEntry::or_insert(Default::default())
#9342, e.g.,, to handleor_insert_with(Default::default)
unwrap_or_else_default
tounwrap_or_default
(since the "new" lint handles bothunwrap_or
andunwrap_or_else
, it seemed sensible to use the shortened name)This PR is currently two commits. The first implements 1-3, the second implements 4.
A word about 2: the
or_fun_call
lint currently produces warnings like the following:To me, such warnings look like they should come from
unwrap_or_else_default
, notor_fun_call
, especially sinceor_fun_call
is in the nursery.changelog: Move: Renamed
unwrap_or_else_default
to [unwrap_or_default
]#10120
changelog: Enhancement: [
unwrap_or_default
]: Now handles more functions, likeor_insert_with
#10120