Add support for PEP 696 syntax (#11120)

This commit is contained in:
Jelle Zijlstra 2024-04-26 00:47:29 -07:00 committed by GitHub
parent 45725d3275
commit cd3e319538
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 4338 additions and 669 deletions

View file

@ -53,7 +53,7 @@ class WithinBody[T](list[T]): # OK
def foo(self, x: T) -> T: # OK
return x
def foo(self):
T # OK
@ -76,6 +76,16 @@ type Foo[T: (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNot
def foo[T: (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
class Foo[T: (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
# Same in defaults
type Foo[T = DoesNotExist] = T # F821: Undefined name `DoesNotExist`
def foo[T = DoesNotExist](t: T) -> T: return t # F821: Undefined name `DoesNotExist`
class Foo[T = DoesNotExist](list[T]): ... # F821: Undefined name `DoesNotExist`
type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
# Type parameters in nested classes
class Parent[T]:
@ -83,21 +93,21 @@ class Parent[T]:
def can_use_class_variable(self, x: t) -> t: # OK
return x
class Child:
def can_access_parent_type_parameter(self, x: T) -> T: # OK
T # OK
return x
def cannot_access_parent_variable(self, x: t) -> t: # F821: Undefined name `T`
t # F821: Undefined name `t`
return x
# Type parameters in nested functions
def can_access_inside_nested[T](t: T) -> T: # OK
def bar(x: T) -> T: # OK
T # OK
return x
bar(t)

View file

@ -1568,8 +1568,8 @@ impl<'a> Visitor<'a> for Checker<'a> {
// Step 1: Binding
match type_param {
ast::TypeParam::TypeVar(ast::TypeParamTypeVar { name, range, .. })
| ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { name, range })
| ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { name, range }) => {
| ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { name, range, .. })
| ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { name, range, .. }) => {
self.add_binding(
name.as_str(),
*range,
@ -1579,13 +1579,46 @@ impl<'a> Visitor<'a> for Checker<'a> {
}
}
// Step 2: Traversal
if let ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
bound: Some(bound), ..
}) = type_param
{
self.visit
.type_param_definitions
.push((bound, self.semantic.snapshot()));
match type_param {
ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
bound,
default,
name: _,
range: _,
}) => {
if let Some(expr) = bound {
self.visit
.type_param_definitions
.push((expr, self.semantic.snapshot()));
}
if let Some(expr) = default {
self.visit
.type_param_definitions
.push((expr, self.semantic.snapshot()));
}
}
ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple {
default,
name: _,
range: _,
}) => {
if let Some(expr) = default {
self.visit
.type_param_definitions
.push((expr, self.semantic.snapshot()));
}
}
ast::TypeParam::ParamSpec(ast::TypeParamParamSpec {
default,
name: _,
range: _,
}) => {
if let Some(expr) = default {
self.visit
.type_param_definitions
.push((expr, self.semantic.snapshot()));
}
}
}
}

View file

@ -134,7 +134,7 @@ F821_17.py:77:15: F821 Undefined name `DoesNotExist1`
77 | class Foo[T: (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
78 |
79 | # Type parameters in nested classes
79 | # Same in defaults
|
F821_17.py:77:30: F821 Undefined name `DoesNotExist2`
@ -144,35 +144,117 @@ F821_17.py:77:30: F821 Undefined name `DoesNotExist2`
77 | class Foo[T: (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
78 |
79 | # Type parameters in nested classes
79 | # Same in defaults
|
F821_17.py:92:52: F821 Undefined name `t`
F821_17.py:81:14: F821 Undefined name `DoesNotExist`
|
90 | return x
91 |
92 | def cannot_access_parent_variable(self, x: t) -> t: # F821: Undefined name `T`
| ^ F821
93 | t # F821: Undefined name `t`
94 | return x
79 | # Same in defaults
80 |
81 | type Foo[T = DoesNotExist] = T # F821: Undefined name `DoesNotExist`
| ^^^^^^^^^^^^ F821
82 | def foo[T = DoesNotExist](t: T) -> T: return t # F821: Undefined name `DoesNotExist`
83 | class Foo[T = DoesNotExist](list[T]): ... # F821: Undefined name `DoesNotExist`
|
F821_17.py:92:58: F821 Undefined name `t`
F821_17.py:82:13: F821 Undefined name `DoesNotExist`
|
90 | return x
91 |
92 | def cannot_access_parent_variable(self, x: t) -> t: # F821: Undefined name `T`
| ^ F821
93 | t # F821: Undefined name `t`
94 | return x
81 | type Foo[T = DoesNotExist] = T # F821: Undefined name `DoesNotExist`
82 | def foo[T = DoesNotExist](t: T) -> T: return t # F821: Undefined name `DoesNotExist`
| ^^^^^^^^^^^^ F821
83 | class Foo[T = DoesNotExist](list[T]): ... # F821: Undefined name `DoesNotExist`
|
F821_17.py:93:17: F821 Undefined name `t`
F821_17.py:83:15: F821 Undefined name `DoesNotExist`
|
92 | def cannot_access_parent_variable(self, x: t) -> t: # F821: Undefined name `T`
93 | t # F821: Undefined name `t`
| ^ F821
94 | return x
81 | type Foo[T = DoesNotExist] = T # F821: Undefined name `DoesNotExist`
82 | def foo[T = DoesNotExist](t: T) -> T: return t # F821: Undefined name `DoesNotExist`
83 | class Foo[T = DoesNotExist](list[T]): ... # F821: Undefined name `DoesNotExist`
| ^^^^^^^^^^^^ F821
84 |
85 | type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
|
F821_17.py:85:15: F821 Undefined name `DoesNotExist1`
|
83 | class Foo[T = DoesNotExist](list[T]): ... # F821: Undefined name `DoesNotExist`
84 |
85 | type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
86 | def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
87 | class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
|
F821_17.py:85:30: F821 Undefined name `DoesNotExist2`
|
83 | class Foo[T = DoesNotExist](list[T]): ... # F821: Undefined name `DoesNotExist`
84 |
85 | type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
86 | def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
87 | class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
|
F821_17.py:86:14: F821 Undefined name `DoesNotExist1`
|
85 | type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
86 | def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
87 | class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
|
F821_17.py:86:29: F821 Undefined name `DoesNotExist2`
|
85 | type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
86 | def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
87 | class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
|
F821_17.py:87:16: F821 Undefined name `DoesNotExist1`
|
85 | type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
86 | def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
87 | class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
88 |
89 | # Type parameters in nested classes
|
F821_17.py:87:31: F821 Undefined name `DoesNotExist2`
|
85 | type Foo[T = (DoesNotExist1, DoesNotExist2)] = T # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
86 | def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
87 | class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ... # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
| ^^^^^^^^^^^^^ F821
88 |
89 | # Type parameters in nested classes
|
F821_17.py:102:52: F821 Undefined name `t`
|
100 | return x
101 |
102 | def cannot_access_parent_variable(self, x: t) -> t: # F821: Undefined name `T`
| ^ F821
103 | t # F821: Undefined name `t`
104 | return x
|
F821_17.py:102:58: F821 Undefined name `t`
|
100 | return x
101 |
102 | def cannot_access_parent_variable(self, x: t) -> t: # F821: Undefined name `T`
| ^ F821
103 | t # F821: Undefined name `t`
104 | return x
|
F821_17.py:103:17: F821 Undefined name `t`
|
102 | def cannot_access_parent_variable(self, x: t) -> t: # F821: Undefined name `T`
103 | t # F821: Undefined name `t`
| ^ F821
104 | return x
|

View file

@ -132,6 +132,9 @@ pub(crate) fn non_pep695_type_alias(checker: &mut Checker, stmt: &StmtAnnAssign)
}
None => None,
},
// We don't handle defaults here yet. Should perhaps be a different rule since
// defaults are only valid in 3.13+.
default: None,
})
})
.collect(),

View file

