Add & use is_none_or Option extension in the compiler#111873
Add & use is_none_or Option extension in the compiler#111873WaffleLapkin wants to merge 5 commits into
is_none_or Option extension in the compiler#111873Conversation
|
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.
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.
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.
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.
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.
| 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()) | |
| { |
| // 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.
| 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()) { |
| // 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.
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 |
…=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/rust#111873 (comment)
…=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/rust#111873 (comment)
This adds an extension to
Optionwhich lives in therustc_data_structuresand provides ais_none_ormethod, similarly to theOption::is_some_andthat already exists.IMHO
is_none_ormakes the code a lot more readable than.map_or(true, ...)which it replaces here.