-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Better error recovery for match patterns (#10477)
## Summary This PR updates the match statement's pattern parsing logic to better facilitate the error recovery. The following changes are made: ### Disallow star pattern (`*<name>`) outside of sequence pattern This is done by passing an enum stating whether to allow star pattern or not and is based on where the parser is in the stack. <details><summary>Call stack for pattern parsing functions:</summary> <p> I took notes on where would I requires changing this, so sharing it for documenting purposes: * `parse_match_patterns` * `parse_match_pattern` (`AllowStarPattern::Yes`) * Error if it’s a star pattern and it's not a sequence pattern * `parse_sequence_match_pattern` * `parse_match_pattern` (`AllowStarPattern::Yes`) * `parse_match_pattern` (`allow_star_pattern: AllowStarPattern`) * `parse_match_pattern_lhs` (`allow_star_pattern: AllowStarPattern`) * `parse_match_pattern_mapping` * `parse_match_pattern_lhs` (`AllowStarPattern::No`) * `parse_match_pattern` (`AllowStarPattern::No`) * `parse_match_pattern_star` * `parse_delimited_match_pattern` * `parse_match_pattern` (`AllowStarPattern::Yes`) * `parse_sequence_match_pattern` * `parse_match_pattern_literal` * `parse_attr_expr_for_match_pattern` * `parse_match_pattern_class` * `parse_match_pattern` (`AllowStarPattern::No`) * `parse_complex_literal_pattern` * `parse_match_pattern_lhs` (`AllowStarPattern::No`) </p> </details> The mapping pattern `FIRST` set has been updated to include `*` to allow the parser to recover from this error in mapping pattern. Otherwise, the list parsing would completely skip parsing it. ### Convert `Pattern` to `Expr` In certain cases, the parser expects a specific type of pattern and uses that to extract information. For example, in complex literal, we parse the LHS and RHS as patterns but the LHS can only be a real number while the RHS can only be a complex number. This means that if the parser found any other pattern kind then we would convert the pattern into an equivalent expression and add an appropriate error. This will help any downstream tools. Refer to `recovery::pattern_to_expr` for more details. ### Extract complex number literal pattern parsing logic Earlier, this was inside the `parse_match_pattern_lhs` which made the method a bit more complex than it needed to be. The logic has been extracted to a new `parse_complex_pattern_literal` and is called when the parser encounters a pattern followed by either `+` or `-`. The parser only allows a valid complex literal pattern which is `real_number +/- complex_number`. For any other case, an appropriate error will be raised. ## Review Refer to the test cases to help in the review process. ## Test Plan Add test cases and update the snapshots.
- Loading branch information
1 parent
2832b4e
commit c16f7b7
Showing
27 changed files
with
4,756 additions
and
813 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_0.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
match subject: | ||
# Parser shouldn't confuse this as being a | ||
# class pattern | ||
# v | ||
case (x as y)(a, b): | ||
# ^^^^^^ | ||
# as-pattern | ||
pass |
8 changes: 8 additions & 0 deletions
8
crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_1.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
match subject: | ||
# Parser shouldn't confuse this as being a | ||
# complex literal pattern | ||
# v | ||
case (x as y) + 1j: | ||
# ^^^^^^ | ||
# as-pattern | ||
pass |
5 changes: 5 additions & 0 deletions
5
crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_2.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
match subject: | ||
# This `as` pattern is unparenthesied so the parser never takes the path | ||
# where it might be confused as a complex literal pattern. | ||
case x as y + 1j: | ||
pass |
5 changes: 5 additions & 0 deletions
5
crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_3.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
match subject: | ||
# Not in the mapping start token set, so the list parsing bails | ||
# v | ||
case {(x as y): 1}: | ||
pass |
5 changes: 5 additions & 0 deletions
5
crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_4.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
match subject: | ||
# This `as` pattern is unparenthesized so the parser never takes the path | ||
# where it might be confused as a mapping key pattern. | ||
case {x as y: 1}: | ||
pass |
17 changes: 17 additions & 0 deletions
17
crates/ruff_python_parser/resources/invalid/statements/match/invalid_class_pattern.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Invalid keyword pattern in class argument | ||
match subject: | ||
case Foo(x as y = 1): | ||
pass | ||
case Foo(x | y = 1): | ||
pass | ||
case Foo([x, y] = 1): | ||
pass | ||
case Foo({False: 0} = 1): | ||
pass | ||
case Foo(1=1): | ||
pass | ||
case Foo(Bar()=1): | ||
pass | ||
# Positional pattern cannot follow keyword pattern | ||
# case Foo(x, y=1, z): | ||
# pass |
37 changes: 37 additions & 0 deletions
37
crates/ruff_python_parser/resources/invalid/statements/match/invalid_lhs_or_rhs_pattern.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
match invalid_lhs_pattern: | ||
case Foo() + 1j: | ||
pass | ||
case x + 2j: | ||
pass | ||
case _ + 3j: | ||
pass | ||
case (1 | 2) + 4j: | ||
pass | ||
case [1, 2] + 5j: | ||
pass | ||
case {True: 1} + 6j: | ||
pass | ||
case 1j + 2j: | ||
pass | ||
case -1j + 2j: | ||
pass | ||
|
||
match invalid_rhs_pattern: | ||
case 1 + Foo(): | ||
pass | ||
case 2 + x: | ||
pass | ||
case 3 + _: | ||
pass | ||
case 4 + (1 | 2): | ||
pass | ||
case 5 + [1, 2]: | ||
pass | ||
case 6 + {True: 1}: | ||
pass | ||
case 1 + 2: | ||
pass | ||
|
||
match invalid_lhs_rhs_pattern: | ||
case Foo() + Bar(): | ||
pass |
20 changes: 20 additions & 0 deletions
20
crates/ruff_python_parser/resources/invalid/statements/match/invalid_mapping_pattern.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Starred expression is not allowed as a mapping pattern key | ||
match subject: | ||
case {*key}: | ||
pass | ||
case {*key: 1}: | ||
pass | ||
case {*key 1}: | ||
pass | ||
case {*key, None: 1}: | ||
pass | ||
|
||
# Pattern cannot follow a double star pattern | ||
# Multiple double star patterns are not allowed | ||
match subject: | ||
case {**rest, None: 1}: | ||
pass | ||
case {**rest1, **rest2, None: 1}: | ||
pass | ||
case {**rest1, None: 1, **rest2}: | ||
pass |
24 changes: 24 additions & 0 deletions
24
crates/ruff_python_parser/resources/invalid/statements/match/star_pattern_usage.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Star pattern is only allowed inside a sequence pattern | ||
match subject: | ||
case *_: | ||
pass | ||
case *_ as x: | ||
pass | ||
case *foo: | ||
pass | ||
case *foo | 1: | ||
pass | ||
case 1 | *foo: | ||
pass | ||
case Foo(*_): | ||
pass | ||
case Foo(x=*_): | ||
pass | ||
case {*_}: | ||
pass | ||
case {*_: 1}: | ||
pass | ||
case {None: *_}: | ||
pass | ||
case 1 + *_: | ||
pass |
12 changes: 12 additions & 0 deletions
12
crates/ruff_python_parser/resources/invalid/statements/match/unary_add_usage.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Unary addition isn't allowed but we parse it for better error recovery. | ||
match subject: | ||
case +1: | ||
pass | ||
case 1 | +2 | -3: | ||
pass | ||
case [1, +2, -3]: | ||
pass | ||
case Foo(x=+1, y=-2): | ||
pass | ||
case {True: +1, False: -2}: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.