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.
But I also modified can_partially_move_ty to make Ref return false.

@github-actions
Copy link

github-actions bot commented Dec 3, 2025

Lintcheck changes for 5377dba

Lint Added Removed Changed
clippy::if_then_some_else_none 0 7 2
clippy::manual_map 1 0 0
clippy::option_if_let_else 75 0 8

This comment will be updated if you push new changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties

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

4 participants