diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py index 0daa3bdceb325..b2a7b7b4dd398 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py +++ b/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py @@ -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 @@ class Foo[T: DoesNotExist](list[T]): ... # F821: Undefined name `DoesNotExist` 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) diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index da9b595f40d38..044519daa6c3c 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -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())); + } + } } } diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap index 38834e5e199fd..bb12cf83ab9a8 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap @@ -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 + | diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep695_type_alias.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep695_type_alias.rs index 1966ce1b35055..0039194d21e63 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep695_type_alias.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep695_type_alias.rs @@ -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(), diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index 194e382097daa..66ab901c4885a 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -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>>, + pub default: Option>>, } #[derive(Debug, PartialEq, Eq, Hash)] pub struct TypeParamParamSpec<'a> { pub name: &'a str, + pub default: Option>>, } #[derive(Debug, PartialEq, Eq, Hash)] pub struct TypeParamTypeVarTuple<'a> { pub name: &'a str, + pub default: Option>>, } #[derive(Debug, PartialEq, Eq, Hash)] diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 91186e8f7a2ce..6c89f0287389d 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -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(¶m_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" ); } } diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index 5c4b4f28bfdf4..8142ad468773c 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -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 { diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index e4323ec952c72..8e1143f2adddf 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -3132,6 +3132,7 @@ pub struct TypeParamTypeVar { pub range: TextRange, pub name: Identifier, pub bound: Option>, + pub default: Option>, } impl From for TypeParam { @@ -3145,6 +3146,7 @@ impl From for TypeParam { pub struct TypeParamParamSpec { pub range: TextRange, pub name: Identifier, + pub default: Option>, } impl From for TypeParam { @@ -3158,6 +3160,7 @@ impl From for TypeParam { pub struct TypeParamTypeVarTuple { pub range: TextRange, pub name: Identifier, + pub default: Option>, } impl From for TypeParam { diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index 1233ff2d9e487..e243ff5d0ae6e 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -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(_) => {} } } diff --git a/crates/ruff_python_ast/src/visitor/transformer.rs b/crates/ruff_python_ast/src/visitor/transformer.rs index 9bb6d4b208a93..046630605fce6 100644 --- a/crates/ruff_python_ast/src/visitor/transformer.rs +++ b/crates/ruff_python_ast/src/visitor/transformer.rs @@ -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(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(_) => {} } } diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index 1577c8ec3e794..f937b0f8cc30c 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -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)"); diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py index 1630668e330b1..57034c14a25fb 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py @@ -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: ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py index ad13b9d84cd6e..ac856912069f9 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py @@ -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 @@ [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_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 diff --git a/crates/ruff_python_formatter/src/type_param/type_param_param_spec.rs b/crates/ruff_python_formatter/src/type_param/type_param_param_spec.rs index c64545ce846c7..6f9f5e5a72005 100644 --- a/crates/ruff_python_formatter/src/type_param/type_param_param_spec.rs +++ b/crates/ruff_python_formatter/src/type_param/type_param_param_spec.rs @@ -8,7 +8,15 @@ pub struct FormatTypeParamParamSpec; impl FormatNodeRule 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(()) } } diff --git a/crates/ruff_python_formatter/src/type_param/type_param_type_var.rs b/crates/ruff_python_formatter/src/type_param/type_param_type_var.rs index fbd3e7877538d..294498326714c 100644 --- a/crates/ruff_python_formatter/src/type_param/type_param_type_var.rs +++ b/crates/ruff_python_formatter/src/type_param/type_param_type_var.rs @@ -12,11 +12,15 @@ impl FormatNodeRule 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(()) } } diff --git a/crates/ruff_python_formatter/src/type_param/type_param_type_var_tuple.rs b/crates/ruff_python_formatter/src/type_param/type_param_type_var_tuple.rs index 4f7ae7ca9dcc8..30ab85e9001ff 100644 --- a/crates/ruff_python_formatter/src/type_param/type_param_type_var_tuple.rs +++ b/crates/ruff_python_formatter/src/type_param/type_param_type_var_tuple.rs @@ -8,7 +8,15 @@ pub struct FormatTypeParamTypeVarTuple; impl FormatNodeRule 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(()) } } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap index 32afd9a9d8f90..58d8cd64f3c22 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap @@ -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: ... ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap index 6320591b80c05..a62550da9c42e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap @@ -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 +``` diff --git a/crates/ruff_python_parser/resources/inline/err/type_param_param_spec_invalid_default_expr.py b/crates/ruff_python_parser/resources/inline/err/type_param_param_spec_invalid_default_expr.py new file mode 100644 index 0000000000000..f7f7c609c95f4 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/err/type_param_param_spec_invalid_default_expr.py @@ -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 diff --git a/crates/ruff_python_parser/resources/inline/err/type_param_param_spec_missing_default.py b/crates/ruff_python_parser/resources/inline/err/type_param_param_spec_missing_default.py new file mode 100644 index 0000000000000..4027abfda8857 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/err/type_param_param_spec_missing_default.py @@ -0,0 +1,2 @@ +type X[**P =] = int +type X[**P =, T2] = int diff --git a/crates/ruff_python_parser/resources/inline/err/type_param_type_var_invalid_default_expr.py b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_invalid_default_expr.py new file mode 100644 index 0000000000000..dd3f5b2bb5fe5 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_invalid_default_expr.py @@ -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 diff --git a/crates/ruff_python_parser/resources/inline/err/type_param_type_var_missing_default.py b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_missing_default.py new file mode 100644 index 0000000000000..653849f3192e5 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_missing_default.py @@ -0,0 +1,3 @@ +type X[T =] = int +type X[T: int =] = int +type X[T1 =, T2] = int diff --git a/crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_invalid_default_expr.py b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_invalid_default_expr.py new file mode 100644 index 0000000000000..b41f7d6dad379 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_invalid_default_expr.py @@ -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 diff --git a/crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_missing_default.py b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_missing_default.py new file mode 100644 index 0000000000000..429a5aa588b29 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/err/type_param_type_var_tuple_missing_default.py @@ -0,0 +1,2 @@ +type X[*Ts =] = int +type X[*Ts =, T2] = int diff --git a/crates/ruff_python_parser/resources/inline/ok/type_param_param_spec.py b/crates/ruff_python_parser/resources/inline/ok/type_param_param_spec.py new file mode 100644 index 0000000000000..bb69273701b3f --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/ok/type_param_param_spec.py @@ -0,0 +1,4 @@ +type X[**P] = int +type X[**P = int] = int +type X[T, **P] = int +type X[T, **P = int] = int diff --git a/crates/ruff_python_parser/resources/inline/ok/type_param_type_var.py b/crates/ruff_python_parser/resources/inline/ok/type_param_type_var.py new file mode 100644 index 0000000000000..83f7adb99b2b1 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/ok/type_param_type_var.py @@ -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 diff --git a/crates/ruff_python_parser/resources/inline/ok/type_param_type_var_tuple.py b/crates/ruff_python_parser/resources/inline/ok/type_param_type_var_tuple.py new file mode 100644 index 0000000000000..34ee60455a0c1 --- /dev/null +++ b/crates/ruff_python_parser/resources/inline/ok/type_param_type_var_tuple.py @@ -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 diff --git a/crates/ruff_python_parser/resources/valid/statement/class.py b/crates/ruff_python_parser/resources/valid/statement/class.py index 470805ff913c4..1d6b0f1b63e51 100644 --- a/crates/ruff_python_parser/resources/valid/statement/class.py +++ b/crates/ruff_python_parser/resources/valid/statement/class.py @@ -29,9 +29,15 @@ def method_with_default(self, arg='default'): # 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 diff --git a/crates/ruff_python_parser/resources/valid/statement/type.py b/crates/ruff_python_parser/resources/valid/statement/type.py index 0b74785ed0340..4136bfb3f12f2 100644 --- a/crates/ruff_python_parser/resources/valid/statement/type.py +++ b/crates/ruff_python_parser/resources/valid/statement/type.py @@ -7,6 +7,10 @@ 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 diff --git a/crates/ruff_python_parser/src/parser/statement.rs b/crates/ruff_python_parser/src/parser/statement.rs index b7816ea6e7724..cfe5e2e831565 100644 --- a/crates/ruff_python_parser/src/parser/statement.rs +++ b/crates/ruff_python_parser/src/parser/statement.rs @@ -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, }) } } diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@class_def_unclosed_type_param_list.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@class_def_unclosed_type_param_list.py.snap index 8d75eb452f2c7..0fa2471470db4 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@class_def_unclosed_type_param_list.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@class_def_unclosed_type_param_list.py.snap @@ -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, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@function_def_unclosed_type_param_list.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@function_def_unclosed_type_param_list.py.snap index 6f684498991f5..be462835e0b70 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@function_def_unclosed_type_param_list.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@function_def_unclosed_type_param_list.py.snap @@ -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, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__function_type_parameters.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__function_type_parameters.py.snap index 6256a009bb0cd..c2f674bcf30b7 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__function_type_parameters.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__function_type_parameters.py.snap @@ -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, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_invalid_bound_expr.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_invalid_bound_expr.py.snap index 26f5f4a590f28..6ce990e253a44 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_invalid_bound_expr.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_invalid_bound_expr.py.snap @@ -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, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_missing_bound.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_missing_bound.py.snap index 3a7c95c53872b..c4a22ec121b32 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_missing_bound.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_missing_bound.py.snap @@ -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, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_bound.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_bound.py.snap index da9817f84c53c..976cdf2c1c493 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_bound.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_bound.py.snap @@ -30,6 +30,7 @@ Module( id: "T", range: 9..10, }, + default: None, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_invalid_default_expr.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_invalid_default_expr.py.snap new file mode 100644 index 0000000000000..dbaa4ecf56734 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_invalid_default_expr.py.snap @@ -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 + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_missing_default.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_missing_default.py.snap new file mode 100644 index 0000000000000..26192a5aec7ee --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_param_spec_missing_default.py.snap @@ -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 + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_invalid_default_expr.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_invalid_default_expr.py.snap new file mode 100644 index 0000000000000..439efae18716c --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_invalid_default_expr.py.snap @@ -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 + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_missing_default.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_missing_default.py.snap new file mode 100644 index 0000000000000..7f4c56d9d7bb3 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_missing_default.py.snap @@ -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 + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_bound.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_bound.py.snap index 49e65c0cea789..a5a86ddffdcda 100644 --- a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_bound.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_bound.py.snap @@ -30,6 +30,7 @@ Module( id: "T", range: 8..9, }, + default: None, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_invalid_default_expr.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_invalid_default_expr.py.snap new file mode 100644 index 0000000000000..b17121dac3536 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_invalid_default_expr.py.snap @@ -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 ':=' + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_missing_default.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_missing_default.py.snap new file mode 100644 index 0000000000000..c1fa0dfd5a7d2 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@type_param_type_var_tuple_missing_default.py.snap @@ -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 + | diff --git a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__class.py.snap b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__class.py.snap index 98ebc2cf778c9..0da461c58410c 100644 --- a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__class.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__class.py.snap @@ -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,32 +438,164 @@ 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: None, + default: Some( + Name( + ExprName { + range: 391..394, + id: "str", + ctx: Load, + }, + ), + ), + }, + ), + ], + }, + ), + arguments: Some( + Arguments { + range: 395..397, + args: [], + keywords: [], + }, + ), + body: [ + Expr( + StmtExpr { + range: 399..402, + value: EllipsisLiteral( + ExprEllipsisLiteral { + range: 399..402, + }, + ), + }, + ), + ], + }, + ), + ClassDef( + StmtClassDef { + range: 425..450, + decorator_list: [], + name: Identifier { + id: "Test", + range: 431..435, + }, + type_params: Some( + TypeParams { + range: 435..443, + type_params: [ + TypeVar( + TypeParamTypeVar { + range: 436..442, + name: Identifier { + id: "T", + range: 436..437, }, bound: Some( Name( ExprName { - range: 388..391, + 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, + }, + ), + ), }, ), ], @@ -470,7 +603,7 @@ Module( ), arguments: Some( Arguments { - range: 392..394, + range: 515..517, args: [], keywords: [], }, @@ -478,10 +611,10 @@ Module( body: [ Expr( StmtExpr { - range: 396..399, + range: 519..522, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 396..399, + range: 519..522, }, ), }, @@ -491,38 +624,38 @@ Module( ), ClassDef( StmtClassDef { - range: 428..462, + range: 551..585, decorator_list: [], name: Identifier { id: "Test", - range: 434..438, + range: 557..561, }, type_params: Some( TypeParams { - range: 438..455, + range: 561..578, type_params: [ TypeVar( TypeParamTypeVar { - range: 439..454, + range: 562..577, name: Identifier { id: "T", - range: 439..440, + 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,23 +857,278 @@ 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: [ + TypeVarTuple( + TypeParamTypeVarTuple { + range: 752..781, + name: Identifier { + id: "Ts", + range: 753..755, + }, + 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, + }, + ), + ), + }, + ), + ], + }, + ), + arguments: Some( + Arguments { + range: 782..784, + args: [], + keywords: [], + }, + ), + body: [ + Expr( + StmtExpr { + range: 786..789, + value: EllipsisLiteral( + ExprEllipsisLiteral { + range: 786..789, + }, + ), + }, + ), + ], + }, + ), + 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: "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, + }, + ), + ), + }, + ), + ], + }, + ), + arguments: Some( + Arguments { + 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: 613..616, + range: 942..958, name: Identifier { id: "P", - range: 615..616, + 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, + }, + ), + ), }, ), ], @@ -742,7 +1136,7 @@ Module( ), arguments: Some( Arguments { - range: 617..619, + range: 959..961, args: [], keywords: [], }, @@ -750,10 +1144,10 @@ Module( body: [ Expr( StmtExpr { - range: 621..624, + range: 963..966, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 621..624, + range: 963..966, }, ), }, @@ -763,60 +1157,64 @@ Module( ), ClassDef( StmtClassDef { - range: 640..680, + range: 982..1022, decorator_list: [], name: Identifier { id: "Test", - range: 646..650, + range: 988..992, }, type_params: Some( TypeParams { - range: 650..670, + range: 992..1012, type_params: [ TypeVar( TypeParamTypeVar { - range: 651..652, + range: 993..994, name: Identifier { id: "X", - range: 651..652, + range: 993..994, }, bound: None, + default: None, }, ), TypeVar( TypeParamTypeVar { - range: 654..660, + range: 996..1002, name: Identifier { id: "Y", - range: 654..655, + range: 996..997, }, bound: Some( Name( ExprName { - range: 657..660, + range: 999..1002, id: "str", ctx: Load, }, ), ), + default: None, }, ), TypeVarTuple( TypeParamTypeVarTuple { - range: 662..664, + range: 1004..1006, name: Identifier { id: "U", - range: 663..664, + range: 1005..1006, }, + default: None, }, ), ParamSpec( TypeParamParamSpec { - range: 666..669, + range: 1008..1011, name: Identifier { id: "P", - range: 668..669, + range: 1010..1011, }, + default: None, }, ), ], @@ -824,7 +1222,7 @@ Module( ), arguments: Some( Arguments { - range: 670..672, + range: 1012..1014, args: [], keywords: [], }, @@ -832,7 +1230,7 @@ Module( body: [ Pass( StmtPass { - range: 676..680, + range: 1018..1022, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__function.py.snap b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__function.py.snap index 3e436931fa021..3f741ebf3321d 100644 --- a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__function.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__function.py.snap @@ -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, }, ), ], diff --git a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__type.py.snap b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__type.py.snap index 1b5e45c4662db..ba6f64dc5c900 100644 --- a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__type.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__type.py.snap @@ -7,7 +7,7 @@ input_file: crates/ruff_python_parser/resources/valid/statement/type.py ``` Module( ModModule { - range: 0..1661, + range: 0..1828, body: [ TypeAlias( StmtTypeAlias { @@ -128,6 +128,7 @@ Module( range: 68..69, }, bound: None, + default: None, }, ), ], @@ -203,6 +204,7 @@ Module( range: 108..109, }, bound: None, + default: None, }, ), ], @@ -239,6 +241,7 @@ Module( range: 124..125, }, bound: None, + default: None, }, ), ], @@ -314,6 +317,7 @@ Module( range: 153..154, }, bound: None, + default: None, }, ), TypeVarTuple( @@ -323,6 +327,7 @@ Module( id: "Ts", range: 157..159, }, + default: None, }, ), ParamSpec( @@ -332,6 +337,7 @@ Module( id: "P", range: 163..164, }, + default: None, }, ), ], @@ -399,6 +405,7 @@ Module( }, ), ), + default: None, }, ), TypeVarTuple( @@ -408,6 +415,7 @@ Module( id: "Ts", range: 195..197, }, + default: None, }, ), ParamSpec( @@ -417,6 +425,7 @@ Module( id: "P", range: 201..202, }, + default: None, }, ), ], @@ -500,6 +509,7 @@ Module( }, ), ), + default: None, }, ), TypeVarTuple( @@ -509,6 +519,7 @@ Module( id: "Ts", range: 240..242, }, + default: None, }, ), ParamSpec( @@ -518,6 +529,7 @@ Module( id: "P", range: 246..247, }, + default: None, }, ), ], @@ -557,10 +569,369 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 292..307, + range: 262..287, name: Name( ExprName { - range: 297..301, + range: 267..268, + id: "X", + ctx: Store, + }, + ), + type_params: Some( + TypeParams { + range: 268..277, + type_params: [ + TypeVar( + TypeParamTypeVar { + range: 269..276, + name: Identifier { + id: "T", + range: 269..270, + }, + bound: None, + default: Some( + Name( + ExprName { + range: 273..276, + id: "int", + ctx: Load, + }, + ), + ), + }, + ), + ], + }, + ), + value: BinOp( + ExprBinOp { + range: 280..287, + left: Name( + ExprName { + range: 280..281, + id: "T", + ctx: Load, + }, + ), + op: BitOr, + right: Name( + ExprName { + range: 284..287, + id: "str", + ctx: Load, + }, + ), + }, + ), + }, + ), + TypeAlias( + StmtTypeAlias { + range: 288..330, + name: Name( + ExprName { + range: 293..294, + id: "X", + ctx: Store, + }, + ), + type_params: Some( + TypeParams { + range: 294..314, + type_params: [ + TypeVar( + TypeParamTypeVar { + range: 295..313, + name: Identifier { + id: "T", + range: 295..296, + }, + bound: Some( + BinOp( + ExprBinOp { + range: 298..307, + left: Name( + ExprName { + range: 298..301, + id: "int", + ctx: Load, + }, + ), + op: BitOr, + right: Name( + ExprName { + range: 304..307, + id: "str", + ctx: Load, + }, + ), + }, + ), + ), + default: Some( + Name( + ExprName { + range: 310..313, + id: "int", + ctx: Load, + }, + ), + ), + }, + ), + ], + }, + ), + value: BinOp( + ExprBinOp { + range: 317..330, + left: BinOp( + ExprBinOp { + range: 317..324, + left: Name( + ExprName { + range: 317..318, + id: "T", + ctx: Load, + }, + ), + op: BitOr, + right: Name( + ExprName { + range: 321..324, + id: "int", + ctx: Load, + }, + ), + }, + ), + op: BitOr, + right: Name( + ExprName { + range: 327..330, + id: "str", + ctx: Load, + }, + ), + }, + ), + }, + ), + TypeAlias( + StmtTypeAlias { + range: 331..384, + name: Name( + ExprName { + range: 336..337, + id: "X", + ctx: Store, + }, + ), + type_params: Some( + TypeParams { + range: 337..361, + type_params: [ + TypeVarTuple( + TypeParamTypeVarTuple { + range: 338..360, + name: Identifier { + id: "Ts", + range: 339..341, + }, + default: Some( + Starred( + ExprStarred { + range: 344..360, + value: Subscript( + ExprSubscript { + range: 345..360, + value: Name( + ExprName { + range: 345..350, + id: "tuple", + ctx: Load, + }, + ), + slice: Tuple( + ExprTuple { + range: 351..359, + elts: [ + Name( + ExprName { + range: 351..354, + id: "int", + ctx: Load, + }, + ), + Name( + ExprName { + range: 356..359, + id: "str", + ctx: Load, + }, + ), + ], + ctx: Load, + parenthesized: false, + }, + ), + ctx: Load, + }, + ), + ctx: Load, + }, + ), + ), + }, + ), + ], + }, + ), + value: Subscript( + ExprSubscript { + range: 364..384, + value: Name( + ExprName { + range: 364..369, + id: "tuple", + ctx: Load, + }, + ), + slice: Tuple( + ExprTuple { + range: 370..383, + elts: [ + Name( + ExprName { + range: 370..373, + id: "int", + ctx: Load, + }, + ), + Starred( + ExprStarred { + range: 375..378, + value: Name( + ExprName { + range: 376..378, + id: "Ts", + ctx: Load, + }, + ), + ctx: Load, + }, + ), + Name( + ExprName { + range: 380..383, + id: "str", + ctx: Load, + }, + ), + ], + ctx: Load, + parenthesized: false, + }, + ), + ctx: Load, + }, + ), + }, + ), + TypeAlias( + StmtTypeAlias { + range: 385..428, + name: Name( + ExprName { + range: 390..391, + id: "X", + ctx: Store, + }, + ), + type_params: Some( + TypeParams { + range: 391..409, + type_params: [ + ParamSpec( + TypeParamParamSpec { + range: 392..408, + name: Identifier { + id: "P", + range: 394..395, + }, + default: Some( + List( + ExprList { + range: 398..408, + elts: [ + Name( + ExprName { + range: 399..402, + id: "int", + ctx: Load, + }, + ), + Name( + ExprName { + range: 404..407, + id: "str", + ctx: Load, + }, + ), + ], + ctx: Load, + }, + ), + ), + }, + ), + ], + }, + ), + value: Subscript( + ExprSubscript { + range: 412..428, + value: Name( + ExprName { + range: 412..420, + id: "Callable", + ctx: Load, + }, + ), + slice: Tuple( + ExprTuple { + range: 421..427, + elts: [ + Name( + ExprName { + range: 421..422, + id: "P", + ctx: Load, + }, + ), + Name( + ExprName { + range: 424..427, + id: "str", + ctx: Load, + }, + ), + ], + ctx: Load, + parenthesized: false, + }, + ), + ctx: Load, + }, + ), + }, + ), + TypeAlias( + StmtTypeAlias { + range: 459..474, + name: Name( + ExprName { + range: 464..468, id: "type", ctx: Store, }, @@ -568,7 +939,7 @@ Module( type_params: None, value: Name( ExprName { - range: 304..307, + range: 471..474, id: "int", ctx: Load, }, @@ -577,10 +948,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 308..324, + range: 475..491, name: Name( ExprName { - range: 313..318, + range: 480..485, id: "match", ctx: Store, }, @@ -588,7 +959,7 @@ Module( type_params: None, value: Name( ExprName { - range: 321..324, + range: 488..491, id: "int", ctx: Load, }, @@ -597,10 +968,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 325..340, + range: 492..507, name: Name( ExprName { - range: 330..334, + range: 497..501, id: "case", ctx: Store, }, @@ -608,7 +979,7 @@ Module( type_params: None, value: Name( ExprName { - range: 337..340, + range: 504..507, id: "int", ctx: Load, }, @@ -617,10 +988,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 366..381, + range: 533..548, name: Name( ExprName { - range: 371..374, + range: 538..541, id: "foo", ctx: Store, }, @@ -628,7 +999,7 @@ Module( type_params: None, value: Name( ExprName { - range: 377..381, + range: 544..548, id: "type", ctx: Load, }, @@ -637,10 +1008,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 382..398, + range: 549..565, name: Name( ExprName { - range: 387..390, + range: 554..557, id: "foo", ctx: Store, }, @@ -648,7 +1019,7 @@ Module( type_params: None, value: Name( ExprName { - range: 393..398, + range: 560..565, id: "match", ctx: Load, }, @@ -657,10 +1028,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 399..414, + range: 566..581, name: Name( ExprName { - range: 404..407, + range: 571..574, id: "foo", ctx: Store, }, @@ -668,7 +1039,7 @@ Module( type_params: None, value: Name( ExprName { - range: 410..414, + range: 577..581, id: "case", ctx: Load, }, @@ -677,10 +1048,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 438..453, + range: 605..620, name: Name( ExprName { - range: 446..447, + range: 613..614, id: "X", ctx: Store, }, @@ -688,7 +1059,7 @@ Module( type_params: None, value: Name( ExprName { - range: 450..453, + range: 617..620, id: "int", ctx: Load, }, @@ -697,10 +1068,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 454..469, + range: 621..636, name: Name( ExprName { - range: 459..460, + range: 626..627, id: "X", ctx: Store, }, @@ -708,7 +1079,7 @@ Module( type_params: None, value: Name( ExprName { - range: 466..469, + range: 633..636, id: "int", ctx: Load, }, @@ -717,10 +1088,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 470..485, + range: 637..652, name: Name( ExprName { - range: 475..476, + range: 642..643, id: "X", ctx: Store, }, @@ -728,7 +1099,7 @@ Module( type_params: None, value: Name( ExprName { - range: 482..485, + range: 649..652, id: "int", ctx: Load, }, @@ -737,10 +1108,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 486..506, + range: 653..673, name: Name( ExprName { - range: 491..492, + range: 658..659, id: "X", ctx: Store, }, @@ -748,7 +1119,7 @@ Module( type_params: None, value: Name( ExprName { - range: 501..504, + range: 668..671, id: "int", ctx: Load, }, @@ -757,26 +1128,27 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 507..526, + range: 674..693, name: Name( ExprName { - range: 518..519, + range: 685..686, id: "X", ctx: Store, }, ), type_params: Some( TypeParams { - range: 519..522, + range: 686..689, type_params: [ TypeVar( TypeParamTypeVar { - range: 520..521, + range: 687..688, name: Identifier { id: "T", - range: 520..521, + range: 687..688, }, bound: None, + default: None, }, ), ], @@ -784,7 +1156,7 @@ Module( ), value: Name( ExprName { - range: 525..526, + range: 692..693, id: "T", ctx: Load, }, @@ -793,26 +1165,27 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 527..547, + range: 694..714, name: Name( ExprName { - range: 532..533, + range: 699..700, id: "X", ctx: Store, }, ), type_params: Some( TypeParams { - range: 540..543, + range: 707..710, type_params: [ TypeVar( TypeParamTypeVar { - range: 541..542, + range: 708..709, name: Identifier { id: "T", - range: 541..542, + range: 708..709, }, bound: None, + default: None, }, ), ], @@ -820,7 +1193,7 @@ Module( ), value: Name( ExprName { - range: 546..547, + range: 713..714, id: "T", ctx: Load, }, @@ -829,26 +1202,27 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 548..567, + range: 715..734, name: Name( ExprName { - range: 553..554, + range: 720..721, id: "X", ctx: Store, }, ), type_params: Some( TypeParams { - range: 554..557, + range: 721..724, type_params: [ TypeVar( TypeParamTypeVar { - range: 555..556, + range: 722..723, name: Identifier { id: "T", - range: 555..556, + range: 722..723, }, bound: None, + default: None, }, ), ], @@ -856,7 +1230,7 @@ Module( ), value: Name( ExprName { - range: 566..567, + range: 733..734, id: "T", ctx: Load, }, @@ -865,10 +1239,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 589..601, + range: 756..768, name: Name( ExprName { - range: 594..595, + range: 761..762, id: "X", ctx: Store, }, @@ -876,7 +1250,7 @@ Module( type_params: None, value: Name( ExprName { - range: 598..601, + range: 765..768, id: "int", ctx: Load, }, @@ -885,10 +1259,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 603..615, + range: 770..782, name: Name( ExprName { - range: 608..609, + range: 775..776, id: "X", ctx: Store, }, @@ -896,7 +1270,7 @@ Module( type_params: None, value: Name( ExprName { - range: 612..615, + range: 779..782, id: "str", ctx: Load, }, @@ -905,10 +1279,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 617..630, + range: 784..797, name: Name( ExprName { - range: 622..623, + range: 789..790, id: "X", ctx: Store, }, @@ -916,7 +1290,7 @@ Module( type_params: None, value: Name( ExprName { - range: 626..630, + range: 793..797, id: "type", ctx: Load, }, @@ -925,21 +1299,21 @@ Module( ), ClassDef( StmtClassDef { - range: 631..652, + range: 798..819, decorator_list: [], name: Identifier { id: "X", - range: 637..638, + range: 804..805, }, type_params: None, arguments: None, body: [ TypeAlias( StmtTypeAlias { - range: 640..652, + range: 807..819, name: Name( ExprName { - range: 645..646, + range: 812..813, id: "X", ctx: Store, }, @@ -947,7 +1321,7 @@ Module( type_params: None, value: Name( ExprName { - range: 649..652, + range: 816..819, id: "int", ctx: Load, }, @@ -959,10 +1333,10 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 654..686, + range: 821..853, name: Name( ExprName { - range: 659..664, + range: 826..831, id: "Point", ctx: Store, }, @@ -970,28 +1344,28 @@ Module( type_params: None, value: Subscript( ExprSubscript { - range: 667..686, + range: 834..853, value: Name( ExprName { - range: 667..672, + range: 834..839, id: "tuple", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 673..685, + range: 840..852, elts: [ Name( ExprName { - range: 673..678, + range: 840..845, id: "float", ctx: Load, }, ), Name( ExprName { - range: 680..685, + range: 847..852, id: "float", ctx: Load, }, @@ -1008,26 +1382,27 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 687..714, + range: 854..881, name: Name( ExprName { - range: 692..697, + range: 859..864, id: "Point", ctx: Store, }, ), type_params: Some( TypeParams { - range: 697..700, + range: 864..867, type_params: [ TypeVar( TypeParamTypeVar { - range: 698..699, + range: 865..866, name: Identifier { id: "T", - range: 698..699, + range: 865..866, }, bound: None, + default: None, }, ), ], @@ -1035,28 +1410,28 @@ Module( ), value: Subscript( ExprSubscript { - range: 703..714, + range: 870..881, value: Name( ExprName { - range: 703..708, + range: 870..875, id: "tuple", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 709..713, + range: 876..880, elts: [ Name( ExprName { - range: 709..710, + range: 876..877, id: "T", ctx: Load, }, ), Name( ExprName { - range: 712..713, + range: 879..880, id: "T", ctx: Load, }, @@ -1073,25 +1448,26 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 715..751, + range: 882..918, name: Name( ExprName { - range: 720..727, + range: 887..894, id: "IntFunc", ctx: Store, }, ), type_params: Some( TypeParams { - range: 727..732, + range: 894..899, type_params: [ ParamSpec( TypeParamParamSpec { - range: 728..731, + range: 895..898, name: Identifier { id: "P", - range: 730..731, + range: 897..898, }, + default: None, }, ), ], @@ -1099,28 +1475,28 @@ Module( ), value: Subscript( ExprSubscript { - range: 735..751, + range: 902..918, value: Name( ExprName { - range: 735..743, + range: 902..910, id: "Callable", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 744..750, + range: 911..917, elts: [ Name( ExprName { - range: 744..745, + range: 911..912, id: "P", ctx: Load, }, ), Name( ExprName { - range: 747..750, + range: 914..917, id: "int", ctx: Load, }, @@ -1137,25 +1513,26 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 765..805, + range: 932..972, name: Name( ExprName { - range: 770..782, + range: 937..949, id: "LabeledTuple", ctx: Store, }, ), type_params: Some( TypeParams { - range: 782..787, + range: 949..954, type_params: [ TypeVarTuple( TypeParamTypeVarTuple { - range: 783..786, + range: 950..953, name: Identifier { id: "Ts", - range: 784..786, + range: 951..953, }, + default: None, }, ), ], @@ -1163,31 +1540,31 @@ Module( ), value: Subscript( ExprSubscript { - range: 790..805, + range: 957..972, value: Name( ExprName { - range: 790..795, + range: 957..962, id: "tuple", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 796..804, + range: 963..971, elts: [ Name( ExprName { - range: 796..799, + range: 963..966, id: "str", ctx: Load, }, ), Starred( ExprStarred { - range: 801..804, + range: 968..971, value: Name( ExprName { - range: 802..804, + range: 969..971, id: "Ts", ctx: Load, }, @@ -1207,34 +1584,35 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 822..870, + range: 989..1037, name: Name( ExprName { - range: 827..843, + range: 994..1010, id: "HashableSequence", ctx: Store, }, ), type_params: Some( TypeParams { - range: 843..856, + range: 1010..1023, type_params: [ TypeVar( TypeParamTypeVar { - range: 844..855, + range: 1011..1022, name: Identifier { id: "T", - range: 844..845, + range: 1011..1012, }, bound: Some( Name( ExprName { - range: 847..855, + range: 1014..1022, id: "Hashable", ctx: Load, }, ), ), + default: None, }, ), ], @@ -1242,17 +1620,17 @@ Module( ), value: Subscript( ExprSubscript { - range: 859..870, + range: 1026..1037, value: Name( ExprName { - range: 859..867, + range: 1026..1034, id: "Sequence", ctx: Load, }, ), slice: Name( ExprName { - range: 868..869, + range: 1035..1036, id: "T", ctx: Load, }, @@ -1264,40 +1642,40 @@ Module( ), TypeAlias( StmtTypeAlias { - range: 893..943, + range: 1060..1110, name: Name( ExprName { - range: 898..914, + range: 1065..1081, id: "IntOrStrSequence", ctx: Store, }, ), type_params: Some( TypeParams { - range: 914..929, + range: 1081..1096, type_params: [ TypeVar( TypeParamTypeVar { - range: 915..928, + range: 1082..1095, name: Identifier { id: "T", - range: 915..916, + range: 1082..1083, }, bound: Some( Tuple( ExprTuple { - range: 918..928, + range: 1085..1095, elts: [ Name( ExprName { - range: 919..922, + range: 1086..1089, id: "int", ctx: Load, }, ), Name( ExprName { - range: 924..927, + range: 1091..1094, id: "str", ctx: Load, }, @@ -1308,6 +1686,7 @@ Module( }, ), ), + default: None, }, ), ], @@ -1315,17 +1694,17 @@ Module( ), value: Subscript( ExprSubscript { - range: 932..943, + range: 1099..1110, value: Name( ExprName { - range: 932..940, + range: 1099..1107, id: "Sequence", ctx: Load, }, ), slice: Name( ExprName { - range: 941..942, + range: 1108..1109, id: "T", ctx: Load, }, @@ -1337,20 +1716,20 @@ Module( ), Expr( StmtExpr { - range: 997..1011, + range: 1164..1178, value: Tuple( ExprTuple { - range: 997..1011, + range: 1164..1178, elts: [ BinOp( ExprBinOp { - range: 997..1008, + range: 1164..1175, left: BinOp( ExprBinOp { - range: 997..1004, + range: 1164..1171, left: Name( ExprName { - range: 997..1001, + range: 1164..1168, id: "type", ctx: Load, }, @@ -1358,7 +1737,7 @@ Module( op: Mult, right: Name( ExprName { - range: 1003..1004, + range: 1170..1171, id: "a", ctx: Load, }, @@ -1368,7 +1747,7 @@ Module( op: Add, right: Name( ExprName { - range: 1007..1008, + range: 1174..1175, id: "b", ctx: Load, }, @@ -1377,7 +1756,7 @@ Module( ), Name( ExprName { - range: 1010..1011, + range: 1177..1178, id: "c", ctx: Load, }, @@ -1391,17 +1770,17 @@ Module( ), Expr( StmtExpr { - range: 1036..1052, + range: 1203..1219, value: Tuple( ExprTuple { - range: 1036..1052, + range: 1203..1219, elts: [ BinOp( ExprBinOp { - range: 1036..1049, + range: 1203..1216, left: Name( ExprName { - range: 1036..1040, + range: 1203..1207, id: "type", ctx: Load, }, @@ -1409,10 +1788,10 @@ Module( op: Mult, right: BinOp( ExprBinOp { - range: 1043..1048, + range: 1210..1215, left: Name( ExprName { - range: 1043..1044, + range: 1210..1211, id: "a", ctx: Load, }, @@ -1420,7 +1799,7 @@ Module( op: Add, right: Name( ExprName { - range: 1047..1048, + range: 1214..1215, id: "b", ctx: Load, }, @@ -1431,7 +1810,7 @@ Module( ), Name( ExprName { - range: 1051..1052, + range: 1218..1219, id: "c", ctx: Load, }, @@ -1445,29 +1824,29 @@ Module( ), Expr( StmtExpr { - range: 1077..1093, + range: 1244..1260, value: Call( ExprCall { - range: 1077..1093, + range: 1244..1260, func: Name( ExprName { - range: 1077..1081, + range: 1244..1248, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1082..1093, + range: 1249..1260, args: [ Starred( ExprStarred { - range: 1083..1089, + range: 1250..1256, value: BinOp( ExprBinOp { - range: 1084..1089, + range: 1251..1256, left: Name( ExprName { - range: 1084..1085, + range: 1251..1252, id: "a", ctx: Load, }, @@ -1475,7 +1854,7 @@ Module( op: Add, right: Name( ExprName { - range: 1088..1089, + range: 1255..1256, id: "b", ctx: Load, }, @@ -1487,7 +1866,7 @@ Module( ), Name( ExprName { - range: 1091..1092, + range: 1258..1259, id: "c", ctx: Load, }, @@ -1501,16 +1880,16 @@ Module( ), Expr( StmtExpr { - range: 1119..1134, + range: 1286..1301, value: BinOp( ExprBinOp { - range: 1119..1134, + range: 1286..1301, left: BinOp( ExprBinOp { - range: 1119..1130, + range: 1286..1297, left: Name( ExprName { - range: 1119..1123, + range: 1286..1290, id: "type", ctx: Load, }, @@ -1518,10 +1897,10 @@ Module( op: Sub, right: BinOp( ExprBinOp { - range: 1125..1130, + range: 1292..1297, left: Name( ExprName { - range: 1125..1126, + range: 1292..1293, id: "a", ctx: Load, }, @@ -1529,7 +1908,7 @@ Module( op: Mult, right: Name( ExprName { - range: 1129..1130, + range: 1296..1297, id: "b", ctx: Load, }, @@ -1541,7 +1920,7 @@ Module( op: Add, right: Name( ExprName { - range: 1133..1134, + range: 1300..1301, id: "c", ctx: Load, }, @@ -1552,16 +1931,16 @@ Module( ), Expr( StmtExpr { - range: 1160..1177, + range: 1327..1344, value: BinOp( ExprBinOp { - range: 1160..1177, + range: 1327..1344, left: BinOp( ExprBinOp { - range: 1160..1173, + range: 1327..1340, left: Name( ExprName { - range: 1160..1164, + range: 1327..1331, id: "type", ctx: Load, }, @@ -1569,10 +1948,10 @@ Module( op: Sub, right: BinOp( ExprBinOp { - range: 1167..1172, + range: 1334..1339, left: Name( ExprName { - range: 1167..1168, + range: 1334..1335, id: "a", ctx: Load, }, @@ -1580,7 +1959,7 @@ Module( op: Mult, right: Name( ExprName { - range: 1171..1172, + range: 1338..1339, id: "b", ctx: Load, }, @@ -1592,7 +1971,7 @@ Module( op: Add, right: Name( ExprName { - range: 1176..1177, + range: 1343..1344, id: "c", ctx: Load, }, @@ -1603,33 +1982,33 @@ Module( ), Expr( StmtExpr { - range: 1203..1220, + range: 1370..1387, value: BinOp( ExprBinOp { - range: 1203..1220, + range: 1370..1387, left: BinOp( ExprBinOp { - range: 1203..1216, + range: 1370..1383, left: Call( ExprCall { - range: 1203..1212, + range: 1370..1379, func: Name( ExprName { - range: 1203..1207, + range: 1370..1374, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1208..1212, + range: 1375..1379, args: [ UnaryOp( ExprUnaryOp { - range: 1209..1211, + range: 1376..1378, op: USub, operand: Name( ExprName { - range: 1210..1211, + range: 1377..1378, id: "a", ctx: Load, }, @@ -1644,7 +2023,7 @@ Module( op: Mult, right: Name( ExprName { - range: 1215..1216, + range: 1382..1383, id: "b", ctx: Load, }, @@ -1654,7 +2033,7 @@ Module( op: Add, right: Name( ExprName { - range: 1219..1220, + range: 1386..1387, id: "c", ctx: Load, }, @@ -1665,22 +2044,22 @@ Module( ), Expr( StmtExpr { - range: 1247..1256, + range: 1414..1423, value: Attribute( ExprAttribute { - range: 1247..1256, + range: 1414..1423, value: Call( ExprCall { - range: 1247..1254, + range: 1414..1421, func: Name( ExprName { - range: 1247..1251, + range: 1414..1418, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1252..1254, + range: 1419..1421, args: [], keywords: [], }, @@ -1688,7 +2067,7 @@ Module( ), attr: Identifier { id: "a", - range: 1255..1256, + range: 1422..1423, }, ctx: Load, }, @@ -1697,26 +2076,26 @@ Module( ), Expr( StmtExpr { - range: 1272..1283, + range: 1439..1450, value: Attribute( ExprAttribute { - range: 1272..1283, + range: 1439..1450, value: Call( ExprCall { - range: 1272..1281, + range: 1439..1448, func: Name( ExprName { - range: 1272..1276, + range: 1439..1443, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1277..1281, + range: 1444..1448, args: [ Tuple( ExprTuple { - range: 1278..1280, + range: 1445..1447, elts: [], ctx: Load, parenthesized: true, @@ -1729,7 +2108,7 @@ Module( ), attr: Identifier { id: "a", - range: 1282..1283, + range: 1449..1450, }, ctx: Load, }, @@ -1738,26 +2117,26 @@ Module( ), Expr( StmtExpr { - range: 1301..1313, + range: 1468..1480, value: Attribute( ExprAttribute { - range: 1301..1313, + range: 1468..1480, value: Call( ExprCall { - range: 1301..1311, + range: 1468..1478, func: Name( ExprName { - range: 1301..1305, + range: 1468..1472, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1306..1311, + range: 1473..1478, args: [ Tuple( ExprTuple { - range: 1307..1309, + range: 1474..1476, elts: [], ctx: Load, parenthesized: true, @@ -1770,7 +2149,7 @@ Module( ), attr: Identifier { id: "a", - range: 1312..1313, + range: 1479..1480, }, ctx: Load, }, @@ -1779,23 +2158,23 @@ Module( ), Expr( StmtExpr { - range: 1331..1341, + range: 1498..1508, value: Attribute( ExprAttribute { - range: 1331..1341, + range: 1498..1508, value: Subscript( ExprSubscript { - range: 1331..1339, + range: 1498..1506, value: Name( ExprName { - range: 1331..1335, + range: 1498..1502, id: "type", ctx: Load, }, ), slice: Name( ExprName { - range: 1337..1338, + range: 1504..1505, id: "a", ctx: Load, }, @@ -1805,7 +2184,7 @@ Module( ), attr: Identifier { id: "b", - range: 1340..1341, + range: 1507..1508, }, ctx: Load, }, @@ -1814,27 +2193,27 @@ Module( ), Expr( StmtExpr { - range: 1358..1369, + range: 1525..1536, value: Attribute( ExprAttribute { - range: 1358..1369, + range: 1525..1536, value: Subscript( ExprSubscript { - range: 1358..1367, + range: 1525..1534, value: Name( ExprName { - range: 1358..1362, + range: 1525..1529, id: "type", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 1364..1366, + range: 1531..1533, elts: [ Name( ExprName { - range: 1364..1365, + range: 1531..1532, id: "a", ctx: Load, }, @@ -1849,7 +2228,7 @@ Module( ), attr: Identifier { id: "b", - range: 1368..1369, + range: 1535..1536, }, ctx: Load, }, @@ -1858,27 +2237,27 @@ Module( ), Expr( StmtExpr { - range: 1408..1421, + range: 1575..1588, value: Attribute( ExprAttribute { - range: 1408..1421, + range: 1575..1588, value: Subscript( ExprSubscript { - range: 1408..1419, + range: 1575..1586, value: Name( ExprName { - range: 1408..1412, + range: 1575..1579, id: "type", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 1414..1418, + range: 1581..1585, elts: [ Name( ExprName { - range: 1415..1416, + range: 1582..1583, id: "a", ctx: Load, }, @@ -1893,7 +2272,7 @@ Module( ), attr: Identifier { id: "b", - range: 1420..1421, + range: 1587..1588, }, ctx: Load, }, @@ -1902,22 +2281,22 @@ Module( ), Expr( StmtExpr { - range: 1441..1457, + range: 1608..1624, value: Subscript( ExprSubscript { - range: 1441..1457, + range: 1608..1624, value: Call( ExprCall { - range: 1441..1447, + range: 1608..1614, func: Name( ExprName { - range: 1441..1445, + range: 1608..1612, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1445..1447, + range: 1612..1614, args: [], keywords: [], }, @@ -1925,11 +2304,11 @@ Module( ), slice: Slice( ExprSlice { - range: 1448..1456, + range: 1615..1623, lower: Some( Name( ExprName { - range: 1448..1449, + range: 1615..1616, id: "a", ctx: Load, }, @@ -1938,7 +2317,7 @@ Module( upper: Some( Name( ExprName { - range: 1455..1456, + range: 1622..1623, id: "b", ctx: Load, }, @@ -1954,20 +2333,20 @@ Module( ), If( StmtIf { - range: 1476..1494, + range: 1643..1661, test: Named( ExprNamed { - range: 1479..1488, + range: 1646..1655, target: Name( ExprName { - range: 1479..1483, + range: 1646..1650, id: "type", ctx: Store, }, ), value: NumberLiteral( ExprNumberLiteral { - range: 1487..1488, + range: 1654..1655, value: Int( 1, ), @@ -1978,7 +2357,7 @@ Module( body: [ Pass( StmtPass { - range: 1490..1494, + range: 1657..1661, }, ), ], @@ -1987,11 +2366,11 @@ Module( ), Assign( StmtAssign { - range: 1495..1530, + range: 1662..1697, targets: [ Name( ExprName { - range: 1495..1499, + range: 1662..1666, id: "type", ctx: Store, }, @@ -1999,19 +2378,19 @@ Module( ], value: Lambda( ExprLambda { - range: 1502..1530, + range: 1669..1697, parameters: Some( Parameters { - range: 1509..1514, + range: 1676..1681, posonlyargs: [], args: [ ParameterWithDefault { - range: 1509..1514, + range: 1676..1681, parameter: Parameter { - range: 1509..1514, + range: 1676..1681, name: Identifier { id: "query", - range: 1509..1514, + range: 1676..1681, }, annotation: None, }, @@ -2025,10 +2404,10 @@ Module( ), body: Compare( ExprCompare { - range: 1516..1530, + range: 1683..1697, left: Name( ExprName { - range: 1516..1521, + range: 1683..1688, id: "query", ctx: Load, }, @@ -2039,7 +2418,7 @@ Module( comparators: [ Name( ExprName { - range: 1525..1530, + range: 1692..1697, id: "event", ctx: Load, }, @@ -2053,36 +2432,36 @@ Module( ), Expr( StmtExpr { - range: 1531..1546, + range: 1698..1713, value: Call( ExprCall { - range: 1531..1546, + range: 1698..1713, func: Name( ExprName { - range: 1531..1536, + range: 1698..1703, id: "print", ctx: Load, }, ), arguments: Arguments { - range: 1536..1546, + range: 1703..1713, args: [ Call( ExprCall { - range: 1537..1545, + range: 1704..1712, func: Name( ExprName { - range: 1537..1541, + range: 1704..1708, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1541..1545, + range: 1708..1712, args: [ NumberLiteral( ExprNumberLiteral { - range: 1542..1544, + range: 1709..1711, value: Int( 12, ), @@ -2102,23 +2481,23 @@ Module( ), Expr( StmtExpr { - range: 1547..1557, + range: 1714..1724, value: Call( ExprCall { - range: 1547..1557, + range: 1714..1724, func: Name( ExprName { - range: 1547..1551, + range: 1714..1718, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1551..1557, + range: 1718..1724, args: [ Name( ExprName { - range: 1552..1556, + range: 1719..1723, id: "type", ctx: Load, }, @@ -2132,11 +2511,11 @@ Module( ), Assign( StmtAssign { - range: 1558..1576, + range: 1725..1743, targets: [ Name( ExprName { - range: 1558..1559, + range: 1725..1726, id: "a", ctx: Store, }, @@ -2144,10 +2523,10 @@ Module( ], value: Compare( ExprCompare { - range: 1565..1574, + range: 1732..1741, left: Name( ExprName { - range: 1565..1569, + range: 1732..1736, id: "type", ctx: Load, }, @@ -2158,7 +2537,7 @@ Module( comparators: [ Name( ExprName { - range: 1573..1574, + range: 1740..1741, id: "C", ctx: Load, }, @@ -2170,11 +2549,11 @@ Module( ), Assign( StmtAssign { - range: 1577..1593, + range: 1744..1760, targets: [ Name( ExprName { - range: 1577..1578, + range: 1744..1745, id: "a", ctx: Store, }, @@ -2182,20 +2561,20 @@ Module( ], value: Call( ExprCall { - range: 1584..1591, + range: 1751..1758, func: Name( ExprName { - range: 1584..1588, + range: 1751..1755, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1588..1591, + range: 1755..1758, args: [ Name( ExprName { - range: 1589..1590, + range: 1756..1757, id: "b", ctx: Load, }, @@ -2209,32 +2588,32 @@ Module( ), Expr( StmtExpr { - range: 1594..1611, + range: 1761..1778, value: Call( ExprCall { - range: 1594..1611, + range: 1761..1778, func: Name( ExprName { - range: 1594..1598, + range: 1761..1765, id: "type", ctx: Load, }, ), arguments: Arguments { - range: 1599..1611, + range: 1766..1778, args: [], keywords: [ Keyword { - range: 1602..1609, + range: 1769..1776, arg: Some( Identifier { id: "X", - range: 1602..1603, + range: 1769..1770, }, ), value: Name( ExprName { - range: 1606..1609, + range: 1773..1776, id: "int", ctx: Load, }, @@ -2248,11 +2627,11 @@ Module( ), Assign( StmtAssign { - range: 1612..1620, + range: 1779..1787, targets: [ Name( ExprName { - range: 1612..1616, + range: 1779..1783, id: "type", ctx: Store, }, @@ -2260,7 +2639,7 @@ Module( ], value: NumberLiteral( ExprNumberLiteral { - range: 1619..1620, + range: 1786..1787, value: Int( 1, ), @@ -2270,18 +2649,18 @@ Module( ), Assign( StmtAssign { - range: 1621..1633, + range: 1788..1800, targets: [ Name( ExprName { - range: 1621..1625, + range: 1788..1792, id: "type", ctx: Store, }, ), Name( ExprName { - range: 1628..1629, + range: 1795..1796, id: "x", ctx: Store, }, @@ -2289,7 +2668,7 @@ Module( ], value: NumberLiteral( ExprNumberLiteral { - range: 1632..1633, + range: 1799..1800, value: Int( 1, ), @@ -2299,18 +2678,18 @@ Module( ), Assign( StmtAssign { - range: 1634..1646, + range: 1801..1813, targets: [ Name( ExprName { - range: 1634..1635, + range: 1801..1802, id: "x", ctx: Store, }, ), Name( ExprName { - range: 1638..1642, + range: 1805..1809, id: "type", ctx: Store, }, @@ -2318,7 +2697,7 @@ Module( ], value: NumberLiteral( ExprNumberLiteral { - range: 1645..1646, + range: 1812..1813, value: Int( 1, ), @@ -2328,22 +2707,22 @@ Module( ), Expr( StmtExpr { - range: 1647..1661, + range: 1814..1828, value: Lambda( ExprLambda { - range: 1647..1661, + range: 1814..1828, parameters: Some( Parameters { - range: 1654..1655, + range: 1821..1822, posonlyargs: [], args: [ ParameterWithDefault { - range: 1654..1655, + range: 1821..1822, parameter: Parameter { - range: 1654..1655, + range: 1821..1822, name: Identifier { id: "x", - range: 1654..1655, + range: 1821..1822, }, annotation: None, }, @@ -2357,7 +2736,7 @@ Module( ), body: Name( ExprName { - range: 1657..1661, + range: 1824..1828, id: "type", ctx: Load, }, diff --git a/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_param_spec.py.snap b/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_param_spec.py.snap new file mode 100644 index 0000000000000..5b26b475fce6c --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_param_spec.py.snap @@ -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, + }, + ), + }, + ), + ], + }, +) +``` diff --git a/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_type_var.py.snap b/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_type_var.py.snap new file mode 100644 index 0000000000000..4477747d42dd8 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_type_var.py.snap @@ -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, + }, + ), + }, + ), + ], + }, +) +``` diff --git a/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_type_var_tuple.py.snap b/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_type_var_tuple.py.snap new file mode 100644 index 0000000000000..199f094a1ca16 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/valid_syntax@type_param_type_var_tuple.py.snap @@ -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, + }, + ), + }, + ), + ], + }, +) +```