Skip to content

Fixes a collapsible_match false positive where the suggested fix turned an exhaustive match into a non-exhaustive one.#16911

Open
Souradip121 wants to merge 3 commits intorust-lang:masterfrom
Souradip121:fix-collapsible-match-drops-else
Open

Fixes a collapsible_match false positive where the suggested fix turned an exhaustive match into a non-exhaustive one.#16911
Souradip121 wants to merge 3 commits intorust-lang:masterfrom
Souradip121:fix-collapsible-match-drops-else

Conversation

@Souradip121
Copy link
Copy Markdown
Contributor

@Souradip121 Souradip121 commented Apr 25, 2026

When the inner if cond { A } else { B } was collapsed into a guarded outer arm and the
outer "wild-like" sibling arm was None (a constructor pattern, not a true catch-all),
the suggestion dropped the inner else body and produced a match that no longer
covered Some(_) when the guard failed.

Closes #16910

What changed

arm_is_wild_like accepts Wild, Binding, and OptionNone. The first two are
true catch-alls; OptionNone is wild-LIKE but only matches None, so it cannot catch
a Some(_) value falling through from a guarded Some(_) arm above.

Path B (inner plain if) was already gated on only_wildcards_after (added in #16875
to handle a similar case where a _ if cond arm intercepts the fall-through). That gate
has been tightened: every arm after the one being collapsed must be unconditional with
a _ or binding pattern
, and at least one such arm must exist. This catches both the
prior _ if cond case and the new None case.

Reproducer (from the issue, simplified)

Before the fix the lint suggested:

// original (compiles)
match self.temp {
    None => { fs::rename(self.source, dest)?; }
    Some(temp) => {
        if dest.exists() { /* ... uses temp */ }
        else { fs::rename(self.source, dest)?; }
    }
};

// suggested (does NOT compile - `Some(temp) if !dest.exists()` is unhandled)
match self.temp {
    None => { fs::rename(self.source, dest)?; }
    Some(temp) if dest.exists() => { /* ... */ }
};

After the fix the lint stays silent on this shape.

Conditions for the if-guard collapse to fire

  • the outer is a match
  • every arm after the one being collapsed is unconditional and has a _ or binding
    pattern, and there is at least one such arm
  • (existing conditions: else bodies are equivalent, no binding moved/mutated in the new
    guard, etc.)

changelog: [collapsible_match]: no longer suggests a fix that drops an else branch when the fall-through arm is wild-LIKE (e.g. None) but not a true catch-all

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Apr 25, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 25, 2026

r? @dswij

rustbot has assigned @dswij.
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: 7 candidates
  • 7 candidates expanded to 7 candidates
  • Random selection from Jarcho, dswij, llogiq

@github-actions
Copy link
Copy Markdown

Lintcheck changes for a91feec

Lint Added Removed Changed
clippy::collapsible_match 0 3 0

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.

collapsible_match ignore "else" when fixing an if statement

3 participants