Fix syntax error false positive on nested alternative patterns (#21104)

## Summary

Fixes #21101 by storing the child visitor's names in the parent visitor.
This makes sure that `visitor.names` on line 1818 isn't empty after we
visit a nested OR pattern.

## Test Plan

New inline test cases derived from the issue,
[playground](https://play.ruff.rs/7b6439ac-ee8f-4593-9a3e-c2aa34a595d0)
This commit is contained in:
Brent Westbrook 2025-10-30 13:40:03 -04:00 committed by GitHub
parent 10bda3df00
commit f0fe6d62fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 512 additions and 0 deletions

View file

@ -0,0 +1,495 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/nested_alternative_patterns.py
---
## AST
```
Module(
ModModule {
node_index: NodeIndex(None),
range: 0..181,
body: [
Match(
StmtMatch {
node_index: NodeIndex(None),
range: 0..96,
subject: Name(
ExprName {
node_index: NodeIndex(None),
range: 6..10,
id: Name("ruff"),
ctx: Load,
},
),
cases: [
MatchCase {
range: 16..96,
node_index: NodeIndex(None),
pattern: MatchOr(
PatternMatchOr {
node_index: NodeIndex(None),
range: 21..83,
patterns: [
MatchMapping(
PatternMatchMapping {
node_index: NodeIndex(None),
range: 21..67,
keys: [
StringLiteral(
ExprStringLiteral {
node_index: NodeIndex(None),
range: 22..28,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 22..28,
node_index: NodeIndex(None),
value: "lint",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
unclosed: false,
},
},
),
},
},
),
],
patterns: [
MatchOr(
PatternMatchOr {
node_index: NodeIndex(None),
range: 30..66,
patterns: [
MatchMapping(
PatternMatchMapping {
node_index: NodeIndex(None),
range: 30..43,
keys: [
StringLiteral(
ExprStringLiteral {
node_index: NodeIndex(None),
range: 31..39,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 31..39,
node_index: NodeIndex(None),
value: "select",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
unclosed: false,
},
},
),
},
},
),
],
patterns: [
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 41..42,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 41..42,
node_index: NodeIndex(None),
},
),
},
),
],
rest: None,
},
),
MatchMapping(
PatternMatchMapping {
node_index: NodeIndex(None),
range: 46..66,
keys: [
StringLiteral(
ExprStringLiteral {
node_index: NodeIndex(None),
range: 47..62,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 47..62,
node_index: NodeIndex(None),
value: "extend-select",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
unclosed: false,
},
},
),
},
},
),
],
patterns: [
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 64..65,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 64..65,
node_index: NodeIndex(None),
},
),
},
),
],
rest: None,
},
),
],
},
),
],
rest: None,
},
),
MatchMapping(
PatternMatchMapping {
node_index: NodeIndex(None),
range: 70..83,
keys: [
StringLiteral(
ExprStringLiteral {
node_index: NodeIndex(None),
range: 71..79,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 71..79,
node_index: NodeIndex(None),
value: "select",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
unclosed: false,
},
},
),
},
},
),
],
patterns: [
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 81..82,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 81..82,
node_index: NodeIndex(None),
},
),
},
),
],
rest: None,
},
),
],
},
),
guard: None,
body: [
Expr(
StmtExpr {
node_index: NodeIndex(None),
range: 93..96,
value: EllipsisLiteral(
ExprEllipsisLiteral {
node_index: NodeIndex(None),
range: 93..96,
},
),
},
),
],
},
],
},
),
Match(
StmtMatch {
node_index: NodeIndex(None),
range: 97..136,
subject: NumberLiteral(
ExprNumberLiteral {
node_index: NodeIndex(None),
range: 103..105,
value: Int(
42,
),
},
),
cases: [
MatchCase {
range: 111..136,
node_index: NodeIndex(None),
pattern: MatchOr(
PatternMatchOr {
node_index: NodeIndex(None),
range: 116..131,
patterns: [
MatchSequence(
PatternMatchSequence {
node_index: NodeIndex(None),
range: 116..127,
patterns: [
MatchOr(
PatternMatchOr {
node_index: NodeIndex(None),
range: 117..126,
patterns: [
MatchSequence(
PatternMatchSequence {
node_index: NodeIndex(None),
range: 117..120,
patterns: [
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 118..119,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 118..119,
node_index: NodeIndex(None),
},
),
},
),
],
},
),
MatchSequence(
PatternMatchSequence {
node_index: NodeIndex(None),
range: 123..126,
patterns: [
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 124..125,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 124..125,
node_index: NodeIndex(None),
},
),
},
),
],
},
),
],
},
),
],
},
),
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 130..131,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 130..131,
node_index: NodeIndex(None),
},
),
},
),
],
},
),
guard: None,
body: [
Expr(
StmtExpr {
node_index: NodeIndex(None),
range: 133..136,
value: EllipsisLiteral(
ExprEllipsisLiteral {
node_index: NodeIndex(None),
range: 133..136,
},
),
},
),
],
},
],
},
),
Match(
StmtMatch {
node_index: NodeIndex(None),
range: 137..180,
subject: NumberLiteral(
ExprNumberLiteral {
node_index: NodeIndex(None),
range: 143..145,
value: Int(
42,
),
},
),
cases: [
MatchCase {
range: 151..180,
node_index: NodeIndex(None),
pattern: MatchOr(
PatternMatchOr {
node_index: NodeIndex(None),
range: 156..175,
patterns: [
MatchSequence(
PatternMatchSequence {
node_index: NodeIndex(None),
range: 156..171,
patterns: [
MatchOr(
PatternMatchOr {
node_index: NodeIndex(None),
range: 157..170,
patterns: [
MatchSequence(
PatternMatchSequence {
node_index: NodeIndex(None),
range: 157..164,
patterns: [
MatchOr(
PatternMatchOr {
node_index: NodeIndex(None),
range: 158..163,
patterns: [
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 158..159,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 158..159,
node_index: NodeIndex(None),
},
),
},
),
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 162..163,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 162..163,
node_index: NodeIndex(None),
},
),
},
),
],
},
),
],
},
),
MatchSequence(
PatternMatchSequence {
node_index: NodeIndex(None),
range: 167..170,
patterns: [
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 168..169,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 168..169,
node_index: NodeIndex(None),
},
),
},
),
],
},
),
],
},
),
],
},
),
MatchAs(
PatternMatchAs {
node_index: NodeIndex(None),
range: 174..175,
pattern: None,
name: Some(
Identifier {
id: Name("x"),
range: 174..175,
node_index: NodeIndex(None),
},
),
},
),
],
},
),
guard: None,
body: [
Expr(
StmtExpr {
node_index: NodeIndex(None),
range: 177..180,
value: EllipsisLiteral(
ExprEllipsisLiteral {
node_index: NodeIndex(None),
range: 177..180,
},
),
},
),
],
},
],
},
),
],
},
)
```