-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[syntax-errors] Type parameter lists before Python 3.12 #16479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
17ccf37
5686e97
1b259f1
6bc9876
ae50ba8
ed689c7
83b8d56
fc35635
61f2ad7
1d6a6df
a35bf2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # parse_options: {"target-version": "3.11"} | ||
| class Foo[S: (str, bytes), T: float, *Ts, **P]: ... | ||
| class Foo[]: ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # parse_options: {"target-version": "3.11"} | ||
| def foo[T](): ... | ||
| def foo[](): ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # parse_options: {"target-version": "3.12"} | ||
| class Foo[S: (str, bytes), T: float, *Ts, **P]: ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # parse_options: {"target-version": "3.12"} | ||
| def foo[T](): ... |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1786,6 +1786,25 @@ impl<'src> Parser<'src> { | |||||||||||||||||||||||||||||||
| // x = 10 | ||||||||||||||||||||||||||||||||
| let type_params = self.try_parse_type_params(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // test_ok function_type_params_py312 | ||||||||||||||||||||||||||||||||
| // # parse_options: {"target-version": "3.12"} | ||||||||||||||||||||||||||||||||
| // def foo[T](): ... | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // test_err function_type_params_py311 | ||||||||||||||||||||||||||||||||
| // # parse_options: {"target-version": "3.11"} | ||||||||||||||||||||||||||||||||
| // def foo[T](): ... | ||||||||||||||||||||||||||||||||
| // def foo[](): ... | ||||||||||||||||||||||||||||||||
| if let Some(ast::TypeParams { range, type_params }) = &type_params { | ||||||||||||||||||||||||||||||||
| // Only emit the `ParseError` for an empty parameter list instead of also including an | ||||||||||||||||||||||||||||||||
| // `UnsupportedSyntaxError`. | ||||||||||||||||||||||||||||||||
| if !type_params.is_empty() { | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
| fn inner(errors: &mut Vec<ParseError>, error: ParseErrorType, range: TextRange) { | |
| // Avoid flagging multiple errors at the same location | |
| let is_same_location = errors | |
| .last() | |
| .is_some_and(|last| last.location.start() == range.start()); | |
| if !is_same_location { | |
| errors.push(ParseError { | |
| error, | |
| location: range, | |
| }); | |
| } | |
| } | |
| inner(&mut self.errors, error, ranged.range()); |
But I agree that we should solve this holisticly because it will otherwise be very error prone to avoid all possible errors at the same location
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah nice! I'll remove these checks for now, and then maybe we can add UnsupportedSyntaxErrors to that check or a similar one later.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| --- | ||
| source: crates/ruff_python_parser/tests/fixtures.rs | ||
| input_file: crates/ruff_python_parser/resources/inline/err/class_type_params_py311.py | ||
| --- | ||
| ## AST | ||
|
|
||
| ``` | ||
| Module( | ||
| ModModule { | ||
| range: 0..113, | ||
| body: [ | ||
| ClassDef( | ||
| StmtClassDef { | ||
| range: 44..95, | ||
| decorator_list: [], | ||
| name: Identifier { | ||
| id: Name("Foo"), | ||
| range: 50..53, | ||
| }, | ||
| type_params: Some( | ||
| TypeParams { | ||
| range: 53..90, | ||
| type_params: [ | ||
| TypeVar( | ||
| TypeParamTypeVar { | ||
| range: 54..69, | ||
| name: Identifier { | ||
| id: Name("S"), | ||
| range: 54..55, | ||
| }, | ||
| bound: Some( | ||
| Tuple( | ||
| ExprTuple { | ||
| range: 57..69, | ||
| elts: [ | ||
| Name( | ||
| ExprName { | ||
| range: 58..61, | ||
| id: Name("str"), | ||
| ctx: Load, | ||
| }, | ||
| ), | ||
| Name( | ||
| ExprName { | ||
| range: 63..68, | ||
| id: Name("bytes"), | ||
| ctx: Load, | ||
| }, | ||
| ), | ||
| ], | ||
| ctx: Load, | ||
| parenthesized: true, | ||
| }, | ||
| ), | ||
| ), | ||
| default: None, | ||
| }, | ||
| ), | ||
| TypeVar( | ||
| TypeParamTypeVar { | ||
| range: 71..79, | ||
| name: Identifier { | ||
| id: Name("T"), | ||
| range: 71..72, | ||
| }, | ||
| bound: Some( | ||
| Name( | ||
| ExprName { | ||
| range: 74..79, | ||
| id: Name("float"), | ||
| ctx: Load, | ||
| }, | ||
| ), | ||
| ), | ||
| default: None, | ||
| }, | ||
| ), | ||
| TypeVarTuple( | ||
| TypeParamTypeVarTuple { | ||
| range: 81..84, | ||
| name: Identifier { | ||
| id: Name("Ts"), | ||
| range: 82..84, | ||
| }, | ||
| default: None, | ||
| }, | ||
| ), | ||
| ParamSpec( | ||
| TypeParamParamSpec { | ||
| range: 86..89, | ||
| name: Identifier { | ||
| id: Name("P"), | ||
| range: 88..89, | ||
| }, | ||
| default: None, | ||
| }, | ||
| ), | ||
| ], | ||
| }, | ||
| ), | ||
| arguments: None, | ||
| body: [ | ||
| Expr( | ||
| StmtExpr { | ||
| range: 92..95, | ||
| value: EllipsisLiteral( | ||
| ExprEllipsisLiteral { | ||
| range: 92..95, | ||
| }, | ||
| ), | ||
| }, | ||
| ), | ||
| ], | ||
| }, | ||
| ), | ||
| ClassDef( | ||
| StmtClassDef { | ||
| range: 96..112, | ||
| decorator_list: [], | ||
| name: Identifier { | ||
| id: Name("Foo"), | ||
| range: 102..105, | ||
| }, | ||
| type_params: Some( | ||
| TypeParams { | ||
| range: 105..107, | ||
| type_params: [], | ||
| }, | ||
| ), | ||
| arguments: None, | ||
| body: [ | ||
| Expr( | ||
| StmtExpr { | ||
| range: 109..112, | ||
| value: EllipsisLiteral( | ||
| ExprEllipsisLiteral { | ||
| range: 109..112, | ||
| }, | ||
| ), | ||
| }, | ||
| ), | ||
| ], | ||
| }, | ||
| ), | ||
| ], | ||
| }, | ||
| ) | ||
| ``` | ||
| ## Errors | ||
|
|
||
| | | ||
| 1 | # parse_options: {"target-version": "3.11"} | ||
| 2 | class Foo[S: (str, bytes), T: float, *Ts, **P]: ... | ||
| 3 | class Foo[]: ... | ||
| | ^ Syntax Error: Type parameter list cannot be empty | ||
| | | ||
|
|
||
|
|
||
| ## Unsupported Syntax Errors | ||
|
|
||
| | | ||
| 1 | # parse_options: {"target-version": "3.11"} | ||
| 2 | class Foo[S: (str, bytes), T: float, *Ts, **P]: ... | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Syntax Error: Cannot use type parameter lists on Python 3.11 (syntax was added in Python 3.12) | ||
| 3 | class Foo[]: ... | ||
| | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work? Shouldn't the link be after
[..]:on the same line?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appeared to work in Emacs, but I can put it on one line to be safe!