@ -1173,21 +1173,29 @@ impl<'a> From<&'a ast::TypeParam> for ComparableTypeParam<'a> {
ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
name,
bound,
default,
range: _,
}) => Self::TypeVar(TypeParamTypeVar {
name: name.as_str(),
bound: bound.as_ref().map(Into::into),
default: default.as_ref().map(Into::into),
}),
ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple {
name,
default,
range: _,
}) => Self::TypeVarTuple(TypeParamTypeVarTuple {
name: name.as_str(),
default: default.as_ref().map(Into::into),
}),
ast::TypeParam::ParamSpec(ast::TypeParamParamSpec {
name,
default,
range: _,
}) => Self::ParamSpec(TypeParamParamSpec {
name: name.as_str(),
default: default.as_ref().map(Into::into),
}),
ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { name, range: _ }) => {
Self::TypeVarTuple(TypeParamTypeVarTuple {
name: name.as_str(),
})
}
ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { name, range: _ }) => {
Self::ParamSpec(TypeParamParamSpec {
name: name.as_str(),
})
}
}
}
}
@ -1196,16 +1204,19 @@ impl<'a> From<&'a ast::TypeParam> for ComparableTypeParam<'a> {
pub struct TypeParamTypeVar<'a> {
pub name: &'a str,
pub bound: Option<Box<ComparableExpr<'a>>>,
pub default: Option<Box<ComparableExpr<'a>>>,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TypeParamParamSpec<'a> {
pub name: &'a str,
pub default: Option<Box<ComparableExpr<'a>>>,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TypeParamTypeVarTuple<'a> {
pub name: &'a str,
pub default: Option<Box<ComparableExpr<'a>>>,
}
#[derive(Debug, PartialEq, Eq, Hash)]

View file

@ -264,11 +264,20 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
pub fn any_over_type_param(type_param: &TypeParam, func: &dyn Fn(&Expr) -> bool) -> bool {
match type_param {
TypeParam::TypeVar(ast::TypeParamTypeVar { bound, .. }) => bound
TypeParam::TypeVar(ast::TypeParamTypeVar { bound, default, .. }) => {
bound
.as_ref()
.is_some_and(|value| any_over_expr(value, func))
|| default
.as_ref()
.is_some_and(|value| any_over_expr(value, func))
}
TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { default, .. }) => default
.as_ref()
.is_some_and(|value| any_over_expr(value, func)),
TypeParam::ParamSpec(ast::TypeParamParamSpec { default, .. }) => default
.as_ref()
.is_some_and(|value| any_over_expr(value, func)),
TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { .. }) => false,
TypeParam::ParamSpec(ast::TypeParamParamSpec { .. }) => false,
}
}
@ -1619,11 +1628,13 @@ mod tests {
let type_var_one = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
bound: Some(Box::new(constant_one.clone())),
default: None,
name: Identifier::new("x", TextRange::default()),
});
let type_var_two = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
bound: Some(Box::new(constant_two.clone())),
bound: None,
default: Some(Box::new(constant_two.clone())),
name: Identifier::new("x", TextRange::default()),
});
let type_alias = Stmt::TypeAlias(StmtTypeAlias {
@ -1650,30 +1661,49 @@ mod tests {
let type_var_no_bound = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
bound: None,
default: None,
name: Identifier::new("x", TextRange::default()),
});
assert!(!any_over_type_param(&type_var_no_bound, &|_expr| true));
let bound = Expr::NumberLiteral(ExprNumberLiteral {
let constant = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::ONE),
range: TextRange::default(),
});
let type_var_with_bound = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
bound: Some(Box::new(bound.clone())),
bound: Some(Box::new(constant.clone())),
default: None,
name: Identifier::new("x", TextRange::default()),
});
assert!(
any_over_type_param(&type_var_with_bound, &|expr| {
assert_eq!(
*expr, bound,
*expr, constant,
"the received expression should be the unwrapped bound"
);
true
}),
"if true is returned from `func` it should be respected"
);
let type_var_with_default = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
default: Some(Box::new(constant.clone())),
bound: None,
name: Identifier::new("x", TextRange::default()),
});
assert!(
any_over_type_param(&type_var_with_default, &|expr| {
assert_eq!(
*expr, constant,
"the received expression should be the unwrapped default"
);
true
}),
"if true is returned from `func` it should be respected"
);
}
#[test]
@ -1681,10 +1711,32 @@ mod tests {
let type_var_tuple = TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
range: TextRange::default(),
name: Identifier::new("x", TextRange::default()),
default: None,
});
assert!(
!any_over_type_param(&type_var_tuple, &|_expr| true),
"type var tuples have no expressions to visit"
"this TypeVarTuple has no expressions to visit"
);
let constant = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::ONE),
range: TextRange::default(),
});
let type_var_tuple_with_default = TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
range: TextRange::default(),
default: Some(Box::new(constant.clone())),
name: Identifier::new("x", TextRange::default()),
});
assert!(
any_over_type_param(&type_var_tuple_with_default, &|expr| {
assert_eq!(
*expr, constant,
"the received expression should be the unwrapped default"
);
true
}),
"if true is returned from `func` it should be respected"
);
}
@ -1693,10 +1745,32 @@ mod tests {
let type_param_spec = TypeParam::ParamSpec(TypeParamParamSpec {
range: TextRange::default(),
name: Identifier::new("x", TextRange::default()),
default: None,
});
assert!(
!any_over_type_param(&type_param_spec, &|_expr| true),
"param specs have no expressions to visit"
"this ParamSpec has no expressions to visit"
);
let constant = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::ONE),
range: TextRange::default(),
});
let param_spec_with_default = TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
range: TextRange::default(),
default: Some(Box::new(constant.clone())),
name: Identifier::new("x", TextRange::default()),
});
assert!(
any_over_type_param(&param_spec_with_default, &|expr| {
assert_eq!(
*expr, constant,
"the received expression should be the unwrapped default"
);
true
}),
"if true is returned from `func` it should be respected"
);
}
}

View file

