Skip to content

Report error for irrefutable patterns that make remaining match patterns unreachable - #21926

Open
haeganm wants to merge 1 commit into
python:masterfrom
haeganm:match-irrefutable-patterns
Open

Report error for irrefutable patterns that make remaining match patterns unreachable#21926
haeganm wants to merge 1 commit into
python:masterfrom
haeganm:match-irrefutable-patterns

Conversation

@haeganm

@haeganm haeganm commented Sep 1, 2026

Copy link
Copy Markdown

Fixes #21925

CPython rejects a match statement at compile time when an unguarded irrefutable pattern (a capture or wildcard) appears in any case except the last one:

SyntaxError: name capture 'y' makes remaining patterns unreachable

It also rejects an irrefutable alternative in a non-final position of an or pattern (case _ | 1:), wherever the or pattern appears, including nested inside sequence, mapping and class patterns. mypy reported nothing for either, so files that cannot even be imported checked clean.

Two changes:

  • get_irrefutable_pattern in patterns.py returns the capture or wildcard pattern that makes a pattern irrefutable, following the compiler's definition: a capture, a wildcard, an as pattern whose subpattern is irrefutable, or an or pattern whose last alternative is irrefutable.
  • Semantic analysis now reports an error for an unguarded irrefutable pattern in a non-final case (in visit_match_stmt) and for an irrefutable alternative in a non-final position of an or pattern (in visit_or_pattern). The check lives in semantic analysis rather than in the pattern checker because every pattern is visited there unconditionally, so it also fires in unchecked functions, matching the runtime SyntaxError. The error messages mirror CPython's, and the errors are reported with serious=True like the existing check for await outside a coroutine.

I verified the behavior against CPython 3.13 on a matrix of 26 cases (guarded and unguarded captures and wildcards, as patterns, or patterns in every position, and patterns nested in sequence, mapping and class patterns) by compiling each snippet with compile() and comparing with mypy's verdict; they agree on all of them. The new test cases fail without this change and pass with it. Existing behavior is preserved: an irrefutable pattern in the last case, a guarded case, and refutable patterns that happen to match anything (like case int(): on an int subject) still produce no error.

…rns unreachable

CPython rejects a match statement at compile time when an unguarded
irrefutable pattern (a capture or wildcard) appears in any case except
the last one, and when an irrefutable alternative appears in a non-final
position of an or pattern. mypy accepted both without any error, so a
file that cannot even be imported checked clean.

Add the check to semantic analysis, where every pattern is visited
unconditionally, so it also fires in unchecked functions the same way
the runtime SyntaxError does.

Fixes python#21925
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

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.

Irrefutable pattern before the last case in a match statement passes type checking but is a SyntaxError at runtime

1 participant