Skip to content
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

Suggest Option::map_or(_else) for if let Some { y } else { x } #5301

Merged
merged 14 commits into from
Jul 6, 2020

Conversation

JarredAllen
Copy link
Contributor

@JarredAllen JarredAllen commented Mar 11, 2020

Fixes #5203

There are two issues with this code that I have noticed:

  • Use of Option::map_or causes it to always evaluate the code in the else block. If that block is computationally expensive or if it updates some state (such as getting the next value from an iterator), then this change would cause the code to behave differently. In either of those circumstances, it should suggest Option::map_or_else, which takes both cases as a closure and runs one. However, I don't know how to check if the expression would change some state, so I left the lint's applicability as MaybeIncorrect.

  • There are lints which can trigger on specific sub-cases of this lint (if_let_some_result, question_mark, and while_let_loop) and suggest different changes (usually better ones because they're more specific). Is this acceptable for clippy to give multiple suggestions, or should I have the code check if those other lints trigger and then not trigger this lint if they do?

changelog: Add lint [option_if_let_else]

@flip1995
Copy link
Member

For your first point, there's a pretty simple solution: If the block has statements (besides the returning expression), then you should suggest map_or_else(|| { /* else block */ }, ...). If the else block only contains a returning expression, you can suggest map_or(expr, ...). If this expression is then a function call, that can have side effects, the or_fun_call lint will take care of this afterwards.

For your second point. The if_let_some_result lint and this lint should not trigger at the same time, but the if_let_some_result should be prioritized. Since both lints address if let Some(..) = expr constructs, maybe you can reuse some code of this lint and the if_let_some_result lint and don't trigger this lint, if the if_let_some_result is triggered.

For the other two: This new lint should never trigger, if there is a break, continue, or return statement in one of the if/else blocks, since using a closure for this won't work. (Well, maybe it works for break/continue, but I'm not sure how they behave in a closure. I think break/continue are at least confusing in a closure, if they aren't in a loop inside the closure)

@flip1995 flip1995 added the S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) label Mar 11, 2020
@bors
Copy link
Contributor

bors commented Mar 23, 2020

