Skip to content

Commit c33fbee

Browse files
authored
Parse type parameters in class definitions
2 parents c8092b2 + 3ec64e1 commit c33fbee

File tree

4 files changed

+11158
-9470
lines changed

4 files changed

+11158
-9470
lines changed

parser/src/parser.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,38 @@ class Foo(A, B):
636636
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
637637
}
638638

639+
#[test]
640+
#[cfg(feature = "all-nodes-with-ranges")]
641+
fn test_parse_class_generic_types() {
642+
let source = "\
643+
# TypeVar
644+
class Foo[T](): ...
645+
646+
# TypeVar with bound
647+
class Foo[T: str](): ...
648+
649+
# TypeVar with tuple bound
650+
class Foo[T: (str, bytes)](): ...
651+
652+
# Multiple TypeVar
653+
class Foo[T, U](): ...
654+
655+
# Trailing comma
656+
class Foo[T, U,](): ...
657+
658+
# TypeVarTuple
659+
class Foo[*Ts](): ...
660+
661+
# ParamSpec
662+
class Foo[**P](): ...
663+
664+
# Mixed types
665+
class Foo[X, Y: str, *U, **P]():
666+
pass
667+
";
668+
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
669+
}
670+
639671
#[test]
640672
#[cfg(feature = "all-nodes-with-ranges")]
641673
fn test_parse_dict_comprehension() {

parser/src/python.lalrpop

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,27 +1126,51 @@ KwargParameter<ArgType>: Option<Box<ast::Arg>> = {
11261126
};
11271127

11281128
ClassDef: ast::Stmt = {
1129-
<decorator_list:Decorator*> <location:@L> "class" <name:Identifier> <a:("(" ArgumentList ")")?> ":" <body:Suite> => {
1129+
<decorator_list:Decorator*> <location:@L> "class" <name:Identifier> <type_params:TypeParamList?> <a:("(" ArgumentList ")")?> ":" <body:Suite> => {
11301130
let (bases, keywords) = match a {
11311131
Some((_, arg, _)) => (arg.args, arg.keywords),
11321132
None => (vec![], vec![]),
11331133
};
11341134
let end_location = body.last().unwrap().end();
1135-
let type_params = Vec::new();
11361135
ast::Stmt::ClassDef(
11371136
ast::StmtClassDef {
11381137
name,
11391138
bases,
11401139
keywords,
11411140
body,
11421141
decorator_list,
1143-
type_params,
1142+
type_params: type_params.unwrap_or_default(),
11441143
range: (location..end_location).into()
11451144
},
11461145
)
11471146
},
11481147
};
11491148

1149+
1150+
TypeParamList: Vec<ast::TypeParam> = {
1151+
<location:@L> "[" <vars:OneOrMore<TypeParam>> ","? "]" <end_location:@R> => {
1152+
vars
1153+
}
1154+
};
1155+
1156+
TypeParam: ast::TypeParam = {
1157+
<location:@L> <name:Identifier> <bound:(":" <Test<"all">>)?> <end_location:@R> => {
1158+
ast::TypeParam::TypeVar(
1159+
ast::TypeParamTypeVar { name, bound: bound.map(Box::new), range: (location..end_location).into() }
1160+
)
1161+
},
1162+
<location:@L> "*" <name:Identifier> <end_location:@R> => {
1163+
ast::TypeParam::TypeVarTuple(
1164+
ast::TypeParamTypeVarTuple { name, range: (location..end_location).into() }
1165+
)
1166+
},
1167+
<location:@L> "**" <name:Identifier> <end_location:@R> => {
1168+
ast::TypeParam::ParamSpec(
1169+
ast::TypeParamParamSpec { name, range: (location..end_location).into() }
1170+
)
1171+
}
1172+
};
1173+
11501174
// Decorators:
11511175
Decorator: ast::Expr = {
11521176
<location:@L> "@" <p:NamedExpressionTest> "\n" => {

0 commit comments

Comments
 (0)