@ -4317,6 +4317,7 @@ impl AstNode for ast::TypeParamTypeVar {
{
let ast::TypeParamTypeVar {
bound,
default,
name: _,
range: _,
} = self;
@ -4324,6 +4325,9 @@ impl AstNode for ast::TypeParamTypeVar {
if let Some(expr) = bound {
visitor.visit_expr(expr);
}
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
}
impl AstNode for ast::TypeParamTypeVarTuple {
@ -4355,11 +4359,18 @@ impl AstNode for ast::TypeParamTypeVarTuple {
}
#[inline]
fn visit_preorder<'a, V>(&'a self, _visitor: &mut V)
fn visit_preorder<'a, V>(&'a self, visitor: &mut V)
where
V: PreorderVisitor<'a> + ?Sized,
{
let ast::TypeParamTypeVarTuple { range: _, name: _ } = self;
let ast::TypeParamTypeVarTuple {
range: _,
name: _,
default,
} = self;
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
}
impl AstNode for ast::TypeParamParamSpec {
@ -4391,11 +4402,18 @@ impl AstNode for ast::TypeParamParamSpec {
}
#[inline]
fn visit_preorder<'a, V>(&'a self, _visitor: &mut V)
fn visit_preorder<'a, V>(&'a self, visitor: &mut V)
where
V: PreorderVisitor<'a> + ?Sized,
{
let ast::TypeParamParamSpec { range: _, name: _ } = self;
let ast::TypeParamParamSpec {
range: _,
name: _,
default,
} = self;
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
}
impl AstNode for ast::FString {

View file

@ -3132,6 +3132,7 @@ pub struct TypeParamTypeVar {
pub range: TextRange,
pub name: Identifier,
pub bound: Option<Box<Expr>>,
pub default: Option<Box<Expr>>,
}
impl From<TypeParamTypeVar> for TypeParam {
@ -3145,6 +3146,7 @@ impl From<TypeParamTypeVar> for TypeParam {
pub struct TypeParamParamSpec {
pub range: TextRange,
pub name: Identifier,
pub default: Option<Box<Expr>>,
}
impl From<TypeParamParamSpec> for TypeParam {
@ -3158,6 +3160,7 @@ impl From<TypeParamParamSpec> for TypeParam {
pub struct TypeParamTypeVarTuple {
pub range: TextRange,
pub name: Identifier,
pub default: Option<Box<Expr>>,
}
impl From<TypeParamTypeVarTuple> for TypeParam {

View file

@ -7,7 +7,8 @@ use crate::{
self as ast, Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator,
ElifElseClause, ExceptHandler, Expr, ExprContext, FString, FStringElement, FStringPart,
Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, PatternArguments, PatternKeyword,
Stmt, StringLiteral, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem,
Stmt, StringLiteral, TypeParam, TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple,
TypeParams, UnaryOp, WithItem,
};
/// A trait for AST visitors. Visits all nodes in the AST recursively in evaluation-order.
@ -666,14 +667,35 @@ pub fn walk_type_param<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, type_param:
match type_param {
TypeParam::TypeVar(TypeParamTypeVar {
bound,
default,
name: _,
range: _,
}) => {
if let Some(expr) = bound {
visitor.visit_expr(expr);
}
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
default,
name: _,
range: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
TypeParam::ParamSpec(TypeParamParamSpec {
default,
name: _,
range: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
TypeParam::TypeVarTuple(_) | TypeParam::ParamSpec(_) => {}
}
}

View file

@ -2,7 +2,8 @@ use crate::{
self as ast, Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator,
ElifElseClause, ExceptHandler, Expr, ExprContext, FString, FStringElement, Keyword, MatchCase,
Operator, Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt,
StringLiteral, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem,
StringLiteral, TypeParam, TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple,
TypeParams, UnaryOp, WithItem,
};
/// A trait for transforming ASTs. Visits all nodes in the AST recursively in evaluation-order.
@ -652,14 +653,35 @@ pub fn walk_type_param<V: Transformer + ?Sized>(visitor: &V, type_param: &mut Ty
match type_param {
TypeParam::TypeVar(TypeParamTypeVar {
bound,
default,
name: _,
range: _,
}) => {
if let Some(expr) = bound {
visitor.visit_expr(expr);
}
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
default,
name: _,
range: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
TypeParam::ParamSpec(TypeParamParamSpec {
default,
name: _,
range: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);
}
}
TypeParam::TypeVarTuple(_) | TypeParam::ParamSpec(_) => {}
}
}

View file

@ -756,20 +756,37 @@ impl<'a> Generator<'a> {
pub(crate) fn unparse_type_param(&mut self, ast: &TypeParam) {
match ast {
TypeParam::TypeVar(TypeParamTypeVar { name, bound, .. }) => {
TypeParam::TypeVar(TypeParamTypeVar {
name,
bound,
default,
..
}) => {
self.p_id(name);
if let Some(expr) = bound {
self.p(": ");
self.unparse_expr(expr, precedence::MAX);
}
if let Some(expr) = default {
self.p(" = ");
self.unparse_expr(expr, precedence::MAX);
}
}
TypeParam::TypeVarTuple(TypeParamTypeVarTuple { name, .. }) => {
TypeParam::TypeVarTuple(TypeParamTypeVarTuple { name, default, .. }) => {
self.p("*");
self.p_id(name);
if let Some(expr) = default {
self.p(" = ");
self.unparse_expr(expr, precedence::MAX);
}
}
TypeParam::ParamSpec(TypeParamParamSpec { name, .. }) => {
TypeParam::ParamSpec(TypeParamParamSpec { name, default, .. }) => {
self.p("**");
self.p_id(name);
if let Some(expr) = default {
self.p(" = ");
self.unparse_expr(expr, precedence::MAX);
}
}
}
}
@ -1676,6 +1693,10 @@ class Foo:
assert_round_trip!(r"type Foo[T] = list[T]");
assert_round_trip!(r"type Foo[*Ts] = ...");
assert_round_trip!(r"type Foo[**P] = ...");
assert_round_trip!(r"type Foo[T = int] = list[T]");
assert_round_trip!(r"type Foo[*Ts = int] = ...");
assert_round_trip!(r"type Foo[*Ts = *int] = ...");
assert_round_trip!(r"type Foo[**P = int] = ...");
assert_round_trip!(r"type Foo[T, U, *Ts, **P] = ...");
// https://github.com/astral-sh/ruff/issues/6498
assert_round_trip!(r"f(a=1, *args, **kwargs)");

View file

@ -433,3 +433,6 @@ def function_with_one_argument_and_a_keyword_separator(
# https://peps.python.org/pep-0646/#change-2-args-as-a-typevartuple
def function_with_variadic_generics(*args: *tuple[int]): ...
def function_with_variadic_generics(*args: *tuple[int],): ...
# Generic arguments (PEP 695)
def func[T](lotsoflongargs: T, lotsoflongargs2: T, lotsoflongargs3: T, lotsoflongargs4: T, lotsoflongargs5: T) -> T: ...

View file

@ -1,11 +1,15 @@
# basic usage
type X = int
type X = int | str
type X = int | "ForwardRefY"
type X[T] = T | list[X[T]] # recursive
type X[T] = int
type X[T] = list[T] | set[T]
type X[T=int]=int
type X[T:int=int]=int
type X[**P=int]=int
type X[*Ts=int]=int
type X[*Ts=*int]=int
type X[T, *Ts, **P] = (T, Ts, P)
type X[T: int, *Ts, **P] = (T, Ts, P)
type X[T: (int, str), *Ts, **P] = (T, Ts, P)
@ -49,6 +53,18 @@ type X \
[T] = T
type X[T] \
= T
type X[T
] = T
# bounds and defaults with multiline definitions
type X[T
:int ] = int
type X[T:
int] = int
type X[T
= int] = int
type X[T=
int] = int
# type leading comment
type X = ( # trailing open paren comment
@ -94,3 +110,43 @@ type bounds_single_line[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, cccc
type bounds_arguments_on_their_own_line[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)] = T
type bounds_argument_per_line[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc, ddddddddddddd, eeeeeeeeeeeeeeee, ffffffffffff)] = T
type bounds_trailing_comma[T: (a, b,)] = T
# bounds plus comments
type comment_before_colon[T # comment
: int] = T
type comment_after_colon[T: # comment
int] = T
type comment_on_its_own_line[T
# comment
:
# another comment
int
# why not another
] = T
# type variable defaults
type defaults_single_line[T= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc)] = T
type defaults_on_their_own_line[T= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)] = T
type defaults_one_per_line[T= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc, ddddddddddddd, eeeeeeeeeeeeeeee, ffffffffffff)] = T
type defaults_trailing_comma[T= (a, b,)] = T
# defaults plus comments
type comment_before_colon[T # comment
= int] = T
type comment_after_colon[T = # comment
int] = T
type comment_on_its_own_line[T
# comment
=
# another comment
int
# why not another
] = T
type after_star[*Ts = *
# comment
int] = int
# both bounds and defaults
type bound_and_default[T:int=int] = int
type long_bound_short_default[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)=a]=int
type short_bound_long_default[T:a= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)]=int

View file

@ -8,7 +8,15 @@ pub struct FormatTypeParamParamSpec;
impl FormatNodeRule<TypeParamParamSpec> for FormatTypeParamParamSpec {
fn fmt_fields(&self, item: &TypeParamParamSpec, f: &mut PyFormatter) -> FormatResult<()> {
let TypeParamParamSpec { range: _, name } = item;
write!(f, [token("**"), name.format()])
let TypeParamParamSpec {
range: _,
name,
default,
} = item;
write!(f, [token("**"), name.format()])?;
if let Some(default) = default {
write!(f, [space(), token("="), space(), default.format()])?;
}
Ok(())
}
}

View file

@ -12,11 +12,15 @@ impl FormatNodeRule<TypeParamTypeVar> for FormatTypeParamTypeVar {
range: _,
name,
bound,
default,
} = item;
name.format().fmt(f)?;
if let Some(bound) = bound {
write!(f, [token(":"), space(), bound.format()])?;
}
if let Some(default) = default {
write!(f, [space(), token("="), space(), default.format()])?;
}
Ok(())
}
}

View file

@ -8,7 +8,15 @@ pub struct FormatTypeParamTypeVarTuple;
impl FormatNodeRule<TypeParamTypeVarTuple> for FormatTypeParamTypeVarTuple {
fn fmt_fields(&self, item: &TypeParamTypeVarTuple, f: &mut PyFormatter) -> FormatResult<()> {
let TypeParamTypeVarTuple { range: _, name } = item;
write!(f, [token("*"), name.format()])
let TypeParamTypeVarTuple {
range: _,
name,
default,
} = item;
write!(f, [token("*"), name.format()])?;
if let Some(default) = default {
write!(f, [space(), token("="), space(), default.format()])?;
}
Ok(())
}
}

View file

@ -439,6 +439,9 @@ def function_with_one_argument_and_a_keyword_separator(
# https://peps.python.org/pep-0646/#change-2-args-as-a-typevartuple
def function_with_variadic_generics(*args: *tuple[int]): ...
def function_with_variadic_generics(*args: *tuple[int],): ...
# Generic arguments (PEP 695)
def func[T](lotsoflongargs: T, lotsoflongargs2: T, lotsoflongargs3: T, lotsoflongargs4: T, lotsoflongargs5: T) -> T: ...
```
## Output
@ -1028,4 +1031,14 @@ def function_with_variadic_generics(*args: *tuple[int]): ...
def function_with_variadic_generics(
*args: *tuple[int],
): ...
# Generic arguments (PEP 695)
def func[T](
lotsoflongargs: T,
lotsoflongargs2: T,
lotsoflongargs3: T,
lotsoflongargs4: T,
lotsoflongargs5: T,
) -> T: ...
```

View file

@ -5,13 +5,17 @@ input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/
## Input
```python
# basic usage
type X = int
type X = int | str
type X = int | "ForwardRefY"
type X[T] = T | list[X[T]] # recursive
type X[T] = int
type X[T] = list[T] | set[T]
type X[T=int]=int
type X[T:int=int]=int
type X[**P=int]=int
type X[*Ts=int]=int
type X[*Ts=*int]=int
type X[T, *Ts, **P] = (T, Ts, P)
type X[T: int, *Ts, **P] = (T, Ts, P)
type X[T: (int, str), *Ts, **P] = (T, Ts, P)
@ -55,6 +59,18 @@ type X \
[T] = T
type X[T] \
= T
type X[T
] = T
# bounds and defaults with multiline definitions
type X[T
:int ] = int
type X[T:
int] = int
type X[T
= int] = int
type X[T=
int] = int
# type leading comment
type X = ( # trailing open paren comment
@ -100,18 +116,62 @@ type bounds_single_line[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, cccc
type bounds_arguments_on_their_own_line[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)] = T
type bounds_argument_per_line[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc, ddddddddddddd, eeeeeeeeeeeeeeee, ffffffffffff)] = T
type bounds_trailing_comma[T: (a, b,)] = T
# bounds plus comments
type comment_before_colon[T # comment
: int] = T
type comment_after_colon[T: # comment
int] = T
type comment_on_its_own_line[T
# comment
:
# another comment
int
# why not another
] = T
# type variable defaults
type defaults_single_line[T= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc)] = T
type defaults_on_their_own_line[T= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)] = T
type defaults_one_per_line[T= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc, ddddddddddddd, eeeeeeeeeeeeeeee, ffffffffffff)] = T
type defaults_trailing_comma[T= (a, b,)] = T
# defaults plus comments
type comment_before_colon[T # comment
= int] = T
type comment_after_colon[T = # comment
int] = T
type comment_on_its_own_line[T
# comment
=
# another comment
int
# why not another
] = T
type after_star[*Ts = *
# comment
int] = int
# both bounds and defaults
type bound_and_default[T:int=int] = int
type long_bound_short_default[T: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)=a]=int
type short_bound_long_default[T:a= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee)]=int
```
## Output
```python
# basic usage
type X = int
type X = int | str
type X = int | "ForwardRefY"
type X[T] = T | list[X[T]] # recursive
type X[T] = int
type X[T] = list[T] | set[T]
type X[T = int] = int
type X[T: int = int] = int
type X[**P = int] = int
type X[*Ts = int] = int
type X[*Ts = *int] = int
type X[T, *Ts, **P] = (T, Ts, P)
type X[T: int, *Ts, **P] = (T, Ts, P)
type X[T: (int, str), *Ts, **P] = (T, Ts, P)
@ -162,6 +222,13 @@ type X = int
type X[T] = T
type X[T] = T
type X[T] = T
type X[T] = T
# bounds and defaults with multiline definitions
type X[T: int] = int
type X[T: int] = int
type X[T = int] = int
type X[T = int] = int
# type leading comment
type X = ( # trailing open paren comment
@ -248,7 +315,91 @@ type bounds_trailing_comma[
b,
)
] = T
# bounds plus comments
type comment_before_colon[
T: # comment
int
] = T
type comment_after_colon[
T: # comment
int
] = T
type comment_on_its_own_line[
T: # comment
# another comment
int
# why not another
] = T
# type variable defaults
type defaults_single_line[
T = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc)
] = T
type defaults_on_their_own_line[
T = (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbb,
ccccccccccc,
ddddddddddddd,
eeeeeee,
)
] = T
type defaults_one_per_line[
T = (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbb,
ccccccccccccccccc,
ddddddddddddd,
eeeeeeeeeeeeeeee,
ffffffffffff,
)
] = T
type defaults_trailing_comma[
T = (
a,
b,
)
] = T
# defaults plus comments
type comment_before_colon[
T = # comment
int
] = T
type comment_after_colon[
T = # comment
int
] = T
type comment_on_its_own_line[
T = # comment
# another comment
int
# why not another
] = T
type after_star[
*Ts = # comment
*int
] = int
# both bounds and defaults
type bound_and_default[T: int = int] = int
type long_bound_short_default[
T: (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbb,
ccccccccccc,
ddddddddddddd,
eeeeeee,
) = a
] = int
type short_bound_long_default[
T: a = (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbb,
ccccccccccc,
ddddddddddddd,
eeeeeee,
)
] = int
```

View file

@ -0,0 +1,5 @@
type X[**P = *int] = int
type X[**P = yield x] = int
type X[**P = yield from x] = int
type X[**P = x := int] = int
type X[**P = *int] = int

View file

@ -0,0 +1,2 @@
type X[**P =] = int
type X[**P =, T2] = int

View file

@ -0,0 +1,6 @@
type X[T = *int] = int
type X[T = yield x] = int
type X[T = (yield x)] = int
type X[T = yield from x] = int
type X[T = x := int] = int
type X[T: int = *int] = int

View file

@ -0,0 +1,3 @@
type X[T =] = int
type X[T: int =] = int
type X[T1 =, T2] = int

View file

@ -0,0 +1,5 @@
type X[*Ts = *int] = int
type X[*Ts = *int or str] = int
type X[*Ts = yield x] = int
type X[*Ts = yield from x] = int
type X[*Ts = x := int] = int

View file

@ -0,0 +1,2 @@
type X[*Ts =] = int
type X[*Ts =, T2] = int

View file

@ -0,0 +1,4 @@
type X[**P] = int
type X[**P = int] = int
type X[T, **P] = int
type X[T, **P = int] = int

View file

@ -0,0 +1,5 @@
type X[T] = int
type X[T = int] = int
type X[T: int = int] = int
type X[T: (int, int) = int] = int
type X[T: int = int, U: (int, int) = int] = int

View file

@ -0,0 +1,5 @@
type X[*Ts] = int
type X[*Ts = int] = int
type X[*Ts = *int] = int
type X[T, *Ts] = int
type X[T, *Ts = int] = int

View file

@ -29,9 +29,15 @@ class Test(A, B):
# TypeVar
class Test[T](): ...
# TypeVar with default
class Test[T = str](): ...
# TypeVar with bound
class Test[T: str](): ...
# TypeVar with bound and default
class Test[T: int | str = int](): ...
# TypeVar with tuple bound
class Test[T: (str, bytes)](): ...
@ -44,9 +50,18 @@ class Test[T, U,](): ...
# TypeVarTuple
class Test[*Ts](): ...
# TypeVarTuple with default
class Test[*Ts = Unpack[tuple[int, str]]](): ...
# TypeVarTuple with starred default
class Test[*Ts = *tuple[int, str]](): ...
# ParamSpec
class Test[**P](): ...
# ParamSpec with default
class Test[**P = [int, str]](): ...
# Mixed types
class Test[X, Y: str, *U, **P]():
pass

View file

@ -7,6 +7,10 @@ type X[T] = list[T] | set[T]
type X[T, *Ts, **P] = (T, Ts, P)
type X[T: int, *Ts, **P] = (T, Ts, P)
type X[T: (int, str), *Ts, **P] = (T, Ts, P)
type X[T = int] = T | str
type X[T: int | str = int] = T | int | str
type X[*Ts = *tuple[int, str]] = tuple[int, *Ts, str]
type X[**P = [int, str]] = Callable[P, str]
# Soft keyword as alias name
type type = int

View file

@ -3160,24 +3160,95 @@ impl<'src> Parser<'src> {
// We should do the same but currently we can't without throwing away the parsed
// expression because the AST can't contain it.
// test_ok type_param_type_var_tuple
// type X[*Ts] = int
// type X[*Ts = int] = int
// type X[*Ts = *int] = int
// type X[T, *Ts] = int
// type X[T, *Ts = int] = int
if self.eat(TokenKind::Star) {
let name = self.parse_identifier();
let default = if self.eat(TokenKind::Equal) {
if self.at_expr() {
// test_err type_param_type_var_tuple_invalid_default_expr
// type X[*Ts = *int] = int
// type X[*Ts = *int or str] = int
// type X[*Ts = yield x] = int
// type X[*Ts = yield from x] = int
// type X[*Ts = x := int] = int
Some(Box::new(
self.parse_conditional_expression_or_higher_impl(
ExpressionContext::starred_bitwise_or(),
)
.expr,
))
} else {
// test_err type_param_type_var_tuple_missing_default
// type X[*Ts =] = int
// type X[*Ts =, T2] = int
self.add_error(
ParseErrorType::ExpectedExpression,
self.current_token_range(),
);
None
}
} else {
None
};
// test_err type_param_type_var_tuple_bound
// type X[*T: int] = int
ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple {
range: self.node_range(start),
name,
default,
})
// test_ok type_param_param_spec
// type X[**P] = int
// type X[**P = int] = int
// type X[T, **P] = int
// type X[T, **P = int] = int
} else if self.eat(TokenKind::DoubleStar) {
let name = self.parse_identifier();
let default = if self.eat(TokenKind::Equal) {
if self.at_expr() {
// test_err type_param_param_spec_invalid_default_expr
// type X[**P = *int] = int
// type X[**P = yield x] = int
// type X[**P = yield from x] = int
// type X[**P = x := int] = int
// type X[**P = *int] = int
Some(Box::new(self.parse_conditional_expression_or_higher().expr))
} else {
// test_err type_param_param_spec_missing_default
// type X[**P =] = int
// type X[**P =, T2] = int
self.add_error(
ParseErrorType::ExpectedExpression,
self.current_token_range(),
);
None
}
} else {
None
};
// test_err type_param_param_spec_bound
// type X[**T: int] = int
ast::TypeParam::ParamSpec(ast::TypeParamParamSpec {
range: self.node_range(start),
name,
default,
})
// test_ok type_param_type_var
// type X[T] = int
// type X[T = int] = int
// type X[T: int = int] = int
// type X[T: (int, int) = int] = int
// type X[T: int = int, U: (int, int) = int] = int
} else {
let name = self.parse_identifier();
@ -3203,10 +3274,36 @@ impl<'src> Parser<'src> {
None
};
let default = if self.eat(TokenKind::Equal) {
if self.at_expr() {
// test_err type_param_type_var_invalid_default_expr
// type X[T = *int] = int
// type X[T = yield x] = int
// type X[T = (yield x)] = int
// type X[T = yield from x] = int
// type X[T = x := int] = int
// type X[T: int = *int] = int
Some(Box::new(self.parse_conditional_expression_or_higher().expr))
} else {
// test_err type_param_type_var_missing_default
// type X[T =] = int
// type X[T: int =] = int
// type X[T1 =, T2] = int
self.add_error(
ParseErrorType::ExpectedExpression,
self.current_token_range(),
);
None
}
} else {
None
};
ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
range: self.node_range(start),
name,
bound,
default,
})
}
}

View file

@ -29,6 +29,7 @@ Module(
range: 10..12,
},
bound: None,
default: None,
},
),
TypeVarTuple(
@ -38,6 +39,7 @@ Module(
id: "T2",
range: 15..17,
},
default: None,
},
),
],

