Skip to content

or_fun_call isn't always a performance lint #8574

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

Open
hrxi opened this issue Mar 22, 2022 · 11 comments
Open

or_fun_call isn't always a performance lint #8574

hrxi opened this issue Mar 22, 2022 · 11 comments
Labels
A-category Area: Categorization of lints good first issue These issues are a good way to get started with Clippy L-nursery Lint: Currently in the nursery group

Comments

@hrxi
Copy link
Contributor

hrxi commented Mar 22, 2022

Replacing .unwrap_or(Vec::new()) with .unwrap_or_default() doesn't do anything for performance, they produce identical machine code with optimizations: https://rust.godbolt.org/z/hzTdazGqW.

Perhaps the lint category could be changed or it could be changed to not detect cases where it's not actually a performance warning?

@llogiq llogiq added good first issue These issues are a good way to get started with Clippy A-category Area: Categorization of lints labels Apr 18, 2022
@fedemartinezdev
Copy link
Contributor

@rustbot claim

@fedemartinezdev
Copy link
Contributor

Hi @hrxi !
I am new to contributing to rust-clippy.
Could you tell me where can I find the associated lint so I can begin to take a look? Thanks !

@xFrednet
Copy link
Member

xFrednet commented May 5, 2022

Hey @fedemartinezdev, welcome to Clippy 👋. In general we have Clippy's lint list which I use a lot. In this case, I searched for unwrap_or_default and found or_fun_call which is the mentioned lint. This issue requires some detective work to see if any of the cases are still better performance wise or if the entire lint group should be changed. For that, you might have to look at the implementation, to see how the lint internally works 🙃 See clippy_lints/src/methods/or_fun_call.rs

@fedemartinezdev fedemartinezdev removed their assignment Aug 3, 2022
@nikomatsakis
Copy link
Contributor

I ran into this same issue! It's not just Vec::new, I think the same would be true of HashMap::new and other standard library collections.

@hrxi
Copy link
Contributor Author

hrxi commented Nov 10, 2022

I just ran into more clippy suggestions where it doesn't improve performance:

String::from_utf8(vec).or(Err(Enum::InvalidUtf8))

Or a couple of others, the pattern is the same, .or(EnumVariant(PlainOldData)). Changing this to or_else doesn't do anything for performance.

hrxi added a commit to hrxi/rust-clippy that referenced this issue Nov 10, 2022
Also change its category to `style` so it's clear that it's not always a
performance lint.

Fixes rust-lang#8574.
hrxi added a commit to hrxi/rust-clippy that referenced this issue Nov 12, 2022
Also change its category to `style` so it's clear that it's not always a
performance lint.

Fixes rust-lang#8574.
hrxi added a commit to hrxi/rust-clippy that referenced this issue Nov 12, 2022
hrxi added a commit to hrxi/rust-clippy that referenced this issue Nov 12, 2022
Also move it to nursery so that the false-positives can be dealt with.

CC rust-lang#8574
hrxi added a commit to hrxi/rust-clippy that referenced this issue Nov 12, 2022
Also move it to nursery so that the false-positives can be dealt with.

CC rust-lang#8574
bors added a commit that referenced this issue Nov 13, 2022
Make it clear that `or_fun_call` can be a false-positive

Also move it to nursery so that the false-positives can be dealt with.

CC #8574

changelog: [`or_fun_call`]: Mention false-positives, move to nursery.
@smoelius
Copy link
Contributor

smoelius commented Jan 9, 2023

@hrxi Do you still have the full example? I am having trouble reproducing the behavior you described. For example, the following does not seem to trigger or_fun_call:

enum Enum {
    InvalidUtf8,
}
fn foo() -> Result<String, Enum> {
    let vec = Vec::new();
    String::from_utf8(vec).or(Err(Enum::InvalidUtf8))
}

@hrxi
Copy link
Contributor Author

hrxi commented Jan 9, 2023

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8df0162a2915322edfefceb3ca706ca7

#![warn(clippy::or_fun_call)]

use std::borrow::Cow;
fn foo() -> Result<String, Cow<'static, str>> {
    let vec = Vec::new();
    String::from_utf8(vec).or(Err(Cow::from("abc")))
}

fn main() { let _ = foo(); }
    Checking playground v0.0.1 (/playground)
warning: use of `or` followed by a function call
 --> src/main.rs:6:28
  |
6 |     String::from_utf8(vec).or(Err(Cow::from("abc")))
  |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|_| Err(Cow::from("abc")))`
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
note: the lint level is defined here
 --> src/main.rs:1:9
  |
1 | #![warn(clippy::or_fun_call)]
  |         ^^^^^^^^^^^^^^^^^^^

warning: `playground` (bin "playground") generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 0.42s

Haven't tried to minimize it.

@smoelius
Copy link
Contributor

smoelius commented Jan 9, 2023

Thanks!

@smoelius
Copy link
Contributor

smoelius commented Jan 9, 2023

I think my question was imprecise, though. I was looking for an example that produces equivalent code even when or_else is used. I have little experience with this sort of thing, but the just given example seems to produce different code when or_else is used: https://rust.godbolt.org/z/7dqzxMjYo

Am I making a mistake?

For context, I am trying to understand what is needed to move or_fun_call out of nursery. #10120, if merged, would mean things like .unwrap_or(Vec::new()) and .unwrap_or(HashMap::new()) are handled by a different lint. So I am wondering what false positives would then still remain for or_fun_call.

@hrxi
Copy link
Contributor Author

hrxi commented Jan 9, 2023

It seems you're not compiling with optimizations (-O).

I shortened the code a little and get equivalent assembly, the or_else version even seems (inconsequentially) longer: https://rust.godbolt.org/z/cj1EYhv4a

@smoelius
Copy link
Contributor

smoelius commented Jan 9, 2023

Thanks again!

@J-ZhengLi J-ZhengLi added the L-nursery Lint: Currently in the nursery group label Jul 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-category Area: Categorization of lints good first issue These issues are a good way to get started with Clippy L-nursery Lint: Currently in the nursery group
Projects
None yet
Development

No branches or pull requests

7 participants