☔ The latest upstream changes (presumably #5319) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Mar 30, 2020

☔ The latest upstream changes (presumably #5294) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Apr 8, 2020

☔ The latest upstream changes (presumably #5438) made this pull request unmergeable. Please resolve the merge conflicts.

@JarredAllen
Copy link
Contributor Author

I pulled the changes which happened in the master branch while I was gone (sorry for the delay, I had things to deal with involving COVID-19, but everything's fine now), and now, when I try to build, it complains:

error[E0463]: can't find crate for rustc_hir_pretty

I've tried everything I can think of to make it appear, but nothing seems to make it work. If it matters, here's the output of running cargo --version and rustc --version on my machine:

cargo 1.43.0-nightly (e57bd0299 2020-02-21)

rustc 1.43.0-nightly (beac68a88 2020-03-01)

Is there anything that I need to do to make that crate appear?

@JarredAllen
Copy link
Contributor Author

Failed tests are ui/author/blocks.rs and ui/swap.rs, and I didn't mess with either of those lints, so I think this is ready to merge.

@JarredAllen JarredAllen changed the title (WIP) Suggest Option::map_or(_else) for if let Some { y } else { x } Suggest Option::map_or(_else) for if let Some { y } else { x } Apr 14, 2020
@flip1995 flip1995 self-requested a review April 15, 2020 13:39
@flip1995 flip1995 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties and removed S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) labels Apr 15, 2020
Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for taking so long for the review. I don't have an excuse, just wasn't really motivated to review PRs recently.

clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
tests/ui/author/blocks.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
tests/ui/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
@flip1995
Copy link
Member

To get the latest rustc toolchain, you should run sh setup-toolchain.sh, which will install the current rustc master toolchain for you.

@flip1995 flip1995 added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Apr 15, 2020
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
clippy_lints/src/option_if_let_else.rs Outdated Show resolved Hide resolved
tests/ui/swap.rs Outdated Show resolved Hide resolved
@flip1995
Copy link
Member

After undoing the change to tests/ui/swap.rs and a rebase(+squash) to get rid of the merge commit and this is ready to go.

@JarredAllen JarredAllen force-pushed the option_if_let_else branch 2 times, most recently from d074cdd to f958879 Compare April 16, 2020 20:22
@bors
Copy link
Contributor

bors commented Apr 17, 2020

☔ The latest upstream changes (presumably #5423) made this pull request unmergeable. Please resolve the merge conflicts.

@flip1995
Copy link
Member

@bors r+

Thanks!

@bors
Copy link
Contributor

bors commented Apr 17, 2020

📌 Commit ff4da34 has been approved by flip1995

@bors
Copy link
Contributor

bors commented Apr 17, 2020

⌛ Testing commit ff4da34 with merge ed748d3...

bors added a commit that referenced this pull request Apr 17, 2020
Suggest `Option::map_or`(_else) for `if let Some { y } else { x }`

Fixes #5203

There are two issues with this code that I have noticed:

- Use of `Option::map_or` causes it to always evaluate the code in the else block. If that block is computationally expensive or if it updates some state (such as getting the next value from an iterator), then this change would cause the code to behave differently. In either of those circumstances, it should suggest Option::map_or_else, which takes both cases as a closure and runs one. However, I don't know how to check if the expression would change some state, so I left the lint's applicability as MaybeIncorrect.

- There are lints which can trigger on specific sub-cases of this lint (`if_let_some_result`, `question_mark`, and `while_let_loop`) and suggest different changes (usually better ones because they're more specific). Is this acceptable for clippy to give multiple suggestions, or should I have the code check if those other lints trigger and then not trigger this lint if they do?
@bors
Copy link
Contributor

bors commented Apr 17, 2020

💔 Test failed - checks-action_test

@flip1995
Copy link
Member

flip1995 commented Apr 17, 2020

There are a lot of findings in the Clippy codebase itself. You should be able to use cargo clippy --fix -Zunstable-options to fix this. This will do the job (under Linux):

$ cargo +master install --path . --force  # Install Clippy
$ cp ~/.cargo/bin/*clippy* ~/.rustup/toolchains/master/bin  # Make Clippy available in the master toolchain
$ export LD_LIBRARY_PATH=$(rustc +master --print sysroot)/lib  # Set library path
$ cd clippy_lints
$ cargo +master clippy --fix -Zunstable-options  # Fix findings with the previously installed clippy
$ cd -
$ cargo dev fmt  # reformat codebase

@bors
Copy link
Contributor

bors commented Jun 30, 2020

☔ The latest upstream changes (presumably #5751) made this pull request unmergeable. Please resolve the merge conflicts.

@JarredAllen JarredAllen force-pushed the option_if_let_else branch from 890e4b6 to d9fe3b0 Compare July 1, 2020 18:37
@flip1995
Copy link
Member

flip1995 commented Jul 3, 2020

Thanks for rebasing! There's again some fallout of the rebase (cx.tables->cx.tables()). I want to prioritize merging this PR, since it modifies multiple files across the codebase, so please ping me after you addressed the fallout (force pushes tend to not show up in GH notifications).

@bors
Copy link
Contributor

bors commented Jul 3, 2020

☔ The latest upstream changes (presumably #5763) made this pull request unmergeable. Please resolve the merge conflicts.

@JarredAllen JarredAllen force-pushed the option_if_let_else branch from 72e88af to 1c32263 Compare July 4, 2020 03:28
@JarredAllen JarredAllen force-pushed the option_if_let_else branch from 020cc8c to c8f700e Compare July 4, 2020 04:22
@JarredAllen
Copy link
Contributor Author

@flip1995 Sorry for the delay. I had to force-push without it quite working yet because something broke on my machine that causes it to randomly fail a test in the middle, so using the automatic Travis testing was the only way I could actually test it. But it passes all the tests now, so it should finally be good to merge.

@flip1995
Copy link
Member

flip1995 commented Jul 6, 2020

@bors r+ p=10

Thanks!

@bors
Copy link
Contributor

bors commented Jul 6, 2020

📌 Commit c8f700e has been approved by flip1995

@bors
Copy link
Contributor

bors commented Jul 6, 2020

⌛ Testing commit c8f700e with merge ac85692...

@bors
Copy link
Contributor

bors commented Jul 6, 2020

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: flip1995
Pushing ac85692 to master...

@Arnavion
Copy link
Contributor

FYI, issues arising from this lint:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Suggest Option::map_or(_else) for if let Some { y } else { x }
4 participants