View file

@ -30,6 +30,7 @@ Module(
range: 8..10,
},
bound: None,
default: None,
},
),
TypeVarTuple(
@ -39,6 +40,7 @@ Module(
id: "T2",
range: 13..15,
},
default: None,
},
),
],

View file

@ -30,6 +30,7 @@ Module(
range: 807..808,
},
bound: None,
default: None,
},
),
TypeVar(
@ -40,6 +41,7 @@ Module(
range: 810..815,
},
bound: None,
default: None,
},
),
],
@ -89,6 +91,7 @@ Module(
range: 846..847,
},
bound: None,
default: None,
},
),
TypeVar(
@ -99,6 +102,7 @@ Module(
range: 852..853,
},
bound: None,
default: None,
},
),
],
@ -148,6 +152,7 @@ Module(
range: 883..884,
},
bound: None,
default: None,
},
),
TypeVar(
@ -158,6 +163,7 @@ Module(
range: 886..887,
},
bound: None,
default: None,
},
),
],
@ -207,6 +213,7 @@ Module(
range: 926..927,
},
bound: None,
default: None,
},
),
],
@ -256,6 +263,7 @@ Module(
range: 972..973,
},
bound: None,
default: None,
},
),
],

View file

@ -45,6 +45,7 @@ Module(
},
),
),
default: None,
},
),
],
@ -96,6 +97,7 @@ Module(
},
),
),
default: None,
},
),
],
@ -145,6 +147,7 @@ Module(
},
),
),
default: None,
},
),
],
@ -189,6 +192,7 @@ Module(
},
),
),
default: None,
},
),
TypeVar(
@ -199,6 +203,7 @@ Module(
range: 92..95,
},
bound: None,
default: None,
},
),
],

