[syntax-errors] Invalid syntax in annotations (#17101)

Summary
--

This PR detects the use of invalid syntax in annotation scopes,
including
`yield` and `yield from` expressions and named expressions. I combined a
few
different types of CPython errors here, but I think the resulting error
messages
still make sense and are even preferable to what CPython gives. For
example, we
report `yield expression cannot be used in a type annotation` for both
of these:

```pycon
>>> def f[T](x: (yield 1)): ...
  File "<python-input-26>", line 1
    def f[T](x: (yield 1)): ...
                 ^^^^^^^
SyntaxError: yield expression cannot be used within the definition of a generic
>>> def foo() -> (yield x): ...
  File "<python-input-28>", line 1
    def foo() -> (yield x): ...
                  ^^^^^^^
SyntaxError: 'yield' outside function
```

Fixes https://github.com/astral-sh/ruff/issues/11118.

Test Plan
--

New inline tests, along with some updates to existing tests.
This commit is contained in:
Brent Westbrook 2025-04-03 17:56:55 -04:00 committed by GitHub
parent 24b1b1d52c
commit c2b2e42ad3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 2866 additions and 141 deletions

View file

@ -0,0 +1,7 @@
class F[T](y := list): ...
class G((yield 1)): ...
class H((yield from 1)): ...
class I[T]((yield 1)): ...
class J[T]((yield from 1)): ...
class K[T: (yield 1)]: ... # yield in TypeVar
class L[T: (x := 1)]: ... # named expr in TypeVar

View file

@ -0,0 +1,18 @@
def f[T]() -> (y := 3): ...
def g[T](arg: (x := 1)): ...
def h[T](x: (yield 1)): ...
def i(x: (yield 1)): ...
def j[T]() -> (yield 1): ...
def k() -> (yield 1): ...
def l[T](x: (yield from 1)): ...
def m(x: (yield from 1)): ...
def n[T]() -> (yield from 1): ...
def o() -> (yield from 1): ...
def p[T: (yield 1)](): ... # yield in TypeVar bound
def q[T = (yield 1)](): ... # yield in TypeVar default
def r[*Ts = (yield 1)](): ... # yield in TypeVarTuple default
def s[**Ts = (yield 1)](): ... # yield in ParamSpec default
def t[T: (x := 1)](): ... # named expr in TypeVar bound
def u[T = (x := 1)](): ... # named expr in TypeVar default
def v[*Ts = (x := 1)](): ... # named expr in TypeVarTuple default
def w[**Ts = (x := 1)](): ... # named expr in ParamSpec default

View file

@ -0,0 +1,6 @@
type X[T: (yield 1)] = int # TypeVar bound
type X[T = (yield 1)] = int # TypeVar default
type X[*Ts = (yield 1)] = int # TypeVarTuple default
type X[**Ts = (yield 1)] = int # ParamSpec default
type Y = (yield 1) # yield in value
type Y = (x := 1) # named expr in value

View file

@ -1,4 +1,3 @@
def foo() -> int | str: ...
def foo() -> lambda x: x: ...
def foo() -> (yield x): ...
def foo() -> int if True else str: ...

View file

@ -1,4 +1,3 @@
def foo(arg: int): ...
def foo(arg: lambda x: x): ...
def foo(arg: (yield x)): ...
def foo(arg: (x := int)): ...

View file

@ -0,0 +1 @@
class F(y := list): ...

View file

@ -0,0 +1,2 @@
def f() -> (y := 3): ...
def g(arg: (x := 1)): ...

View file

@ -1891,7 +1891,6 @@ impl<'src> Parser<'src> {
// test_ok function_def_valid_return_expr
// def foo() -> int | str: ...
// def foo() -> lambda x: x: ...
// def foo() -> (yield x): ...
// def foo() -> int if True else str: ...
// test_err function_def_invalid_return_expr
@ -2986,7 +2985,6 @@ impl<'src> Parser<'src> {
// test_ok param_with_annotation
// def foo(arg: int): ...
// def foo(arg: lambda x: x): ...
// def foo(arg: (yield x)): ...
// def foo(arg: (x := int)): ...
// test_err param_with_invalid_annotation

View file

@ -114,6 +114,120 @@ impl SemanticSyntaxChecker {
}
Self::debug_shadowing(stmt, ctx);
Self::check_annotation(stmt, ctx);
}
fn check_annotation<Ctx: SemanticSyntaxContext>(stmt: &ast::Stmt, ctx: &Ctx) {
match stmt {
Stmt::FunctionDef(ast::StmtFunctionDef {
type_params,
parameters,
returns,
..
}) => {
// test_ok valid_annotation_function
// def f() -> (y := 3): ...
// def g(arg: (x := 1)): ...
// test_err invalid_annotation_function
// def f[T]() -> (y := 3): ...
// def g[T](arg: (x := 1)): ...
// def h[T](x: (yield 1)): ...
// def i(x: (yield 1)): ...
// def j[T]() -> (yield 1): ...
// def k() -> (yield 1): ...
// def l[T](x: (yield from 1)): ...
// def m(x: (yield from 1)): ...
// def n[T]() -> (yield from 1): ...
// def o() -> (yield from 1): ...
// def p[T: (yield 1)](): ... # yield in TypeVar bound
// def q[T = (yield 1)](): ... # yield in TypeVar default
// def r[*Ts = (yield 1)](): ... # yield in TypeVarTuple default
// def s[**Ts = (yield 1)](): ... # yield in ParamSpec default
// def t[T: (x := 1)](): ... # named expr in TypeVar bound
// def u[T = (x := 1)](): ... # named expr in TypeVar default
// def v[*Ts = (x := 1)](): ... # named expr in TypeVarTuple default
// def w[**Ts = (x := 1)](): ... # named expr in ParamSpec default
let is_generic = type_params.is_some();
let mut visitor = InvalidExpressionVisitor {
allow_named_expr: !is_generic,
position: InvalidExpressionPosition::TypeAnnotation,
ctx,
};
if let Some(type_params) = type_params {
visitor.visit_type_params(type_params);
}
if is_generic {
visitor.position = InvalidExpressionPosition::GenericDefinition;
} else {
visitor.position = InvalidExpressionPosition::TypeAnnotation;
}
for param in parameters
.iter()
.filter_map(ast::AnyParameterRef::annotation)
{
visitor.visit_expr(param);
}
if let Some(returns) = returns {
visitor.visit_expr(returns);
}
}
Stmt::ClassDef(ast::StmtClassDef {
type_params,
arguments,
..
}) => {
// test_ok valid_annotation_class
// class F(y := list): ...
// test_err invalid_annotation_class
// class F[T](y := list): ...
// class G((yield 1)): ...
// class H((yield from 1)): ...
// class I[T]((yield 1)): ...
// class J[T]((yield from 1)): ...
// class K[T: (yield 1)]: ... # yield in TypeVar
// class L[T: (x := 1)]: ... # named expr in TypeVar
let is_generic = type_params.is_some();
let mut visitor = InvalidExpressionVisitor {
allow_named_expr: !is_generic,
position: InvalidExpressionPosition::TypeAnnotation,
ctx,
};
if let Some(type_params) = type_params {
visitor.visit_type_params(type_params);
}
if is_generic {
visitor.position = InvalidExpressionPosition::GenericDefinition;
} else {
visitor.position = InvalidExpressionPosition::BaseClass;
}
if let Some(arguments) = arguments {
visitor.visit_arguments(arguments);
}
}
Stmt::TypeAlias(ast::StmtTypeAlias {
type_params, value, ..
}) => {
// test_err invalid_annotation_type_alias
// type X[T: (yield 1)] = int # TypeVar bound
// type X[T = (yield 1)] = int # TypeVar default
// type X[*Ts = (yield 1)] = int # TypeVarTuple default
// type X[**Ts = (yield 1)] = int # ParamSpec default
// type Y = (yield 1) # yield in value
// type Y = (x := 1) # named expr in value
let mut visitor = InvalidExpressionVisitor {
allow_named_expr: false,
position: InvalidExpressionPosition::TypeAlias,
ctx,
};
visitor.visit_expr(value);
if let Some(type_params) = type_params {
visitor.visit_type_params(type_params);
}
}
_ => {}
}
}
/// Emit a [`SemanticSyntaxErrorKind::InvalidStarExpression`] if `expr` is starred.
@ -511,6 +625,15 @@ impl Display for SemanticSyntaxError {
write!(f, "cannot delete `__debug__` on Python {python_version} (syntax was removed in 3.9)")
}
},
SemanticSyntaxErrorKind::InvalidExpression(
kind,
InvalidExpressionPosition::BaseClass,
) => {
write!(f, "{kind} cannot be used as a base class")
}
SemanticSyntaxErrorKind::InvalidExpression(kind, position) => {
write!(f, "{kind} cannot be used within a {position}")
}
SemanticSyntaxErrorKind::DuplicateMatchKey(key) => {
write!(
f,
@ -641,6 +764,21 @@ pub enum SemanticSyntaxErrorKind {
/// [BPO 45000]: https://github.com/python/cpython/issues/89163
WriteToDebug(WriteToDebugKind),
/// Represents the use of an invalid expression kind in one of several locations.
///
/// The kinds include `yield` and `yield from` expressions and named expressions, and locations
/// include type parameter bounds and defaults, type annotations, type aliases, and base class
/// lists.
///
/// ## Examples
///
/// ```python
/// type X[T: (yield 1)] = int
/// type Y = (yield 1)
/// def f[T](x: int) -> (y := 3): return x
/// ```
InvalidExpression(InvalidExpressionKind, InvalidExpressionPosition),
/// Represents a duplicate key in a `match` mapping pattern.
///
/// The [CPython grammar] allows keys in mapping patterns to be literals or attribute accesses:
@ -713,6 +851,48 @@ pub enum SemanticSyntaxErrorKind {
InvalidStarExpression,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InvalidExpressionPosition {
TypeVarBound,
TypeVarDefault,
TypeVarTupleDefault,
ParamSpecDefault,
TypeAnnotation,
BaseClass,
GenericDefinition,
TypeAlias,
}
impl Display for InvalidExpressionPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
InvalidExpressionPosition::TypeVarBound => "TypeVar bound",
InvalidExpressionPosition::TypeVarDefault => "TypeVar default",
InvalidExpressionPosition::TypeVarTupleDefault => "TypeVarTuple default",
InvalidExpressionPosition::ParamSpecDefault => "ParamSpec default",
InvalidExpressionPosition::TypeAnnotation => "type annotation",
InvalidExpressionPosition::GenericDefinition => "generic definition",
InvalidExpressionPosition::BaseClass => "base class",
InvalidExpressionPosition::TypeAlias => "type alias",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum InvalidExpressionKind {
Yield,
NamedExpr,
}
impl Display for InvalidExpressionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
InvalidExpressionKind::Yield => "yield expression",
InvalidExpressionKind::NamedExpr => "named expression",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WriteToDebugKind {
Store,
@ -905,6 +1085,83 @@ impl<'a, Ctx: SemanticSyntaxContext> MatchPatternVisitor<'a, Ctx> {
}
}
struct InvalidExpressionVisitor<'a, Ctx> {
/// Allow named expressions (`x := ...`) to appear in annotations.
///
/// These are allowed in non-generic functions, for example:
///
/// ```python
/// def foo(arg: (x := int)): ... # ok
/// def foo[T](arg: (x := int)): ... # syntax error
/// ```
allow_named_expr: bool,
/// Context used for emitting errors.
ctx: &'a Ctx,
position: InvalidExpressionPosition,
}
impl<Ctx> Visitor<'_> for InvalidExpressionVisitor<'_, Ctx>
where
Ctx: SemanticSyntaxContext,
{
fn visit_expr(&mut self, expr: &Expr) {
match expr {
Expr::Named(ast::ExprNamed { range, .. }) if !self.allow_named_expr => {
SemanticSyntaxChecker::add_error(
self.ctx,
SemanticSyntaxErrorKind::InvalidExpression(
InvalidExpressionKind::NamedExpr,
self.position,
),
*range,
);
}
Expr::Yield(ast::ExprYield { range, .. })
| Expr::YieldFrom(ast::ExprYieldFrom { range, .. }) => {
SemanticSyntaxChecker::add_error(
self.ctx,
SemanticSyntaxErrorKind::InvalidExpression(
InvalidExpressionKind::Yield,
self.position,
),
*range,
);
}
_ => {}
}
ast::visitor::walk_expr(self, expr);
}
fn visit_type_param(&mut self, type_param: &ast::TypeParam) {
match type_param {
ast::TypeParam::TypeVar(ast::TypeParamTypeVar { bound, default, .. }) => {
if let Some(expr) = bound {
self.position = InvalidExpressionPosition::TypeVarBound;
self.visit_expr(expr);
}
if let Some(expr) = default {
self.position = InvalidExpressionPosition::TypeVarDefault;
self.visit_expr(expr);
}
}
ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { default, .. }) => {
if let Some(expr) = default {
self.position = InvalidExpressionPosition::TypeVarTupleDefault;
self.visit_expr(expr);
}
}
ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { default, .. }) => {
if let Some(expr) = default {
self.position = InvalidExpressionPosition::ParamSpecDefault;
self.visit_expr(expr);
}
}
};
}
}
pub trait SemanticSyntaxContext {
/// Returns `true` if a module's docstring boundary has been passed.
fn seen_docstring_boundary(&self) -> bool;

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/function_def_invalid_return_expr.py
snapshot_kind: text
---
## AST
@ -180,3 +179,13 @@ Module(
3 | def foo() -> yield x: ...
| ^^^^^^^ Syntax Error: Yield expression cannot be used here
|
## Semantic Syntax Errors
|
1 | def foo() -> *int: ...
2 | def foo() -> (*int): ...
3 | def foo() -> yield x: ...
| ^^^^^^^ Syntax Error: yield expression cannot be used within a type annotation
|

View file

@ -0,0 +1,479 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/invalid_annotation_class.py
---
## AST
```
Module(
ModModule {
range: 0..246,
body: [
ClassDef(
StmtClassDef {
range: 0..26,
decorator_list: [],
name: Identifier {
id: Name("F"),
range: 6..7,
},
type_params: Some(
TypeParams {
range: 7..10,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 8..9,
name: Identifier {
id: Name("T"),
range: 8..9,
},
bound: None,
default: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 10..21,
args: [
Named(
ExprNamed {
range: 11..20,
target: Name(
ExprName {
range: 11..12,
id: Name("y"),
ctx: Store,
},
),
value: Name(
ExprName {
range: 16..20,
id: Name("list"),
ctx: Load,
},
),
},
),
],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 23..26,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 23..26,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 27..50,
decorator_list: [],
name: Identifier {
id: Name("G"),
range: 33..34,
},
type_params: None,
arguments: Some(
Arguments {
range: 34..45,
args: [
Yield(
ExprYield {
range: 36..43,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 42..43,
value: Int(
1,
),
},
),
),
},
),
],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 47..50,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 47..50,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 51..79,
decorator_list: [],
name: Identifier {
id: Name("H"),
range: 57..58,
},
type_params: None,
arguments: Some(
Arguments {
range: 58..74,
args: [
YieldFrom(
ExprYieldFrom {
range: 60..72,
value: NumberLiteral(
ExprNumberLiteral {
range: 71..72,
value: Int(
1,
),
},
),
},
),
],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 76..79,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 76..79,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 80..106,
decorator_list: [],
name: Identifier {
id: Name("I"),
range: 86..87,
},
type_params: Some(
TypeParams {
range: 87..90,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 88..89,
name: Identifier {
id: Name("T"),
range: 88..89,
},
bound: None,
default: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 90..101,
args: [
Yield(
ExprYield {
range: 92..99,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 98..99,
value: Int(
1,
),
},
),
),
},
),
],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 103..106,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 103..106,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 107..138,
decorator_list: [],
name: Identifier {
id: Name("J"),
range: 113..114,
},
type_params: Some(
TypeParams {
range: 114..117,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 115..116,
name: Identifier {
id: Name("T"),
range: 115..116,
},
bound: None,
default: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 117..133,
args: [
YieldFrom(
ExprYieldFrom {
range: 119..131,
value: NumberLiteral(
ExprNumberLiteral {
range: 130..131,
value: Int(
1,
),
},
),
},
),
],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 135..138,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 135..138,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 139..165,
decorator_list: [],
name: Identifier {
id: Name("K"),
range: 145..146,
},
type_params: Some(
TypeParams {
range: 146..160,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 147..159,
name: Identifier {
id: Name("T"),
range: 147..148,
},
bound: Some(
Yield(
ExprYield {
range: 151..158,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 157..158,
value: Int(
1,
),
},
),
),
},
),
),
default: None,
},
),
],
},
),
arguments: None,
body: [
Expr(
StmtExpr {
range: 162..165,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 162..165,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 190..215,
decorator_list: [],
name: Identifier {
id: Name("L"),
range: 196..197,
},
type_params: Some(
TypeParams {
range: 197..210,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 198..209,
name: Identifier {
id: Name("T"),
range: 198..199,
},
bound: Some(
Named(
ExprNamed {
range: 202..208,
target: Name(
ExprName {
range: 202..203,
id: Name("x"),
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 207..208,
value: Int(
1,
),
},
),
},
),
),
default: None,
},
),
],
},
),
arguments: None,
body: [
Expr(
StmtExpr {
range: 212..215,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 212..215,
},
),
},
),
],
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | class F[T](y := list): ...
| ^^^^^^^^^ Syntax Error: named expression cannot be used within a generic definition
2 | class G((yield 1)): ...
3 | class H((yield from 1)): ...
|
|
1 | class F[T](y := list): ...
2 | class G((yield 1)): ...
| ^^^^^^^ Syntax Error: yield expression cannot be used as a base class
3 | class H((yield from 1)): ...
4 | class I[T]((yield 1)): ...
|
|
1 | class F[T](y := list): ...
2 | class G((yield 1)): ...
3 | class H((yield from 1)): ...
| ^^^^^^^^^^^^ Syntax Error: yield expression cannot be used as a base class
4 | class I[T]((yield 1)): ...
5 | class J[T]((yield from 1)): ...
|
|
2 | class G((yield 1)): ...
3 | class H((yield from 1)): ...
4 | class I[T]((yield 1)): ...
| ^^^^^^^ Syntax Error: yield expression cannot be used within a generic definition
5 | class J[T]((yield from 1)): ...
6 | class K[T: (yield 1)]: ... # yield in TypeVar
|
|
3 | class H((yield from 1)): ...
4 | class I[T]((yield 1)): ...
5 | class J[T]((yield from 1)): ...
| ^^^^^^^^^^^^ Syntax Error: yield expression cannot be used within a generic definition
6 | class K[T: (yield 1)]: ... # yield in TypeVar
7 | class L[T: (x := 1)]: ... # named expr in TypeVar
|
|
4 | class I[T]((yield 1)): ...
5 | class J[T]((yield from 1)): ...
6 | class K[T: (yield 1)]: ... # yield in TypeVar
| ^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVar bound
7 | class L[T: (x := 1)]: ... # named expr in TypeVar
|
|
5 | class J[T]((yield from 1)): ...
6 | class K[T: (yield 1)]: ... # yield in TypeVar
7 | class L[T: (x := 1)]: ... # named expr in TypeVar
| ^^^^^^ Syntax Error: named expression cannot be used within a TypeVar bound
|

View file

@ -0,0 +1,340 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/invalid_annotation_type_alias.py
---
## AST
```
Module(
ModModule {
range: 0..308,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..26,
name: Name(
ExprName {
range: 5..6,
id: Name("X"),
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 6..20,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 7..19,
name: Identifier {
id: Name("T"),
range: 7..8,
},
bound: Some(
Yield(
ExprYield {
range: 11..18,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 17..18,
value: Int(
1,
),
},
),
),
},
),
),
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 23..26,
id: Name("int"),
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 48..75,
name: Name(
ExprName {
range: 53..54,
id: Name("X"),
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 54..69,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 55..68,
name: Identifier {
id: Name("T"),
range: 55..56,
},
bound: None,
default: Some(
Yield(
ExprYield {
range: 60..67,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 66..67,
value: Int(
1,
),
},
),
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 72..75,
id: Name("int"),
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 98..127,
name: Name(
ExprName {
range: 103..104,
id: Name("X"),
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 104..121,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 105..120,
name: Identifier {
id: Name("Ts"),
range: 106..108,
},
default: Some(
Yield(
ExprYield {
range: 112..119,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 118..119,
value: Int(
1,
),
},
),
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 124..127,
id: Name("int"),
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 153..183,
name: Name(
ExprName {
range: 158..159,
id: Name("X"),
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 159..177,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 160..176,
name: Identifier {
id: Name("Ts"),
range: 162..164,
},
default: Some(
Yield(
ExprYield {
range: 168..175,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 174..175,
value: Int(
1,
),
},
),
),
},
),
),
},
),
],
},
),
value: Name(
ExprName {
range: 180..183,
id: Name("int"),
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 205..223,
name: Name(
ExprName {
range: 210..211,
id: Name("Y"),
ctx: Store,
},
),
type_params: None,
value: Yield(
ExprYield {
range: 215..222,
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 221..222,
value: Int(
1,
),
},
),
),
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 254..271,
name: Name(
ExprName {
range: 259..260,
id: Name("Y"),
ctx: Store,
},
),
type_params: None,
value: Named(
ExprNamed {
range: 264..270,
target: Name(
ExprName {
range: 264..265,
id: Name("x"),
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 269..270,
value: Int(
1,
),
},
),
},
),
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | type X[T: (yield 1)] = int # TypeVar bound
| ^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVar bound
2 | type X[T = (yield 1)] = int # TypeVar default
3 | type X[*Ts = (yield 1)] = int # TypeVarTuple default
|
|
1 | type X[T: (yield 1)] = int # TypeVar bound
2 | type X[T = (yield 1)] = int # TypeVar default
| ^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVar default
3 | type X[*Ts = (yield 1)] = int # TypeVarTuple default
4 | type X[**Ts = (yield 1)] = int # ParamSpec default
|
|
1 | type X[T: (yield 1)] = int # TypeVar bound
2 | type X[T = (yield 1)] = int # TypeVar default
3 | type X[*Ts = (yield 1)] = int # TypeVarTuple default
| ^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVarTuple default
4 | type X[**Ts = (yield 1)] = int # ParamSpec default
5 | type Y = (yield 1) # yield in value
|
|
2 | type X[T = (yield 1)] = int # TypeVar default
3 | type X[*Ts = (yield 1)] = int # TypeVarTuple default
4 | type X[**Ts = (yield 1)] = int # ParamSpec default
| ^^^^^^^ Syntax Error: yield expression cannot be used within a ParamSpec default
5 | type Y = (yield 1) # yield in value
6 | type Y = (x := 1) # named expr in value
|
|
3 | type X[*Ts = (yield 1)] = int # TypeVarTuple default
4 | type X[**Ts = (yield 1)] = int # ParamSpec default
5 | type Y = (yield 1) # yield in value
| ^^^^^^^ Syntax Error: yield expression cannot be used within a type alias
6 | type Y = (x := 1) # named expr in value
|
|
4 | type X[**Ts = (yield 1)] = int # ParamSpec default
5 | type Y = (yield 1) # yield in value
6 | type Y = (x := 1) # named expr in value
| ^^^^^^ Syntax Error: named expression cannot be used within a type alias
|

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/param_with_invalid_annotation.py
snapshot_kind: text
---
## AST
@ -225,3 +224,13 @@ Module(
3 | def foo(arg: x := int): ...
| ^^ Syntax Error: Expected ',', found ':='
|
## Semantic Syntax Errors
|
1 | def foo(arg: *int): ...
2 | def foo(arg: yield int): ...
| ^^^^^^^^^ Syntax Error: yield expression cannot be used within a type annotation
3 | def foo(arg: x := int): ...
|

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/param_with_invalid_star_annotation.py
snapshot_kind: text
---
## AST
@ -309,3 +308,14 @@ Module(
| ^^^^^^^ Syntax Error: Yield expression cannot be used here
5 | # def foo(*args: **int): ...
|
## Semantic Syntax Errors
|
2 | def foo(*args: (*tuple[int])): ...
3 | def foo(*args: *int or str): ...
4 | def foo(*args: *yield x): ...
| ^^^^^^^ Syntax Error: yield expression cannot be used within a type annotation
5 | # def foo(*args: **int): ...
|

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_alias_invalid_value_expr.py
snapshot_kind: text
---
## AST
@ -159,3 +158,23 @@ Module(
4 | type x = x := 1
| ^^ Syntax Error: Expected a statement
|
## Semantic Syntax Errors
|
1 | type x = *y
2 | type x = yield y
| ^^^^^^^ Syntax Error: yield expression cannot be used within a type alias
3 | type x = yield from y
4 | type x = x := 1
|
|
1 | type x = *y
2 | type x = yield y
3 | type x = yield from y
| ^^^^^^^^^^^^ Syntax Error: yield expression cannot be used within a type alias
4 | type x = x := 1
|

View file

@ -1,7 +1,6 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/type_param_invalid_bound_expr.py
snapshot_kind: text
---
## AST
@ -257,3 +256,23 @@ Module(
4 | type X[T: x := int] = int
| ^^ Syntax Error: Expected ',', found ':='
|
## Semantic Syntax Errors
|
1 | type X[T: *int] = int
2 | type X[T: yield x] = int
| ^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVar bound
3 | type X[T: yield from x] = int
4 | type X[T: x := int] = int
|
|
1 | type X[T: *int] = int
2 | type X[T: yield x] = int
3 | type X[T: yield from x] = int
| ^^^^^^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVar bound
4 | type X[T: x := int] = int
|

View file

@ -1,7 +1,6 @@
---
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
snapshot_kind: text
---
## AST
@ -313,3 +312,24 @@ Module(
5 | type X[**P = *int] = int
| ^^^^ Syntax Error: Starred expression cannot be used here
|
## Semantic Syntax Errors
|
1 | type X[**P = *int] = int
2 | type X[**P = yield x] = int
| ^^^^^^^ Syntax Error: yield expression cannot be used within a ParamSpec default
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 within a ParamSpec default
4 | type X[**P = x := int] = int
5 | type X[**P = *int] = int
|

View file

@ -1,7 +1,6 @@
---
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
snapshot_kind: text
---
## AST
@ -378,3 +377,34 @@ Module(
6 | type X[T: int = *int] = int
| ^^^^ Syntax Error: Starred expression cannot be used here
|
## Semantic Syntax Errors
|
1 | type X[T = *int] = int
2 | type X[T = yield x] = int
| ^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVar default
3 | type X[T = (yield x)] = int
4 | type X[T = yield from x] = int
|
|
1 | type X[T = *int] = int
2 | type X[T = yield x] = int
3 | type X[T = (yield x)] = int
| ^^^^^^^ Syntax Error: yield expression cannot be used within a TypeVar default
4 | type X[T = yield from x] = int
5 | type X[T = x := int] = 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 within a TypeVar default
5 | type X[T = x := int] = int
6 | type X[T: int = *int] = int
|

View file

@ -1,7 +1,6 @@
---
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
snapshot_kind: text
---
## AST
@ -320,3 +319,24 @@ Module(
5 | type X[*Ts = x := int] = int
| ^^ Syntax Error: Expected ',', found ':='
|
## Semantic Syntax Errors
|
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 within a TypeVarTuple default
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 within a TypeVarTuple default
5 | type X[*Ts = x := int] = int
|

View file

@ -1,14 +1,13 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/function_def_valid_return_expr.py
snapshot_kind: text
---
## AST
```
Module(
ModModule {
range: 0..125,
range: 0..97,
body: [
FunctionDef(
StmtFunctionDef {
@ -135,7 +134,7 @@ Module(
),
FunctionDef(
StmtFunctionDef {
range: 58..85,
range: 58..96,
is_async: false,
decorator_list: [],
name: Identifier {
@ -151,74 +150,26 @@ Module(
kwonlyargs: [],
kwarg: None,
},
returns: Some(
Yield(
ExprYield {
range: 72..79,
value: Some(
Name(
ExprName {
range: 78..79,
id: Name("x"),
ctx: Load,
},
),
),
},
),
),
body: [
Expr(
StmtExpr {
range: 82..85,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 82..85,
},
),
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 86..124,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("foo"),
range: 90..93,
},
type_params: None,
parameters: Parameters {
range: 93..95,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: Some(
If(
ExprIf {
range: 99..119,
range: 71..91,
test: BooleanLiteral(
ExprBooleanLiteral {
range: 106..110,
range: 78..82,
value: true,
},
),
body: Name(
ExprName {
range: 99..102,
range: 71..74,
id: Name("int"),
ctx: Load,
},
),
orelse: Name(
ExprName {
range: 116..119,
range: 88..91,
id: Name("str"),
ctx: Load,
},
@ -229,10 +180,10 @@ Module(
body: [
Expr(
StmtExpr {
range: 121..124,
range: 93..96,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 121..124,
range: 93..96,
},
),
},

View file

@ -1,14 +1,13 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/param_with_annotation.py
snapshot_kind: text
---
## AST
```
Module(
ModModule {
range: 0..113,
range: 0..84,
body: [
FunctionDef(
StmtFunctionDef {
@ -148,7 +147,7 @@ Module(
),
FunctionDef(
StmtFunctionDef {
range: 54..82,
range: 54..83,
is_async: false,
decorator_list: [],
name: Identifier {
@ -157,92 +156,31 @@ Module(
},
type_params: None,
parameters: Parameters {
range: 61..77,
range: 61..78,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 62..76,
range: 62..77,
parameter: Parameter {
range: 62..76,
range: 62..77,
name: Identifier {
id: Name("arg"),
range: 62..65,
},
annotation: Some(
Yield(
ExprYield {
range: 68..75,
value: Some(
Name(
ExprName {
range: 74..75,
id: Name("x"),
ctx: Load,
},
),
),
},
),
),
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 79..82,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 79..82,
},
),
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 83..112,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("foo"),
range: 87..90,
},
type_params: None,
parameters: Parameters {
range: 90..107,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 91..106,
parameter: Parameter {
range: 91..106,
name: Identifier {
id: Name("arg"),
range: 91..94,
},
annotation: Some(
Named(
ExprNamed {
range: 97..105,
range: 68..76,
target: Name(
ExprName {
range: 97..98,
range: 68..69,
id: Name("x"),
ctx: Store,
},
),
value: Name(
ExprName {
range: 102..105,
range: 73..76,
id: Name("int"),
ctx: Load,
},
@ -262,10 +200,10 @@ Module(
body: [
Expr(
StmtExpr {
range: 109..112,
range: 80..83,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 109..112,
range: 80..83,
},
),
},

View file

@ -0,0 +1,65 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/valid_annotation_class.py
---
## AST
```
Module(
ModModule {
range: 0..24,
body: [
ClassDef(
StmtClassDef {
range: 0..23,
decorator_list: [],
name: Identifier {
id: Name("F"),
range: 6..7,
},
type_params: None,
arguments: Some(
Arguments {
range: 7..18,
args: [
Named(
ExprNamed {
range: 8..17,
target: Name(
ExprName {
range: 8..9,
id: Name("y"),
ctx: Store,
},
),
value: Name(
ExprName {
range: 13..17,
id: Name("list"),
ctx: Load,
},
),
},
),
],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 20..23,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 20..23,
},
),
},
),
],
},
),
],
},
)
```

View file

@ -0,0 +1,136 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/valid_annotation_function.py
---
## AST
```
Module(
ModModule {
range: 0..51,
body: [
FunctionDef(
StmtFunctionDef {
range: 0..24,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("f"),
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..7,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: Some(
Named(
ExprNamed {
range: 12..18,
target: Name(
ExprName {
range: 12..13,
id: Name("y"),
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 17..18,
value: Int(
3,
),
},
),
},
),
),
body: [
Expr(
StmtExpr {
range: 21..24,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 21..24,
},
),
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 25..50,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("g"),
range: 29..30,
},
type_params: None,
parameters: Parameters {
range: 30..45,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 31..44,
parameter: Parameter {
range: 31..44,
name: Identifier {
id: Name("arg"),
range: 31..34,
},
annotation: Some(
Named(
ExprNamed {
range: 37..43,
target: Name(
ExprName {
range: 37..38,
id: Name("x"),
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 42..43,
value: Int(
1,
),
},
),
},
),
),
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 47..50,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 47..50,
},
),
},
),
],
},
),
],
},
)
```