-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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 & use is_none_or
Option
extension in the compiler
#111873
Add & use is_none_or
Option
extension in the compiler
#111873
Conversation
r? @cjgillot (rustbot has picked a reviewer for you, use r? to override) |
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri |
why do you add this to |
d7468b2
to
1c8ca38
Compare
This comment has been minimized.
This comment has been minimized.
1c8ca38
to
3bd865c
Compare
Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 |
I don't think this is worth it with the requirement to add an extension trait. I am open to throw this to the libs team with the added rationale of this PR, but as is this PR doesn't feel great to me. |
…mpiler, r=petrochenkov Use `Option::is_some_and` and `Result::is_ok_and` in the compiler `.is_some_and(..)`/`.is_ok_and(..)` replace `.map_or(false, ..)` and `.map(..).unwrap_or(false)`, making the code more readable. This PR is a sibling of rust-lang#111873 (comment)
☔ The latest upstream changes (presumably #111918) made this pull request unmergeable. Please resolve the merge conflicts. |
.session | ||
.source_map() | ||
.span_to_snippet(span) | ||
.map(|snippet| snippet.starts_with("#[")) | ||
.unwrap_or(true); | ||
.map_or(true, |snippet| snippet.starts_with("#[")); | ||
if !is_macro_callsite { |
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.
Since this condition is only used inverted, it might be easier to read to just use is_some_and
with the inverted condition:
if self
.session
.source_map()
.span_to_snippet(span)
.is_some_and(|snippet| !snippet.starts_with("#["))
{
Then it clearly reads as "if the snippet is available and doesn't start with #[
".
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.
Good catch, thanks!
(as a side note span_to_snippet
returns a result, so this would have to be a is_ok_and
, but yeah)
let lifetime_only_in_expanded_code = | ||
deletion_span.map(|sp| sp.in_derive_expansion()).unwrap_or(true); | ||
deletion_span.is_none_or(|sp| sp.in_derive_expansion()); | ||
if !lifetime_only_in_expanded_code { |
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.
Here's another case where the condition is inverted, such that is_some_and
might be easier to read:
if deletion_span.is_some_and(|sp| !sp.in_derive_expansion()) {
"If the deletion span is not in a derive expansion, then .."
attr.ident().map_or(true, |ident| { | ||
attr.ident().is_none_or(|ident| { | ||
ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name) | ||
}) |
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.
maybe_needs_tokens
only ever seems to be used as !maybe_needs_tokens
, so maybe this function should be inverted:
// name to be bikeshed
pub fn is_complete(attrs: &[ast::Attribute]) -> bool {
attrs.iter().all(|attr| {
attr.is_doc_comment() || attr.ident().is_some_and(|ident| {
ident.name != sym::cfg_attr && rustc_feature::is_builtin_attr_name(ident.name)
})
})
}
"The attributes are complete if all tokens are either a doc comment or a builtin attribute other than cfg_attr."
if self | ||
.prev_expn_span | ||
.is_none_or(|prev_expn_span| self.curr().expn_span.ctxt() != prev_expn_span.ctxt()) | ||
{ |
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.
if self | |
.prev_expn_span | |
.is_none_or(|prev_expn_span| self.curr().expn_span.ctxt() != prev_expn_span.ctxt()) | |
{ | |
if !self | |
.prev_expn_span | |
.is_some_and(|prev_expn_span| self.curr().expn_span.ctxt() == prev_expn_span.ctxt()) | |
{ |
@@ -382,7 +383,7 @@ impl BasicCoverageBlockData { | |||
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also | |||
// have an expression (to be injected into an existing `BasicBlock` represented by this | |||
// `BasicCoverageBlock`). | |||
if !self.counter_kind.as_ref().map_or(true, |c| c.is_expression()) { | |||
if !self.counter_kind.as_ref().is_none_or(|c| c.is_expression()) { |
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.
if !self.counter_kind.as_ref().is_none_or(|c| c.is_expression()) { | |
if self.counter_kind.as_ref().is_some_and(|c| !c.is_expression()) { |
@@ -389,7 +390,7 @@ pub fn struct_lint_level( | |||
// if this lint occurs in the expansion of a macro from an external crate, | |||
// allow individual lints to opt-out from being reported. | |||
let not_future_incompatible = | |||
future_incompatible.map(|f| f.reason.edition().is_some()).unwrap_or(true); | |||
future_incompatible.is_none_or(|f| f.reason.edition().is_some()); |
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 not_
prefix of the name here also hints at an inverted condition that might be easier to read:
let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none());
@WaffleLapkin any updates on this? |
@Dylan-DPC this is waiting on me figuring out if the method is actually useful. Mara showed that it can be often replaced by |
I recently wanted something like IMO it is the obvious dual to |
This seems like a repeating pattern:
Yes! That's why I was/am advocating for it =) |
#115111 is an example that would benefit from Grepping for |
I have some code that vaguely looks like this: iter.filter(|element| !element.date.is_some_and(|date| date != today)) where I want to iterate over all the elements that are from today or don't have a date. Having to negate a couple of times to get the De Morgan equivalent doesn't read well at all. iter.filter(|element| element.date.is_none_or(|date| date == today)) reads so much better. It's a pretty well known rule to avoid double negatives in writing because it makes it harder to understand. So I'm honestly baffled by the push back here. |
I do want to return to this and thoughtfully re-check if |
I just had another usecase, where I ended up writing // If the newly promised alignment is bigger than the native alignment of this
// allocation, and bigger than the previously promised alignment, then set it.
if align > alloc_align
&& !alloc_extra
.symbolic_alignment
.get()
.is_some_and(|(_, old_align)| align <= old_align) but having to use de Morgan and // If the newly promised alignment is bigger than the native alignment of this
// allocation, and bigger than the previously promised alignment, then set it.
if align > alloc_align
&& alloc_extra
.symbolic_alignment
.get()
.is_none_or(|(_, old_align)| align > old_align) |
Another data point: rust analyzer has a surprising amount of
And to me it looks like in a lot of them |
This adds an extension to
Option
which lives in therustc_data_structures
and provides ais_none_or
method, similarly to theOption::is_some_and
that already exists.IMHO
is_none_or
makes the code a lot more readable than.map_or(true, ...)
which it replaces here.