View file

@ -31,6 +31,7 @@ Module(
range: 7..8,
},
bound: None,
default: None,
},
),
],
@ -67,6 +68,7 @@ Module(
range: 25..27,
},
bound: None,
default: None,
},
),
TypeVar(
@ -77,6 +79,7 @@ Module(
range: 31..33,
},
bound: None,
default: None,
},
),
],

View file

@ -30,6 +30,7 @@ Module(
id: "T",
range: 9..10,
},
default: None,
},
),
],

View file

@ -0,0 +1,314 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_param_param_spec_invalid_default_expr.py
---
## AST
```
Module(
ModModule {
range: 0..140,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..24,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..18,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 7..17,
name: Identifier {
id: "P",
range: 9..10,
},
default: Some(
Starred(
ExprStarred {
range: 13..17,
value: Name(
ExprName {
range: 14..17,
id: "int",
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 21..24,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 25..52,
name: Name(
ExprName {
range: 30..31,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 31..46,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 32..45,
name: Identifier {
id: "P",
range: 34..35,
},
default: Some(
Yield(
ExprYield {
range: 38..45,
value: Some(
Name(
ExprName {
range: 44..45,
id: "x",
ctx: Load,
},
),
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 49..52,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 53..85,
name: Name(
ExprName {
range: 58..59,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 59..79,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 60..78,
name: Identifier {
id: "P",
range: 62..63,
},
default: Some(
YieldFrom(
ExprYieldFrom {
range: 66..78,
value: Name(
ExprName {
range: 77..78,
id: "x",
ctx: Load,
},
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 82..85,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 86..114,
name: Name(
ExprName {
range: 91..92,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 92..108,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 93..100,
name: Identifier {
id: "P",
range: 95..96,
},
default: Some(
Name(
ExprName {
range: 99..100,
id: "x",
ctx: Load,
},
),
),
},
),
TypeVar(
TypeParamTypeVar {
range: 104..107,
name: Identifier {
id: "int",
range: 104..107,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 111..114,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 115..139,
name: Name(
ExprName {
range: 120..121,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 121..133,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 122..132,
name: Identifier {
id: "P",
range: 124..125,
},
default: Some(
Starred(
ExprStarred {
range: 128..132,
value: Name(
ExprName {
range: 129..132,
id: "int",
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 136..139,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```
## Errors
|
1 | type X[**P = *int] = int
| ^^^^ Syntax Error: Starred expression cannot be used here
2 | type X[**P = yield x] = int
3 | type X[**P = yield from x] = int
|
|
1 | type X[**P = *int] = int
2 | type X[**P = yield x] = int
| ^^^^^^^ Syntax Error: Yield expression cannot be used here
3 | type X[**P = yield from x] = int
4 | type X[**P = x := int] = int
|
|
1 | type X[**P = *int] = int
2 | type X[**P = yield x] = int
3 | type X[**P = yield from x] = int
| ^^^^^^^^^^^^ Syntax Error: Yield expression cannot be used here
4 | type X[**P = x := int] = int
5 | type X[**P = *int] = int
|
|
2 | type X[**P = yield x] = int
3 | type X[**P = yield from x] = int
4 | type X[**P = x := int] = int
| ^^ Syntax Error: Expected ',', found ':='
5 | type X[**P = *int] = int
|
|
3 | type X[**P = yield from x] = int
4 | type X[**P = x := int] = int
5 | type X[**P = *int] = int
| ^^^^ Syntax Error: Starred expression cannot be used here
|

View file

@ -0,0 +1,112 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_param_param_spec_missing_default.py
---
## AST
```
Module(
ModModule {
range: 0..44,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..19,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..13,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 7..12,
name: Identifier {
id: "P",
range: 9..10,
},
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 16..19,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 20..43,
name: Name(
ExprName {
range: 25..26,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 26..37,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 27..32,
name: Identifier {
id: "P",
range: 29..30,
},
default: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 34..36,
name: Identifier {
id: "T2",
range: 34..36,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 40..43,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```
## Errors
|
1 | type X[**P =] = int
| ^ Syntax Error: Expected an expression
2 | type X[**P =, T2] = int
|
|
1 | type X[**P =] = int
2 | type X[**P =, T2] = int
| ^ Syntax Error: Expected an expression
|

View file

