[syntax-errors] Irrefutable case pattern before final case (#16905)

Summary
--

Detects irrefutable `match` cases before the final case using a modified
version
of the existing `Pattern::is_irrefutable` method from the AST crate. The
modified method helps to retrieve a more precise diagnostic range to
match what
Python 3.13 shows in the REPL.

Test Plan
--

New inline tests, as well as some updates to existing tests that had
irrefutable
patterns before the last block.
This commit is contained in:
Brent Westbrook 2025-03-26 12:27:16 -04:00 committed by GitHub
parent 58350ec93b
commit 5697d21fca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 1420 additions and 594 deletions

View file

@ -2244,12 +2244,33 @@ impl Pattern {
///
/// [irrefutable pattern]: https://peps.python.org/pep-0634/#irrefutable-case-blocks
pub fn is_irrefutable(&self) -> bool {
self.irrefutable_pattern().is_some()
}
/// Return `Some(IrrefutablePattern)` if `self` is irrefutable or `None` otherwise.
pub fn irrefutable_pattern(&self) -> Option<IrrefutablePattern> {
match self {
Pattern::MatchAs(PatternMatchAs { pattern: None, .. }) => true,
Pattern::MatchAs(PatternMatchAs {
pattern,
name,
range,
}) => match pattern {
Some(pattern) => pattern.irrefutable_pattern(),
None => match name {
Some(name) => Some(IrrefutablePattern {
kind: IrrefutablePatternKind::Name(name.id.clone()),
range: *range,
}),
None => Some(IrrefutablePattern {
kind: IrrefutablePatternKind::Wildcard,
range: *range,
}),
},
},
Pattern::MatchOr(PatternMatchOr { patterns, .. }) => {
patterns.iter().any(Pattern::is_irrefutable)
patterns.iter().find_map(Pattern::irrefutable_pattern)
}
_ => false,
_ => None,
}
}
@ -2277,6 +2298,17 @@ impl Pattern {
}
}
pub struct IrrefutablePattern {
pub kind: IrrefutablePatternKind,
pub range: TextRange,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum IrrefutablePatternKind {
Name(Name),
Wildcard,
}
/// See also [MatchValue](https://docs.python.org/3/library/ast.html#ast.MatchValue)
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchValue {