8000 Fix `if_then_some_else_none` FP when encountering `await` codes by relaxcn · Pull Request #16178 · rust-lang/rust-clippy · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@relaxcn
Copy link
Contributor
@relaxcn relaxcn commented Dec 2, 2025

changelog: Fix FP of [if_then_some_else_none] when the then block contains await codes.

That is because bool:then doesn't work with await code.

Closes: #16176

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Dec 2, 2025
@rustbot
Copy link
Collaborator
rustbot commented Dec 2, 2025

r? @Jarcho

rustbot has assigned @Jarcho.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot

This comment has been minimized.

Comment on lines 82 to 94
&& !contains_return(then_block.stmts)
&& then_block.expr.is_none_or(|expr| !contains_return(expr))
&& then_block.expr.is_none_or(|expr| {
!contains_return(expr)
// `bool::then` doesn't work with async code
&& for_each_expr_without_closures(expr, |e| {
if desugar_await(e).is_some() {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
})
.is_none()
})
Copy link
Member

Choose a reason for hiding this comment

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

Could we just use can_move_expr_to_closure on the then expression here? I'm not sure if it would introduce FNs but it seems like it answers exactly the question of "can we move that code into a closure", taking into account control flow constructs and the like (yield, return, continue, break, ...).

Copy link
Member

Choose a reason for hiding this comment

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

There's also a bug in the current logic here because it only runs the visitor on the tail expression and not the statements, so it would miss await in statements of the block.

If can_move_expr_to_closure doesn't work out it might still be better to remove the contains_return and instead just have a single for_each_expr_without_closures on the block that checks for everything we want to ignore. That saves us from visiting the whole block twice.

Rather than using desugar_await(e).is_some() it might also be better to just check for ExprKind::Yield since that's ultimately the root cause. It also can't really be used in bool::then and await uses yield.

Copy link
Contributor Author
@relaxcn relaxcn Dec 3, 2025

Choose a reason for hiding this comment

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

Thank you. I think we need to use can_move_expr_to_closure consistently.
And I also modified can_partially_move_ty to make Ref return false because Ref can't be moved partially.

@github-actions
Copy link
github-actions bot commented Dec 3, 2025

No changes for 6159c19

@rustbot

This comment has been minimized.

@ada4a
Copy link
Contributor
ada4a commented Dec 5, 2025

The new FP in manual_map is only partially related to these changes:

  • It looks like can_move_expr_to_closure fails to notice the use of input inside trace!, most likely because the latter expands to nothing, and thus wrongly returns true.
  • But in theory, manual_map should've avoided linting by itself, as it shouldn't lint then-block which contains statements (in this case, the trace!), but doesn't, as it doesn't notice trace!, as it expands to nothing.

Opened a separate issue for the latter: #16193

@relaxcn
Copy link
Contributor Author
relaxcn commented Dec 5, 2025

The new FP in manual_map is only partially related to these changes:

  • It looks like can_move_expr_to_closure fails to notice the use of input inside trace!, most likely because the latter expands to nothing, and thus wrongly returns true.
  • But in theory, manual_map should've avoided linting by itself, as it shouldn't lint then-block which contains statements (in this case, the trace!), but doesn't, as it doesn't notice trace!, as it expands to nothing.

Opened a separate issue for the latter: #16193

Yes. The new issue #16193 seems to be caused by can_move_expr_to_closure returns true wrongly.

Even though the manual_map could prevent it in the early age, I prefer to improve can_move_expr_to_closure to keep the lint code simple.

gauravagerwala added a commit to gauravagerwala/rust-clippy that referenced this pull request Dec 7, 2025
@Jarcho
Copy link
Contributor
Jarcho commented Dec 9, 2025

The change to can_partially_move_ty is causing the new FPs in option_if_let_else. Those will have to be fixed before this can be merged. manual_map has a partial workaround for the lack of lifetime checking that should be enough.

@rustbot
Copy link
Collaborator
rustbot commented Dec 9, 2025

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@relaxcn
8000 Copy link
Contributor Author
relaxcn commented Dec 9, 2025

The change to can_partially_move_ty is causing the new FPs in option_if_let_else. Those will have to be fixed before this can be merged. manual_map has a partial workaround for the lack of lifetime checking that should be enough.

Agree. I've made minimal changes this time.

Copy link
Contributor
@Jarcho Jarcho left a comment

Choose a reason for hiding this comment

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

I'll take the current form as it fixes the issue, but I would like to see the original fix after the regressions are fixed.

Thank you.

View changes since this review

@Jarcho Jarcho added this pull request to the merge queue Dec 12, 2025
Merged via the queue into rust-lang:master with commit 89aeed1 Dec 12, 2025
11 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

if_then_some_else_none triggers even though code contains .await in the if branch

5 participants

0