@ -0,0 +1,379 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_param_type_var_invalid_default_expr.py
---
## AST
```
Module(
ModModule {
range: 0..163,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..22,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..16,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 7..15,
name: Identifier {
id: "T",
range: 7..8,
},
bound: None,
default: Some(
Starred(
ExprStarred {
range: 11..15,
value: Name(
ExprName {
range: 12..15,
id: "int",
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 19..22,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 23..48,
name: Name(
ExprName {
range: 28..29,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 29..42,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 30..41,
name: Identifier {
id: "T",
range: 30..31,
},
bound: None,
default: Some(
Yield(
ExprYield {
range: 34..41,
value: Some(
Name(
ExprName {
range: 40..41,
id: "x",
ctx: Load,
},
),
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 45..48,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 49..76,
name: Name(
ExprName {
range: 54..55,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 55..70,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 56..69,
name: Identifier {
id: "T",
range: 56..57,
},
bound: None,
default: Some(
Yield(
ExprYield {
range: 61..68,
value: Some(
Name(
ExprName {
range: 67..68,
id: "x",
ctx: Load,
},
),
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 73..76,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 77..107,
name: Name(
ExprName {
range: 82..83,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 83..101,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 84..100,
name: Identifier {
id: "T",
range: 84..85,
},
bound: None,
default: Some(
YieldFrom(
ExprYieldFrom {
range: 88..100,
value: Name(
ExprName {
range: 99..100,
id: "x",
ctx: Load,
},
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 104..107,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 108..134,
name: Name(
ExprName {
range: 113..114,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 114..128,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 115..120,
name: Identifier {
id: "T",
range: 115..116,
},
bound: None,
default: Some(
Name(
ExprName {
range: 119..120,
id: "x",
ctx: Load,
},
),
),
},
),
TypeVar(
TypeParamTypeVar {
range: 124..127,
name: Identifier {
id: "int",
range: 124..127,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 131..134,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 135..162,
name: Name(
ExprName {
range: 140..141,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 141..156,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 142..155,
name: Identifier {
id: "T",
range: 142..143,
},
bound: Some(
Name(
ExprName {
range: 145..148,
id: "int",
ctx: Load,
},
),
),
default: Some(
Starred(
ExprStarred {
range: 151..155,
value: Name(
ExprName {
range: 152..155,
id: "int",
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 159..162,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```
## Errors
|
1 | type X[T = *int] = int
| ^^^^ Syntax Error: Starred expression cannot be used here
2 | type X[T = yield x] = int
3 | type X[T = (yield x)] = int
|
|
1 | type X[T = *int] = int
2 | type X[T = yield x] = int
| ^^^^^^^ Syntax Error: Yield expression cannot be used here
3 | type X[T = (yield x)] = int
4 | type X[T = yield from x] = int
|
|
2 | type X[T = yield x] = int
3 | type X[T = (yield x)] = int
4 | type X[T = yield from x] = int
| ^^^^^^^^^^^^ Syntax Error: Yield expression cannot be used here
5 | type X[T = x := int] = int
6 | type X[T: int = *int] = int
|
|
3 | type X[T = (yield x)] = int
4 | type X[T = yield from x] = int
5 | type X[T = x := int] = int
| ^^ Syntax Error: Expected ',', found ':='
6 | type X[T: int = *int] = int
|
|
4 | type X[T = yield from x] = int
5 | type X[T = x := int] = int
6 | type X[T: int = *int] = int
| ^^^^ Syntax Error: Starred expression cannot be used here
|

View file

@ -0,0 +1,169 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_param_type_var_missing_default.py
---
## AST
```
Module(
ModModule {
range: 0..64,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..17,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..11,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 7..10,
name: Identifier {
id: "T",
range: 7..8,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 14..17,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 18..40,
name: Name(
ExprName {
range: 23..24,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 24..34,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 25..33,
name: Identifier {
id: "T",
range: 25..26,
},
bound: Some(
Name(
ExprName {
range: 28..31,
id: "int",
ctx: Load,
},
),
),
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 37..40,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 41..63,
name: Name(
ExprName {
range: 46..47,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 47..57,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 48..52,
name: Identifier {
id: "T1",
range: 48..50,
},
bound: None,
default: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 54..56,
name: Identifier {
id: "T2",
range: 54..56,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 60..63,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```
## Errors
|
1 | type X[T =] = int
| ^ Syntax Error: Expected an expression
2 | type X[T: int =] = int
3 | type X[T1 =, T2] = int
|
|
1 | type X[T =] = int
2 | type X[T: int =] = int
| ^ Syntax Error: Expected an expression
3 | type X[T1 =, T2] = int
|
|
1 | type X[T =] = int
2 | type X[T: int =] = int
3 | type X[T1 =, T2] = int
| ^ Syntax Error: Expected an expression
|

View file

@ -30,6 +30,7 @@ Module(
id: "T",
range: 8..9,
},
default: None,
},
),
],

View file

@ -0,0 +1,321 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_invalid_default_expr.py
---
## AST
```
Module(
ModModule {
range: 0..147,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..24,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..18,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 7..17,
name: Identifier {
id: "Ts",
range: 8..10,
},
default: Some(
Starred(
ExprStarred {
range: 13..17,
value: Name(
ExprName {
range: 14..17,
id: "int",
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 21..24,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 25..56,
name: Name(
ExprName {
range: 30..31,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 31..50,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 32..49,
name: Identifier {
id: "Ts",
range: 33..35,
},
default: Some(
Starred(
ExprStarred {
range: 38..49,
value: BoolOp(
ExprBoolOp {
range: 39..49,
op: Or,
values: [
Name(
ExprName {
range: 39..42,
id: "int",
ctx: Load,
},
),
Name(
ExprName {
range: 46..49,
id: "str",
ctx: Load,
},
),
],
},
),
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 53..56,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 57..84,
name: Name(
ExprName {
range: 62..63,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 63..78,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 64..77,
name: Identifier {
id: "Ts",
range: 65..67,
},
default: Some(
Yield(
ExprYield {
range: 70..77,
value: Some(
Name(
ExprName {
range: 76..77,
id: "x",
ctx: Load,
},
),
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 81..84,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 85..117,
name: Name(
ExprName {
range: 90..91,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 91..111,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 92..110,
name: Identifier {
id: "Ts",
range: 93..95,
},
default: Some(
YieldFrom(
ExprYieldFrom {
range: 98..110,
value: Name(
ExprName {
range: 109..110,
id: "x",
ctx: Load,
},
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 114..117,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 118..146,
name: Name(
ExprName {
range: 123..124,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 124..140,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 125..132,
name: Identifier {
id: "Ts",
range: 126..128,
},
default: Some(
Name(
ExprName {
range: 131..132,
id: "x",
ctx: Load,
},
),
),
},
),
TypeVar(
TypeParamTypeVar {
range: 136..139,
name: Identifier {
id: "int",
range: 136..139,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 143..146,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```
## Errors
|
1 | type X[*Ts = *int] = int
2 | type X[*Ts = *int or str] = int
| ^^^^^^^^^^ Syntax Error: Boolean expression cannot be used here
3 | type X[*Ts = yield x] = int
4 | type X[*Ts = yield from x] = int
|
|
1 | type X[*Ts = *int] = int
2 | type X[*Ts = *int or str] = int
3 | type X[*Ts = yield x] = int
| ^^^^^^^ Syntax Error: Yield expression cannot be used here
4 | type X[*Ts = yield from x] = int
5 | type X[*Ts = x := int] = int
|
|
2 | type X[*Ts = *int or str] = int
3 | type X[*Ts = yield x] = int
4 | type X[*Ts = yield from x] = int
| ^^^^^^^^^^^^ Syntax Error: Yield expression cannot be used here
5 | type X[*Ts = x := int] = int
|
|
3 | type X[*Ts = yield x] = int
4 | type X[*Ts = yield from x] = int
5 | type X[*Ts = x := int] = int
| ^^ Syntax Error: Expected ',', found ':='
|

View file

@ -0,0 +1,112 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_missing_default.py
---
## AST
```
Module(
ModModule {
range: 0..44,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..19,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..13,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 7..12,
name: Identifier {
id: "Ts",
range: 8..10,
},
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 16..19,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 20..43,
name: Name(
ExprName {
range: 25..26,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 26..37,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 27..32,
name: Identifier {
id: "Ts",
range: 28..30,
},
default: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 34..36,
name: Identifier {
id: "T2",
range: 34..36,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 40..43,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```
## Errors
|
1 | type X[*Ts =] = int
| ^ Syntax Error: Expected an expression
2 | type X[*Ts =, T2] = int
|
|
1 | type X[*Ts =] = int
2 | type X[*Ts =, T2] = int
| ^ Syntax Error: Expected an expression
|

