mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-02 18:02:58 +00:00
Add syntax error for empty type parameter list (#12030)
## Summary (I'm pretty sure I added this in the parser re-write but must've got lost in the rebase?) This PR raises a syntax error if the type parameter list is empty. As per the grammar, there should be at least one type parameter: ``` type_params: | invalid_type_params | '[' type_param_seq ']' type_param_seq: ','.type_param+ [','] ``` Verified via the builtin `ast` module as well: ```console $ python3.13 -m ast parser/_.py Traceback (most recent call last): [..] File "parser/_.py", line 1 def foo[](): ^ SyntaxError: Type parameter list cannot be empty ``` ## Test Plan Add inline test cases and update the snapshots.
This commit is contained in:
parent
83fe44728b
commit
7cb2619ef5
4 changed files with 116 additions and 0 deletions
|
@ -0,0 +1,3 @@
|
||||||
|
def foo[]():
|
||||||
|
pass
|
||||||
|
type ListOrSet[] = list | set
|
|
@ -99,6 +99,8 @@ pub enum ParseErrorType {
|
||||||
EmptyDeleteTargets,
|
EmptyDeleteTargets,
|
||||||
/// An empty import names list was found during parsing.
|
/// An empty import names list was found during parsing.
|
||||||
EmptyImportNames,
|
EmptyImportNames,
|
||||||
|
/// An empty type parameter list was found during parsing.
|
||||||
|
EmptyTypeParams,
|
||||||
|
|
||||||
/// An unparenthesized named expression was found where it is not allowed.
|
/// An unparenthesized named expression was found where it is not allowed.
|
||||||
UnparenthesizedNamedExpression,
|
UnparenthesizedNamedExpression,
|
||||||
|
@ -242,6 +244,7 @@ impl std::fmt::Display for ParseErrorType {
|
||||||
ParseErrorType::EmptyImportNames => {
|
ParseErrorType::EmptyImportNames => {
|
||||||
f.write_str("Expected one or more symbol names after import")
|
f.write_str("Expected one or more symbol names after import")
|
||||||
}
|
}
|
||||||
|
ParseErrorType::EmptyTypeParams => f.write_str("Type parameter list cannot be empty"),
|
||||||
ParseErrorType::ParamAfterVarKeywordParam => {
|
ParseErrorType::ParamAfterVarKeywordParam => {
|
||||||
f.write_str("Parameter cannot follow var-keyword parameter")
|
f.write_str("Parameter cannot follow var-keyword parameter")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3027,6 +3027,14 @@ impl<'src> Parser<'src> {
|
||||||
Parser::parse_type_param,
|
Parser::parse_type_param,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if type_params.is_empty() {
|
||||||
|
// test_err type_params_empty
|
||||||
|
// def foo[]():
|
||||||
|
// pass
|
||||||
|
// type ListOrSet[] = list | set
|
||||||
|
self.add_error(ParseErrorType::EmptyTypeParams, self.current_token_range());
|
||||||
|
}
|
||||||
|
|
||||||
self.expect(TokenKind::Rsqb);
|
self.expect(TokenKind::Rsqb);
|
||||||
|
|
||||||
ast::TypeParams {
|
ast::TypeParams {
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||||
|
input_file: crates/ruff_python_parser/resources/inline/err/type_params_empty.py
|
||||||
|
---
|
||||||
|
## AST
|
||||||
|
|
||||||
|
```
|
||||||
|
Module(
|
||||||
|
ModModule {
|
||||||
|
range: 0..52,
|
||||||
|
body: [
|
||||||
|
FunctionDef(
|
||||||
|
StmtFunctionDef {
|
||||||
|
range: 0..21,
|
||||||
|
is_async: false,
|
||||||
|
decorator_list: [],
|
||||||
|
name: Identifier {
|
||||||
|
id: "foo",
|
||||||
|
range: 4..7,
|
||||||
|
},
|
||||||
|
type_params: Some(
|
||||||
|
TypeParams {
|
||||||
|
range: 7..9,
|
||||||
|
type_params: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
parameters: Parameters {
|
||||||
|
range: 9..11,
|
||||||
|
posonlyargs: [],
|
||||||
|
args: [],
|
||||||
|
vararg: None,
|
||||||
|
kwonlyargs: [],
|
||||||
|
kwarg: None,
|
||||||
|
},
|
||||||
|
returns: None,
|
||||||
|
body: [
|
||||||
|
Pass(
|
||||||
|
StmtPass {
|
||||||
|
range: 17..21,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TypeAlias(
|
||||||
|
StmtTypeAlias {
|
||||||
|
range: 22..51,
|
||||||
|
name: Name(
|
||||||
|
ExprName {
|
||||||
|
range: 27..36,
|
||||||
|
id: "ListOrSet",
|
||||||
|
ctx: Store,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
type_params: Some(
|
||||||
|
TypeParams {
|
||||||
|
range: 36..38,
|
||||||
|
type_params: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
value: BinOp(
|
||||||
|
ExprBinOp {
|
||||||
|
range: 41..51,
|
||||||
|
left: Name(
|
||||||
|
ExprName {
|
||||||
|
range: 41..45,
|
||||||
|
id: "list",
|
||||||
|
ctx: Load,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
op: BitOr,
|
||||||
|
right: Name(
|
||||||
|
ExprName {
|
||||||
|
range: 48..51,
|
||||||
|
id: "set",
|
||||||
|
ctx: Load,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
```
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
|
|
||||||
|
1 | def foo[]():
|
||||||
|
| ^ Syntax Error: Type parameter list cannot be empty
|
||||||
|
2 | pass
|
||||||
|
3 | type ListOrSet[] = list | set
|
||||||
|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
1 | def foo[]():
|
||||||
|
2 | pass
|
||||||
|
3 | type ListOrSet[] = list | set
|
||||||
|
| ^ Syntax Error: Type parameter list cannot be empty
|
||||||
|
|
|
Loading…
Add table
Add a link
Reference in a new issue