Skip to content

Add let_else_ok_or lint#17207

Open
sylvestre wants to merge 2 commits into
rust-lang:masterfrom
sylvestre:let_else_ok_or
Open

Add let_else_ok_or lint#17207
sylvestre wants to merge 2 commits into
rust-lang:masterfrom
sylvestre:let_else_ok_or

Conversation

@sylvestre

Copy link
Copy Markdown
Contributor

New style lint that detects let...else statements binding the payload of an Option whose else branch only does return Err(<expr>), and suggests the more concise Option::ok_or/ok_or_else with the ? operator:

let Some(value) = opt else {
    return Err("missing");
};
// ->
let value = opt.ok_or("missing")?;

ok_or_else is suggested when the error value is non-trivial, to preserve the laziness of the original else branch. The lint bails on ref bindings, comments or #[cfg] in the else branch, and return Err(..) expressions produced by a macro expansion (e.g. anyhow::bail!), where the error value cannot be rendered into a sound suggestion.

changelog: Add let_else_ok_or lint

@rustbot rustbot added needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Jun 10, 2026
@rustbot

rustbot commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

r? @samueltardieu

rustbot has assigned @samueltardieu.
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

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: 8 candidates
  • 8 candidates expanded to 8 candidates
  • Random selection from Jarcho, dswij, llogiq, samueltardieu

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

Lintcheck changes for 05c9949

Lint Added Removed Changed
clippy::let_else_ok_or 3 0 0

This comment will be updated if you push new changes

@rustbot

This comment has been minimized.

@samueltardieu samueltardieu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The lint will suggest code that doesn't compile in const contexts, such as:

const fn f(a: Option<u32>) -> Result<u32, ()> {
    let Some(a) = a else {
        return Err(());
    };
    Ok(a)
}

You should check that:

  • either you are not in a const context
  • or the three features const_try, const_trait_impl and const_option_ops are enabled (you can do the test once and store the result in the LetElseOkOr struct, and use impl_lint_pass! instead of declare_lint_pass!)

View changes since this review

Comment thread clippy_lints/src/let_else_ok_or.rs
Comment thread clippy_lints/src/let_else_ok_or.rs
@rustbot rustbot 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 Jun 11, 2026
@rustbot

rustbot commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

New `style` lint that detects `let...else` statements binding the payload
of an `Option` whose `else` branch only does `return Err(<expr>)`, and
suggests the more concise `Option::ok_or`/`ok_or_else` with the `?`
operator:

    let Some(value) = opt else {
        return Err("missing");
    };
    // ->
    let value = opt.ok_or("missing")?;

`ok_or_else` is suggested when the error value is non-trivial, to preserve
the laziness of the original `else` branch. The lint bails on `ref`
bindings, comments or `#[cfg]` in the `else` branch, and `return Err(..)`
expressions produced by a macro expansion (e.g. `anyhow::bail!`), where
the error value cannot be rendered into a sound suggestion.

`ok_or`/`ok_or_else` move the error value unconditionally, whereas the
`else` branch only runs on `None`. When the error value moves a non-`Copy`
local that is still used on the `Some` path (or could be moved again across
a loop iteration), the rewrite would reference a moved value and not
compile, so the suggestion is downgraded to non-machine-applicable in that
case (values that are merely borrowed, e.g. `Err(format!("{x}"))`, stay
machine-applicable). The error snippet is rendered through the statement's
context so an error value that is itself a macro call (`format!(..)`) is
shown as written instead of leaking its expansion internals.
@rustbot

rustbot commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

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.

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

Labels

needs-fcp PRs that add, remove, or rename lints and need an FCP 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.

3 participants