mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-29 07:54:40 +00:00
[syntax-errors] Star annotations before Python 3.11 (#16545)
Summary -- This is closely related to (and stacked on) https://github.com/astral-sh/ruff/pull/16544 and detects star annotations in function definitions. I initially called the variant `StarExpressionInAnnotation` to mirror `StarExpressionInIndex`, but I realized it's not really a "star expression" in this position and renamed it. `StarAnnotation` seems in line with the PEP. Test Plan -- Two new inline tests. It looked like there was pretty good existing coverage of this syntax, so I just added simple examples to test the version cutoff.
This commit is contained in:
parent
4f2851982d
commit
6311412373
6 changed files with 199 additions and 2 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
# parse_options: {"target-version": "3.10"}
|
||||||
|
def foo(*args: *Ts): ...
|
|
@ -0,0 +1,2 @@
|
||||||
|
# parse_options: {"target-version": "3.11"}
|
||||||
|
def foo(*args: *Ts): ...
|
|
@ -644,6 +644,34 @@ pub enum UnsupportedSyntaxErrorKind {
|
||||||
///
|
///
|
||||||
/// [PEP 646]: https://peps.python.org/pep-0646/#change-1-star-expressions-in-indexes
|
/// [PEP 646]: https://peps.python.org/pep-0646/#change-1-star-expressions-in-indexes
|
||||||
StarExpressionInIndex,
|
StarExpressionInIndex,
|
||||||
|
|
||||||
|
/// Represents the use of a [PEP 646] star annotations in a function definition.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// Before Python 3.11, star annotations were not allowed in function definitions. This
|
||||||
|
/// restriction was lifted in [PEP 646] to allow type annotations for `typing.TypeVarTuple`,
|
||||||
|
/// also added in Python 3.11:
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// from typing import TypeVarTuple
|
||||||
|
///
|
||||||
|
/// Ts = TypeVarTuple('Ts')
|
||||||
|
///
|
||||||
|
/// def foo(*args: *Ts): ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Unlike [`UnsupportedSyntaxErrorKind::StarExpressionInIndex`], this does not include any
|
||||||
|
/// other annotation positions:
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// x: *Ts # Syntax error
|
||||||
|
/// def foo(x: *Ts): ... # Syntax error
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 646]: https://peps.python.org/pep-0646/#change-2-args-as-a-typevartuple
|
||||||
|
StarAnnotation,
|
||||||
|
|
||||||
/// Represents the use of tuple unpacking in a `for` statement iterator clause before Python
|
/// Represents the use of tuple unpacking in a `for` statement iterator clause before Python
|
||||||
/// 3.9.
|
/// 3.9.
|
||||||
///
|
///
|
||||||
|
@ -699,6 +727,7 @@ impl Display for UnsupportedSyntaxError {
|
||||||
UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
|
UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
|
||||||
"Cannot use star expression in index"
|
"Cannot use star expression in index"
|
||||||
}
|
}
|
||||||
|
UnsupportedSyntaxErrorKind::StarAnnotation => "Cannot use star annotation",
|
||||||
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
|
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
|
||||||
"Cannot use iterable unpacking in `for` statements"
|
"Cannot use iterable unpacking in `for` statements"
|
||||||
}
|
}
|
||||||
|
@ -750,6 +779,7 @@ impl UnsupportedSyntaxErrorKind {
|
||||||
UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
|
UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
|
||||||
Change::Added(PythonVersion::PY311)
|
Change::Added(PythonVersion::PY311)
|
||||||
}
|
}
|
||||||
|
UnsupportedSyntaxErrorKind::StarAnnotation => Change::Added(PythonVersion::PY311),
|
||||||
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
|
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
|
||||||
Change::Added(PythonVersion::PY39)
|
Change::Added(PythonVersion::PY39)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2882,9 +2882,23 @@ impl<'src> Parser<'src> {
|
||||||
// def foo(*args: *int or str): ...
|
// def foo(*args: *int or str): ...
|
||||||
// def foo(*args: *yield x): ...
|
// def foo(*args: *yield x): ...
|
||||||
// # def foo(*args: **int): ...
|
// # def foo(*args: **int): ...
|
||||||
self.parse_conditional_expression_or_higher_impl(
|
let parsed_expr = self.parse_conditional_expression_or_higher_impl(
|
||||||
ExpressionContext::starred_bitwise_or(),
|
ExpressionContext::starred_bitwise_or(),
|
||||||
)
|
);
|
||||||
|
|
||||||
|
// test_ok param_with_star_annotation_py311
|
||||||
|
// # parse_options: {"target-version": "3.11"}
|
||||||
|
// def foo(*args: *Ts): ...
|
||||||
|
|
||||||
|
// test_err param_with_star_annotation_py310
|
||||||
|
// # parse_options: {"target-version": "3.10"}
|
||||||
|
// def foo(*args: *Ts): ...
|
||||||
|
self.add_unsupported_syntax_error(
|
||||||
|
UnsupportedSyntaxErrorKind::StarAnnotation,
|
||||||
|
parsed_expr.range(),
|
||||||
|
);
|
||||||
|
|
||||||
|
parsed_expr
|
||||||
}
|
}
|
||||||
AllowStarAnnotation::No => {
|
AllowStarAnnotation::No => {
|
||||||
// test_ok param_with_annotation
|
// test_ok param_with_annotation
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||||
|
input_file: crates/ruff_python_parser/resources/inline/err/param_with_star_annotation_py310.py
|
||||||
|
---
|
||||||
|
## AST
|
||||||
|
|
||||||
|
```
|
||||||
|
Module(
|
||||||
|
ModModule {
|
||||||
|
range: 0..69,
|
||||||
|
body: [
|
||||||
|
FunctionDef(
|
||||||
|
StmtFunctionDef {
|
||||||
|
range: 44..68,
|
||||||
|
is_async: false,
|
||||||
|
decorator_list: [],
|
||||||
|
name: Identifier {
|
||||||
|
id: Name("foo"),
|
||||||
|
range: 48..51,
|
||||||
|
},
|
||||||
|
type_params: None,
|
||||||
|
parameters: Parameters {
|
||||||
|
range: 51..63,
|
||||||
|
posonlyargs: [],
|
||||||
|
args: [],
|
||||||
|
vararg: Some(
|
||||||
|
Parameter {
|
||||||
|
range: 52..62,
|
||||||
|
name: Identifier {
|
||||||
|
id: Name("args"),
|
||||||
|
range: 53..57,
|
||||||
|
},
|
||||||
|
annotation: Some(
|
||||||
|
Starred(
|
||||||
|
ExprStarred {
|
||||||
|
range: 59..62,
|
||||||
|
value: Name(
|
||||||
|
ExprName {
|
||||||
|
range: 60..62,
|
||||||
|
id: Name("Ts"),
|
||||||
|
ctx: Load,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ctx: Load,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
kwonlyargs: [],
|
||||||
|
kwarg: None,
|
||||||
|
},
|
||||||
|
returns: None,
|
||||||
|
body: [
|
||||||
|
Expr(
|
||||||
|
StmtExpr {
|
||||||
|
range: 65..68,
|
||||||
|
value: EllipsisLiteral(
|
||||||
|
ExprEllipsisLiteral {
|
||||||
|
range: 65..68,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
```
|
||||||
|
## Unsupported Syntax Errors
|
||||||
|
|
||||||
|
|
|
||||||
|
1 | # parse_options: {"target-version": "3.10"}
|
||||||
|
2 | def foo(*args: *Ts): ...
|
||||||
|
| ^^^ Syntax Error: Cannot use star annotation on Python 3.10 (syntax was added in Python 3.11)
|
||||||
|
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||||
|
input_file: crates/ruff_python_parser/resources/inline/ok/param_with_star_annotation_py311.py
|
||||||
|
---
|
||||||
|
## AST
|
||||||
|
|
||||||
|
```
|
||||||
|
Module(
|
||||||
|
ModModule {
|
||||||
|
range: 0..69,
|
||||||
|
body: [
|
||||||
|
FunctionDef(
|
||||||
|
StmtFunctionDef {
|
||||||
|
range: 44..68,
|
||||||
|
is_async: false,
|
||||||
|
decorator_list: [],
|
||||||
|
name: Identifier {
|
||||||
|
id: Name("foo"),
|
||||||
|
range: 48..51,
|
||||||
|
},
|
||||||
|
type_params: None,
|
||||||
|
parameters: Parameters {
|
||||||
|
range: 51..63,
|
||||||
|
posonlyargs: [],
|
||||||
|
args: [],
|
||||||
|
vararg: Some(
|
||||||
|
Parameter {
|
||||||
|
range: 52..62,
|
||||||
|
name: Identifier {
|
||||||
|
id: Name("args"),
|
||||||
|
range: 53..57,
|
||||||
|
},
|
||||||
|
annotation: Some(
|
||||||
|
Starred(
|
||||||
|
ExprStarred {
|
||||||
|
range: 59..62,
|
||||||
|
value: Name(
|
||||||
|
ExprName {
|
||||||
|
range: 60..62,
|
||||||
|
id: Name("Ts"),
|
||||||
|
ctx: Load,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ctx: Load,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
kwonlyargs: [],
|
||||||
|
kwarg: None,
|
||||||
|
},
|
||||||
|
returns: None,
|
||||||
|
body: [
|
||||||
|
Expr(
|
||||||
|
StmtExpr {
|
||||||
|
range: 65..68,
|
||||||
|
value: EllipsisLiteral(
|
||||||
|
ExprEllipsisLiteral {
|
||||||
|
range: 65..68,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
```
|
Loading…
Add table
Add a link
Reference in a new issue