Skip to content

Commit abdafbf

Browse files
ntBreGlyphack
authored andcommitted
[syntax-errors] Check annotations in annotated assignments (astral-sh#17283)
Summary -- This PR extends the checks in astral-sh#17101 and astral-sh#17282 to annotated assignments after Python 3.13. Currently stacked on astral-sh#17282 to include `await`. Test Plan -- New inline tests. These are simpler than the other cases because there's no place to put generics.
1 parent b06c896 commit abdafbf

File tree

5 files changed

+433
-0
lines changed

5 files changed

+433
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# parse_options: {"target-version": "3.14"}
2+
a: (x := 1)
3+
def outer():
4+
b: (yield 1)
5+
c: (yield from 1)
6+
async def outer():
7+
d: (await 1)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# parse_options: {"target-version": "3.13"}
2+
a: (x := 1)
3+
def outer():
4+
b: (yield 1)
5+
c: (yield from 1)
6+
async def outer():
7+
d: (await 1)

crates/ruff_python_parser/src/semantic_errors.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,32 @@ impl SemanticSyntaxChecker {
119119

120120
fn check_annotation<Ctx: SemanticSyntaxContext>(stmt: &ast::Stmt, ctx: &Ctx) {
121121
match stmt {
122+
Stmt::AnnAssign(ast::StmtAnnAssign { annotation, .. }) => {
123+
if ctx.python_version() > PythonVersion::PY313 {
124+
// test_ok valid_annotation_py313
125+
// # parse_options: {"target-version": "3.13"}
126+
// a: (x := 1)
127+
// def outer():
128+
// b: (yield 1)
129+
// c: (yield from 1)
130+
// async def outer():
131+
// d: (await 1)
132+
133+
// test_err invalid_annotation_py314
134+
// # parse_options: {"target-version": "3.14"}
135+
// a: (x := 1)
136+
// def outer():
137+
// b: (yield 1)
138+
// c: (yield from 1)
139+
// async def outer():
140+
// d: (await 1)
141+
let mut visitor = InvalidExpressionVisitor {
142+
position: InvalidExpressionPosition::TypeAnnotation,
143+
ctx,
144+
};
145+
visitor.visit_expr(annotation);
146+
}
147+
}
122148
Stmt::FunctionDef(ast::StmtFunctionDef {
123149
type_params,
124150
parameters,
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
source: crates/ruff_python_parser/tests/fixtures.rs
3+
input_file: crates/ruff_python_parser/resources/inline/err/invalid_annotation_py314.py
4+
---
5+
## AST
6+
7+
```
8+
Module(
9+
ModModule {
10+
range: 0..144,
11+
body: [
12+
AnnAssign(
13+
StmtAnnAssign {
14+
range: 44..55,
15+
target: Name(
16+
ExprName {
17+
range: 44..45,
18+
id: Name("a"),
19+
ctx: Store,
20+
},
21+
),
22+
annotation: Named(
23+
ExprNamed {
24+
range: 48..54,
25+
target: Name(
26+
ExprName {
27+
range: 48..49,
28+
id: Name("x"),
29+
ctx: Store,
30+
},
31+
),
32+
value: NumberLiteral(
33+
ExprNumberLiteral {
34+
range: 53..54,
35+
value: Int(
36+
1,
37+
),
38+
},
39+
),
40+
},
41+
),
42+
value: None,
43+
simple: true,
44+
},
45+
),
46+
FunctionDef(
47+
StmtFunctionDef {
48+
range: 56..107,
49+
is_async: false,
50+
decorator_list: [],
51+
name: Identifier {
52+
id: Name("outer"),
53+
range: 60..65,
54+
},
55+
type_params: None,
56+
parameters: Parameters {
57+
range: 65..67,
58+
posonlyargs: [],
59+
args: [],
60+
vararg: None,
61+
kwonlyargs: [],
62+
kwarg: None,
63+
},
64+
returns: None,
65+
body: [
66+
AnnAssign(
67+
StmtAnnAssign {
68+
range: 73..85,
69+
target: Name(
70+
ExprName {
71+
range: 73..74,
72+
id: Name("b"),
73+
ctx: Store,
74+
},
75+
),
76+
annotation: Yield(
77+
ExprYield {
78+
range: 77..84,
79+
value: Some(
80+
NumberLiteral(
81+
ExprNumberLiteral {
82+
range: 83..84,
83+
value: Int(
84+
1,
85+
),
86+
},
87+
),
88+
),
89+
},
90+
),
91+
value: None,
92+
simple: true,
93+
},
94+
),
95+
AnnAssign(
96+
StmtAnnAssign {
97+
range: 90..107,
98+
target: Name(
99+
ExprName {
100+
range: 90..91,
101+
id: Name("c"),
102+
ctx: Store,
103+
},
104+
),
105+
annotation: YieldFrom(
106+
ExprYieldFrom {
107+
range: 94..106,
108+
value: NumberLiteral(
109+
ExprNumberLiteral {
110+
range: 105..106,
111+
value: Int(
112+
1,
113+
),
114+
},
115+
),
116+
},
117+
),
118+
value: None,
119+
simple: true,
120+
},
121+
),
122+
],
123+
},
124+
),
125+
FunctionDef(
126+
StmtFunctionDef {
127+
range: 108..143,
128+
is_async: true,
129+
decorator_list: [],
130+
name: Identifier {
131+
id: Name("outer"),
132+
range: 118..123,
133+
},
134+
type_params: None,
135+
parameters: Parameters {
136+
range: 123..125,
137+
posonlyargs: [],
138+
args: [],
139+
vararg: None,
140+
kwonlyargs: [],
141+
kwarg: None,
142+
},
143+
returns: None,
144+
body: [
145+
AnnAssign(
146+
StmtAnnAssign {
147+
range: 131..143,
148+
target: Name(
149+
ExprName {
150+
range: 131..132,
151+
id: Name("d"),
152+
ctx: Store,
153+
},
154+
),
155+
annotation: Await(
156+
ExprAwait {
157+
range: 135..142,
158+
value: NumberLiteral(
159+
ExprNumberLiteral {
160+
range: 141..142,
161+
value: Int(
162+
1,
163+
),
164+
},
165+
),
166+
},
167+
),
168+
value: None,
169+
simple: true,
170+
},
171+
),
172+
],
173+
},
174+
),
175+
],
176+
},
177+
)
178+
```
179+
## Semantic Syntax Errors
180+
181+
|
182+
1 | # parse_options: {"target-version": "3.14"}
183+
2 | a: (x := 1)
184+
| ^^^^^^ Syntax Error: named expression cannot be used within a type annotation
185+
3 | def outer():
186+
4 | b: (yield 1)
187+
|
188+
189+
190+
|
191+
2 | a: (x := 1)
192+
3 | def outer():
193+
4 | b: (yield 1)
194+
| ^^^^^^^ Syntax Error: yield expression cannot be used within a type annotation
195+
5 | c: (yield from 1)
196+
6 | async def outer():
197+
|
198+
199+
200+
|
201+
3 | def outer():
202+
4 | b: (yield 1)
203+
5 | c: (yield from 1)
204+
| ^^^^^^^^^^^^ Syntax Error: yield expression cannot be used within a type annotation
205+
6 | async def outer():
206+
7 | d: (await 1)
207+
|
208+
209+
210+
|
211+
5 | c: (yield from 1)
212+
6 | async def outer():
213+
7 | d: (await 1)
214+
| ^^^^^^^ Syntax Error: await expression cannot be used within a type annotation
215+
|

0 commit comments

Comments
 (0)