View file

@ -7,7 +7,7 @@ input_file: crates/ruff_python_parser/resources/valid/statement/class.py
```
Module(
ModModule {
range: 0..681,
range: 0..1023,
body: [
ClassDef(
StmtClassDef {
@ -409,6 +409,7 @@ Module(
range: 342..343,
},
bound: None,
default: None,
},
),
],
@ -437,27 +438,28 @@ Module(
),
ClassDef(
StmtClassDef {
range: 374..399,
range: 376..402,
decorator_list: [],
name: Identifier {
id: "Test",
range: 380..384,
range: 382..386,
},
type_params: Some(
TypeParams {
range: 384..392,
range: 386..395,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 385..391,
range: 387..394,
name: Identifier {
id: "T",
range: 385..386,
range: 387..388,
},
bound: Some(
bound: None,
default: Some(
Name(
ExprName {
range: 388..391,
range: 391..394,
id: "str",
ctx: Load,
},
@ -470,7 +472,7 @@ Module(
),
arguments: Some(
Arguments {
range: 392..394,
range: 395..397,
args: [],
keywords: [],
},
@ -478,10 +480,10 @@ Module(
body: [
Expr(
StmtExpr {
range: 396..399,
range: 399..402,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 396..399,
range: 399..402,
},
),
},
@ -491,38 +493,169 @@ Module(
),
ClassDef(
StmtClassDef {
range: 428..462,
range: 425..450,
decorator_list: [],
name: Identifier {
id: "Test",
range: 434..438,
range: 431..435,
},
type_params: Some(
TypeParams {
range: 438..455,
range: 435..443,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 439..454,
range: 436..442,
name: Identifier {
id: "T",
range: 439..440,
range: 436..437,
},
bound: Some(
Name(
ExprName {
range: 439..442,
id: "str",
ctx: Load,
},
),
),
default: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 443..445,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 447..450,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 447..450,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 485..522,
decorator_list: [],
name: Identifier {
id: "Test",
range: 491..495,
},
type_params: Some(
TypeParams {
range: 495..515,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 496..514,
name: Identifier {
id: "T",
range: 496..497,
},
bound: Some(
BinOp(
ExprBinOp {
range: 499..508,
left: Name(
ExprName {
range: 499..502,
id: "int",
ctx: Load,
},
),
op: BitOr,
right: Name(
ExprName {
range: 505..508,
id: "str",
ctx: Load,
},
),
},
),
),
default: Some(
Name(
ExprName {
range: 511..514,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
arguments: Some(
Arguments {
range: 515..517,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 519..522,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 519..522,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 551..585,
decorator_list: [],
name: Identifier {
id: "Test",
range: 557..561,
},
type_params: Some(
TypeParams {
range: 561..578,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 562..577,
name: Identifier {
id: "T",
range: 562..563,
},
bound: Some(
Tuple(
ExprTuple {
range: 442..454,
range: 565..577,
elts: [
Name(
ExprName {
range: 443..446,
range: 566..569,
id: "str",
ctx: Load,
},
),
Name(
ExprName {
range: 448..453,
range: 571..576,
id: "bytes",
ctx: Load,
},
@ -533,6 +666,7 @@ Module(
},
),
),
default: None,
},
),
],
@ -540,7 +674,7 @@ Module(
),
arguments: Some(
Arguments {
range: 455..457,
range: 578..580,
args: [],
keywords: [],
},
@ -548,10 +682,10 @@ Module(
body: [
Expr(
StmtExpr {
range: 459..462,
range: 582..585,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 459..462,
range: 582..585,
},
),
},
@ -561,34 +695,36 @@ Module(
),
ClassDef(
StmtClassDef {
range: 483..506,
range: 606..629,
decorator_list: [],
name: Identifier {
id: "Test",
range: 489..493,
range: 612..616,
},
type_params: Some(
TypeParams {
range: 493..499,
range: 616..622,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 494..495,
range: 617..618,
name: Identifier {
id: "T",
range: 494..495,
range: 617..618,
},
bound: None,
default: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 497..498,
range: 620..621,
name: Identifier {
id: "U",
range: 497..498,
range: 620..621,
},
bound: None,
default: None,
},
),
],
@ -596,7 +732,7 @@ Module(
),
arguments: Some(
Arguments {
range: 499..501,
range: 622..624,
args: [],
keywords: [],
},
@ -604,10 +740,10 @@ Module(
body: [
Expr(
StmtExpr {
range: 503..506,
range: 626..629,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 503..506,
range: 626..629,
},
),
},
@ -617,34 +753,36 @@ Module(
),
ClassDef(
StmtClassDef {
range: 525..549,
range: 648..672,
decorator_list: [],
name: Identifier {
id: "Test",
range: 531..535,
range: 654..658,
},
type_params: Some(
TypeParams {
range: 535..542,
range: 658..665,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 536..537,
range: 659..660,
name: Identifier {
id: "T",
range: 536..537,
range: 659..660,
},
bound: None,
default: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 539..540,
range: 662..663,
name: Identifier {
id: "U",
range: 539..540,
range: 662..663,
},
bound: None,
default: None,
},
),
],
@ -652,7 +790,7 @@ Module(
),
arguments: Some(
Arguments {
range: 542..544,
range: 665..667,
args: [],
keywords: [],
},
@ -660,10 +798,10 @@ Module(
body: [
Expr(
StmtExpr {
range: 546..549,
range: 669..672,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 546..549,
range: 669..672,
},
),
},
@ -673,23 +811,24 @@ Module(
),
ClassDef(
StmtClassDef {
range: 566..588,
range: 689..711,
decorator_list: [],
name: Identifier {
id: "Test",
range: 572..576,
range: 695..699,
},
type_params: Some(
TypeParams {
range: 576..581,
range: 699..704,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 577..580,
range: 700..703,
name: Identifier {
id: "Ts",
range: 578..580,
range: 701..703,
},
default: None,
},
),
],
@ -697,7 +836,7 @@ Module(
),
arguments: Some(
Arguments {
range: 581..583,
range: 704..706,
args: [],
keywords: [],
},
@ -705,10 +844,10 @@ Module(
body: [
Expr(
StmtExpr {
range: 585..588,
range: 708..711,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 585..588,
range: 708..711,
},
),
},
@ -718,105 +857,163 @@ Module(
),
ClassDef(
StmtClassDef {
range: 602..624,
range: 741..789,
decorator_list: [],
name: Identifier {
id: "Test",
range: 608..612,
range: 747..751,
},
type_params: Some(
TypeParams {
range: 612..617,
range: 751..782,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 613..616,
TypeVarTuple(
TypeParamTypeVarTuple {
range: 752..781,
name: Identifier {
id: "P",
range: 615..616,
id: "Ts",
range: 753..755,
},
},
),
],
},
),
arguments: Some(
Arguments {
range: 617..619,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 621..624,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 621..624,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 640..680,
decorator_list: [],
name: Identifier {
id: "Test",
range: 646..650,
},
type_params: Some(
TypeParams {
range: 650..670,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 651..652,
name: Identifier {
id: "X",
range: 651..652,
},
bound: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 654..660,
name: Identifier {
id: "Y",
range: 654..655,
},
bound: Some(
Name(
ExprName {
range: 657..660,
id: "str",
default: Some(
Subscript(
ExprSubscript {
range: 758..781,
value: Name(
ExprName {
range: 758..764,
id: "Unpack",
ctx: Load,
},
),
slice: Subscript(
ExprSubscript {
range: 765..780,
value: Name(
ExprName {
range: 765..770,
id: "tuple",
ctx: Load,
},
),
slice: Tuple(
ExprTuple {
range: 771..779,
elts: [
Name(
ExprName {
range: 771..774,
id: "int",
ctx: Load,
},
),
Name(
ExprName {
range: 776..779,
id: "str",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
TypeVarTuple(
TypeParamTypeVarTuple {
range: 662..664,
name: Identifier {
id: "U",
range: 663..664,
},
],
},
),
arguments: Some(
Arguments {
range: 782..784,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 786..789,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 786..789,
},
),
ParamSpec(
TypeParamParamSpec {
range: 666..669,
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 827..868,
decorator_list: [],
name: Identifier {
id: "Test",
range: 833..837,
},
type_params: Some(
TypeParams {
range: 837..861,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 838..860,
name: Identifier {
id: "P",
range: 668..669,
id: "Ts",
range: 839..841,
},
default: Some(
Starred(
ExprStarred {
range: 844..860,
value: Subscript(
ExprSubscript {
range: 845..860,
value: Name(
ExprName {
range: 845..850,
id: "tuple",
ctx: Load,
},
),
slice: Tuple(
ExprTuple {
range: 851..859,
elts: [
Name(
ExprName {
range: 851..854,
id: "int",
ctx: Load,
},
),
Name(
ExprName {
range: 856..859,
id: "str",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
],
@ -824,7 +1021,208 @@ Module(
),
arguments: Some(
Arguments {
range: 670..672,
range: 861..863,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 865..868,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 865..868,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 882..904,
decorator_list: [],
name: Identifier {
id: "Test",
range: 888..892,
},
type_params: Some(
TypeParams {
range: 892..897,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 893..896,
name: Identifier {
id: "P",
range: 895..896,
},
default: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 897..899,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 901..904,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 901..904,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 931..966,
decorator_list: [],
name: Identifier {
id: "Test",
range: 937..941,
},
type_params: Some(
TypeParams {
range: 941..959,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 942..958,
name: Identifier {
id: "P",
range: 944..945,
},
default: Some(
List(
ExprList {
range: 948..958,
elts: [
Name(
ExprName {
range: 949..952,
id: "int",
ctx: Load,
},
),
Name(
ExprName {
range: 954..957,
id: "str",
ctx: Load,
},
),
],
ctx: Load,
},
),
),
},
),
],
},
),
arguments: Some(
Arguments {
range: 959..961,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 963..966,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 963..966,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 982..1022,
decorator_list: [],
name: Identifier {
id: "Test",
range: 988..992,
},
type_params: Some(
TypeParams {
range: 992..1012,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 993..994,
name: Identifier {
id: "X",
range: 993..994,
},
bound: None,
default: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 996..1002,
name: Identifier {
id: "Y",
range: 996..997,
},
bound: Some(
Name(
ExprName {
range: 999..1002,
id: "str",
ctx: Load,
},
),
),
default: None,
},
),
TypeVarTuple(
TypeParamTypeVarTuple {
range: 1004..1006,
name: Identifier {
id: "U",
range: 1005..1006,
},
default: None,
},
),
ParamSpec(
TypeParamParamSpec {
range: 1008..1011,
name: Identifier {
id: "P",
range: 1010..1011,
},
default: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 1012..1014,
args: [],
keywords: [],
},
@ -832,7 +1230,7 @@ Module(
body: [
Pass(
StmtPass {
range: 676..680,
range: 1018..1022,
},
),
],

View file

@ -2003,6 +2003,7 @@ Module(
range: 1712..1713,
},
bound: None,
default: None,
},
),
],
@ -2084,6 +2085,7 @@ Module(
},
),
),
default: None,
},
),
],
@ -2181,6 +2183,7 @@ Module(
},
),
),
default: None,
},
),
],
@ -2253,6 +2256,7 @@ Module(
id: "Ts",
range: 1837..1839,
},
default: None,
},
),
],
@ -2355,6 +2359,7 @@ Module(
id: "P",
range: 1887..1888,
},
default: None,
},
),
],
@ -2453,6 +2458,7 @@ Module(
range: 1946..1947,
},
bound: None,
default: None,
},
),
TypeVar(
@ -2471,6 +2477,7 @@ Module(
},
),
),
default: None,
},
),
TypeVarTuple(
@ -2480,6 +2487,7 @@ Module(
id: "Ts",
range: 1958..1960,
},
default: None,
},
),
ParamSpec(
@ -2489,6 +2497,7 @@ Module(
id: "P",
range: 1964..1965,
},
default: None,
},
),
],

View file

@ -0,0 +1,197 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/type_param_param_spec.py
---
## AST
```
Module(
ModModule {
range: 0..90,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..17,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..11,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 7..10,
name: Identifier {
id: "P",
range: 9..10,
},
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 14..17,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 18..41,
name: Name(
ExprName {
range: 23..24,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 24..35,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 25..34,
name: Identifier {
id: "P",
range: 27..28,
},
default: Some(
Name(
ExprName {
range: 31..34,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 38..41,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 42..62,
name: Name(
ExprName {
range: 47..48,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 48..56,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 49..50,
name: Identifier {
id: "T",
range: 49..50,
},
bound: None,
default: None,
},
),
ParamSpec(
TypeParamParamSpec {
range: 52..55,
name: Identifier {
id: "P",
range: 54..55,
},
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 59..62,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 63..89,
name: Name(
ExprName {
range: 68..69,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 69..83,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 70..71,
name: Identifier {
id: "T",
range: 70..71,
},
bound: None,
default: None,
},
),
ParamSpec(
TypeParamParamSpec {
range: 73..82,
name: Identifier {
id: "P",
range: 75..76,
},
default: Some(
Name(
ExprName {
range: 79..82,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 86..89,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```

View file

@ -0,0 +1,315 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/type_param_type_var.py
---
## AST
```
Module(
ModModule {
range: 0..147,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..15,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..9,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 7..8,
name: Identifier {
id: "T",
range: 7..8,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 12..15,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 16..37,
name: Name(
ExprName {
range: 21..22,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 22..31,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 23..30,
name: Identifier {
id: "T",
range: 23..24,
},
bound: None,
default: Some(
Name(
ExprName {
range: 27..30,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 34..37,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 38..64,
name: Name(
ExprName {
range: 43..44,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 44..58,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 45..57,
name: Identifier {
id: "T",
range: 45..46,
},
bound: Some(
Name(
ExprName {
range: 48..51,
id: "int",
ctx: Load,
},
),
),
default: Some(
Name(
ExprName {
range: 54..57,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 61..64,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 65..98,
name: Name(
ExprName {
range: 70..71,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 71..92,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 72..91,
name: Identifier {
id: "T",
range: 72..73,
},
bound: Some(
Tuple(
ExprTuple {
range: 75..85,
elts: [
Name(
ExprName {
range: 76..79,
id: "int",
ctx: Load,
},
),
Name(
ExprName {
range: 81..84,
id: "int",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
),
default: Some(
Name(
ExprName {
range: 88..91,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 95..98,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 99..146,
name: Name(
ExprName {
range: 104..105,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 105..140,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 106..118,
name: Identifier {
id: "T",
range: 106..107,
},
bound: Some(
Name(
ExprName {
range: 109..112,
id: "int",
ctx: Load,
},
),
),
default: Some(
Name(
ExprName {
range: 115..118,
id: "int",
ctx: Load,
},
),
),
},
),
TypeVar(
TypeParamTypeVar {
range: 120..139,
name: Identifier {
id: "U",
range: 120..121,
},
bound: Some(
Tuple(
ExprTuple {
range: 123..133,
elts: [
Name(
ExprName {
range: 124..127,
id: "int",
ctx: Load,
},
),
Name(
ExprName {
range: 129..132,
id: "int",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
),
default: Some(
Name(
ExprName {
range: 136..139,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 143..146,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```

View file

@ -0,0 +1,247 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/type_param_type_var_tuple.py
---
## AST
```
Module(
ModModule {
range: 0..115,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..17,
name: Name(
ExprName {
range: 5..6,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..11,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 7..10,
name: Identifier {
id: "Ts",
range: 8..10,
},
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 14..17,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 18..41,
name: Name(
ExprName {
range: 23..24,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 24..35,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 25..34,
name: Identifier {
id: "Ts",
range: 26..28,
},
default: Some(
Name(
ExprName {
range: 31..34,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 38..41,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 42..66,
name: Name(
ExprName {
range: 47..48,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 48..60,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 49..59,
name: Identifier {
id: "Ts",
range: 50..52,
},
default: Some(
Starred(
ExprStarred {
range: 55..59,
value: Name(
ExprName {
range: 56..59,
id: "int",
ctx: Load,
},
),
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 63..66,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 67..87,
name: Name(
ExprName {
range: 72..73,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 73..81,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 74..75,
name: Identifier {
id: "T",
range: 74..75,
},
bound: None,
default: None,
},
),
TypeVarTuple(
TypeParamTypeVarTuple {
range: 77..80,
name: Identifier {
id: "Ts",
range: 78..80,
},
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 84..87,
id: "int",
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 88..114,
name: Name(
ExprName {
range: 93..94,
id: "X",
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 94..108,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 95..96,
name: Identifier {
id: "T",
range: 95..96,
},
bound: None,
default: None,
},
),
TypeVarTuple(
TypeParamTypeVarTuple {
range: 98..107,
name: Identifier {
id: "Ts",
range: 99..101,
},
default: Some(
Name(
ExprName {
range: 104..107,
id: "int",
ctx: Load,
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 111..114,
id: "int",
ctx: Load,
},
),
},
),
],
},
)
```