[syntax-errors] Tuple unpacking in return and yield before Python 3.8 (#16485)

Summary
--

Checks for tuple unpacking in `return` and `yield` statements before
Python 3.8, as described [here].

Test Plan
--
Inline tests.

[here]: https://github.com/python/cpython/issues/76298
This commit is contained in:
Brent Westbrook 2025-03-06 11:57:20 -05:00 committed by GitHub
parent 0a627ef216
commit 6c14225c66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 1217 additions and 8 deletions

View file

@ -0,0 +1,146 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/iter_unpack_return_py37.py
---
## AST
```
Module(
ModModule {
range: 0..91,
body: [
Assign(
StmtAssign {
range: 43..59,
targets: [
Name(
ExprName {
range: 43..47,
id: Name("rest"),
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 50..59,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 51..52,
value: Int(
4,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 54..55,
value: Int(
5,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 57..58,
value: Int(
6,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
FunctionDef(
StmtFunctionDef {
range: 60..90,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("f"),
range: 64..65,
},
type_params: None,
parameters: Parameters {
range: 65..67,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Return(
StmtReturn {
range: 69..90,
value: Some(
Tuple(
ExprTuple {
range: 76..90,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 76..77,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 79..80,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 82..83,
value: Int(
3,
),
},
),
Starred(
ExprStarred {
range: 85..90,
value: Name(
ExprName {
range: 86..90,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
],
},
),
],
},
)
```
## Unsupported Syntax Errors
|
1 | # parse_options: {"target-version": "3.7"}
2 | rest = (4, 5, 6)
3 | def f(): return 1, 2, 3, *rest
| ^^^^^ Syntax Error: Cannot use iterable unpacking in return statements on Python 3.7 (syntax was added in Python 3.8)
|

View file

@ -0,0 +1,257 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/iter_unpack_yield_py37.py
---
## AST
```
Module(
ModModule {
range: 0..128,
body: [
Assign(
StmtAssign {
range: 43..59,
targets: [
Name(
ExprName {
range: 43..47,
id: Name("rest"),
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 50..59,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 51..52,
value: Int(
4,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 54..55,
value: Int(
5,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 57..58,
value: Int(
6,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
FunctionDef(
StmtFunctionDef {
range: 60..89,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("g"),
range: 64..65,
},
type_params: None,
parameters: Parameters {
range: 65..67,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 69..89,
value: Yield(
ExprYield {
range: 69..89,
value: Some(
Tuple(
ExprTuple {
range: 75..89,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 75..76,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 78..79,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 81..82,
value: Int(
3,
),
},
),
Starred(
ExprStarred {
range: 84..89,
value: Name(
ExprName {
range: 85..89,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 90..127,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("h"),
range: 94..95,
},
type_params: None,
parameters: Parameters {
range: 95..97,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 99..127,
value: Yield(
ExprYield {
range: 99..127,
value: Some(
Tuple(
ExprTuple {
range: 105..127,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 105..106,
value: Int(
1,
),
},
),
Yield(
ExprYield {
range: 109..123,
value: Some(
Tuple(
ExprTuple {
range: 115..123,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 115..116,
value: Int(
2,
),
},
),
Starred(
ExprStarred {
range: 118..123,
value: Name(
ExprName {
range: 119..123,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 126..127,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
},
),
],
},
),
],
},
)
```
## Unsupported Syntax Errors
|
1 | # parse_options: {"target-version": "3.7"}
2 | rest = (4, 5, 6)
3 | def g(): yield 1, 2, 3, *rest
| ^^^^^ Syntax Error: Cannot use iterable unpacking in yield expressions on Python 3.7 (syntax was added in Python 3.8)
4 | def h(): yield 1, (yield 2, *rest), 3
|
|
2 | rest = (4, 5, 6)
3 | def g(): yield 1, 2, 3, *rest
4 | def h(): yield 1, (yield 2, *rest), 3
| ^^^^^ Syntax Error: Cannot use iterable unpacking in yield expressions on Python 3.7 (syntax was added in Python 3.8)
|

View file

@ -0,0 +1,138 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/iter_unpack_return_py37.py
---
## AST
```
Module(
ModModule {
range: 0..93,
body: [
Assign(
StmtAssign {
range: 43..59,
targets: [
Name(
ExprName {
range: 43..47,
id: Name("rest"),
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 50..59,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 51..52,
value: Int(
4,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 54..55,
value: Int(
5,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 57..58,
value: Int(
6,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
FunctionDef(
StmtFunctionDef {
range: 60..92,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("f"),
range: 64..65,
},
type_params: None,
parameters: Parameters {
range: 65..67,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Return(
StmtReturn {
range: 69..92,
value: Some(
Tuple(
ExprTuple {
range: 76..92,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 77..78,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 80..81,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 83..84,
value: Int(
3,
),
},
),
Starred(
ExprStarred {
range: 86..91,
value: Name(
ExprName {
range: 87..91,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
),
},
),
],
},
),
],
},
)
```

View file

@ -0,0 +1,138 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/iter_unpack_return_py38.py
---
## AST
```
Module(
ModModule {
range: 0..91,
body: [
Assign(
StmtAssign {
range: 43..59,
targets: [
Name(
ExprName {
range: 43..47,
id: Name("rest"),
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 50..59,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 51..52,
value: Int(
4,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 54..55,
value: Int(
5,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 57..58,
value: Int(
6,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
FunctionDef(
StmtFunctionDef {
range: 60..90,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("f"),
range: 64..65,
},
type_params: None,
parameters: Parameters {
range: 65..67,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Return(
StmtReturn {
range: 69..90,
value: Some(
Tuple(
ExprTuple {
range: 76..90,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 76..77,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 79..80,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 82..83,
value: Int(
3,
),
},
),
Starred(
ExprStarred {
range: 85..90,
value: Name(
ExprName {
range: 86..90,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
],
},
),
],
},
)
```

View file

@ -0,0 +1,143 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/iter_unpack_yield_py37.py
---
## AST
```
Module(
ModModule {
range: 0..92,
body: [
Assign(
StmtAssign {
range: 43..59,
targets: [
Name(
ExprName {
range: 43..47,
id: Name("rest"),
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 50..59,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 51..52,
value: Int(
4,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 54..55,
value: Int(
5,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 57..58,
value: Int(
6,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
FunctionDef(
StmtFunctionDef {
range: 60..91,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("g"),
range: 64..65,
},
type_params: None,
parameters: Parameters {
range: 65..67,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 69..91,
value: Yield(
ExprYield {
range: 69..91,
value: Some(
Tuple(
ExprTuple {
range: 75..91,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 76..77,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 79..80,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 82..83,
value: Int(
3,
),
},
),
Starred(
ExprStarred {
range: 85..90,
value: Name(
ExprName {
range: 86..90,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
),
},
),
},
),
],
},
),
],
},
)
```

View file

@ -0,0 +1,240 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/iter_unpack_yield_py38.py
---
## AST
```
Module(
ModModule {
range: 0..128,
body: [
Assign(
StmtAssign {
range: 43..59,
targets: [
Name(
ExprName {
range: 43..47,
id: Name("rest"),
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 50..59,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 51..52,
value: Int(
4,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 54..55,
value: Int(
5,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 57..58,
value: Int(
6,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
FunctionDef(
StmtFunctionDef {
range: 60..89,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("g"),
range: 64..65,
},
type_params: None,
parameters: Parameters {
range: 65..67,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 69..89,
value: Yield(
ExprYield {
range: 69..89,
value: Some(
Tuple(
ExprTuple {
range: 75..89,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 75..76,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 78..79,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 81..82,
value: Int(
3,
),
},
),
Starred(
ExprStarred {
range: 84..89,
value: Name(
ExprName {
range: 85..89,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 90..127,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("h"),
range: 94..95,
},
type_params: None,
parameters: Parameters {
range: 95..97,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 99..127,
value: Yield(
ExprYield {
range: 99..127,
value: Some(
Tuple(
ExprTuple {
range: 105..127,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 105..106,
value: Int(
1,
),
},
),
Yield(
ExprYield {
range: 109..123,
value: Some(
Tuple(
ExprTuple {
range: 115..123,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 115..116,
value: Int(
2,
),
},
),
Starred(
ExprStarred {
range: 118..123,
value: Name(
ExprName {
range: 119..123,
id: Name("rest"),
ctx: Load,
},
),
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 126..127,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: false,
},
),
),
},
),
},
),
],
},
),
],
},
)
```