Skip to content

Commit ab3ec4d

Browse files
[red-knot] Emit errors for more AST nodes that are invalid (or only valid in specific contexts) in type expressions (#16822)
## Summary Add error messages for invalid nodes in type expressions Fixes #16816 ## Test Plan Extend annotations/invalid.md to handle these invalid AST nodes error messages
1 parent a9f5ddd commit ab3ec4d

File tree

2 files changed

+210
-80
lines changed

2 files changed

+210
-80
lines changed

crates/red_knot_python_semantic/resources/mdtest/annotations/invalid.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,60 @@ def _(
4747
## Invalid AST nodes
4848

4949
```py
50+
def bar() -> None:
51+
return None
52+
5053
def _(
5154
a: 1, # error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
5255
b: 2.3, # error: [invalid-type-form] "Float literals are not allowed in type expressions"
5356
c: 4j, # error: [invalid-type-form] "Complex literals are not allowed in type expressions"
5457
d: True, # error: [invalid-type-form] "Boolean literals are not allowed in this context in a type expression"
55-
# error: [invalid-type-form] "Bytes literals are not allowed in this context in a type expression"
56-
e: int | b"foo",
58+
e: int | b"foo", # error: [invalid-type-form] "Bytes literals are not allowed in this context in a type expression"
59+
f: 1 and 2, # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
60+
g: 1 or 2, # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
61+
h: (foo := 1), # error: [invalid-type-form] "Named expressions are not allowed in type expressions"
62+
i: not 1, # error: [invalid-type-form] "Unary operations are not allowed in type expressions"
63+
j: lambda: 1, # error: [invalid-type-form] "`lambda` expressions are not allowed in type expressions"
64+
k: 1 if True else 2, # error: [invalid-type-form] "`if` expressions are not allowed in type expressions"
65+
l: await 1, # error: [invalid-type-form] "`await` expressions are not allowed in type expressions"
66+
m: (yield 1), # error: [invalid-type-form] "`yield` expressions are not allowed in type expressions"
67+
n: (yield from [1]), # error: [invalid-type-form] "`yield from` expressions are not allowed in type expressions"
68+
o: 1 < 2, # error: [invalid-type-form] "Comparison expressions are not allowed in type expressions"
69+
p: bar(), # error: [invalid-type-form] "Function calls are not allowed in type expressions"
70+
q: int | f"foo", # error: [invalid-type-form] "F-strings are not allowed in type expressions"
71+
r: [1, 2, 3][1:2], # error: [invalid-type-form] "Slices are not allowed in type expressions"
5772
):
5873
reveal_type(a) # revealed: Unknown
5974
reveal_type(b) # revealed: Unknown
6075
reveal_type(c) # revealed: Unknown
6176
reveal_type(d) # revealed: Unknown
6277
reveal_type(e) # revealed: int | Unknown
78+
reveal_type(f) # revealed: Unknown
79+
reveal_type(g) # revealed: Unknown
80+
reveal_type(h) # revealed: Unknown
81+
reveal_type(i) # revealed: Unknown
82+
reveal_type(j) # revealed: Unknown
83+
reveal_type(k) # revealed: Unknown
84+
reveal_type(p) # revealed: Unknown
85+
reveal_type(q) # revealed: int | Unknown
86+
reveal_type(r) # revealed: @Todo(generics)
87+
```
88+
89+
## Invalid Collection based AST nodes
90+
91+
```py
92+
def _(
93+
a: {1: 2}, # error: [invalid-type-form] "Dict literals are not allowed in type expressions"
94+
b: {1, 2}, # error: [invalid-type-form] "Set literals are not allowed in type expressions"
95+
c: {k: v for k, v in [(1, 2)]}, # error: [invalid-type-form] "Dict comprehensions are not allowed in type expressions"
96+
d: [k for k in [1, 2]], # error: [invalid-type-form] "List comprehensions are not allowed in type expressions"
97+
e: {k for k in [1, 2]}, # error: [invalid-type-form] "Set comprehensions are not allowed in type expressions"
98+
f: (k for k in [1, 2]), # error: [invalid-type-form] "Generator expressions are not allowed in type expressions"
99+
):
100+
reveal_type(a) # revealed: Unknown
101+
reveal_type(b) # revealed: Unknown
102+
reveal_type(c) # revealed: Unknown
103+
reveal_type(d) # revealed: Unknown
104+
reveal_type(e) # revealed: Unknown
105+
reveal_type(f) # revealed: Unknown
63106
```

crates/red_knot_python_semantic/src/types/infer.rs

Lines changed: 165 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6037,16 +6037,19 @@ impl<'db> TypeInferenceBuilder<'db> {
60376037
annotation_ty
60386038
}
60396039

6040+
fn report_invalid_type_expression(
6041+
&mut self,
6042+
expression: &ast::Expr,
6043+
message: std::fmt::Arguments,
6044+
) -> Type<'db> {
6045+
self.context
6046+
.report_lint(&INVALID_TYPE_FORM, expression, message);
6047+
Type::unknown()
6048+
}
6049+
60406050
/// Infer the type of a type expression without storing the result.
60416051
fn infer_type_expression_no_store(&mut self, expression: &ast::Expr) -> Type<'db> {
60426052
// https://typing.readthedocs.io/en/latest/spec/annotations.html#grammar-token-expression-grammar-type_expression
6043-
6044-
let report_invalid_type_expression = |message: std::fmt::Arguments| {
6045-
self.context
6046-
.report_lint(&INVALID_TYPE_FORM, expression, message);
6047-
Type::unknown()
6048-
};
6049-
60506053
match expression {
60516054
ast::Expr::Name(name) => match name.ctx {
60526055
ast::ExprContext::Load => self
@@ -6071,47 +6074,6 @@ impl<'db> TypeInferenceBuilder<'db> {
60716074
// https://typing.readthedocs.io/en/latest/spec/annotations.html#string-annotations
60726075
ast::Expr::StringLiteral(string) => self.infer_string_type_expression(string),
60736076

6074-
// TODO: an Ellipsis literal *on its own* does not have any meaning in annotation
6075-
// expressions, but is meaningful in the context of a number of special forms.
6076-
ast::Expr::EllipsisLiteral(_literal) => {
6077-
todo_type!("ellipsis literal in type expression")
6078-
}
6079-
6080-
// TODO: add a subdiagnostic linking to type-expression grammar
6081-
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
6082-
ast::Expr::BytesLiteral(_) => report_invalid_type_expression(format_args!(
6083-
"Bytes literals are not allowed in this context in a type expression"
6084-
)),
6085-
6086-
// TODO: add a subdiagnostic linking to type-expression grammar
6087-
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
6088-
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
6089-
value: ast::Number::Int(_),
6090-
..
6091-
}) => report_invalid_type_expression(format_args!(
6092-
"Int literals are not allowed in this context in a type expression"
6093-
)),
6094-
6095-
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
6096-
value: ast::Number::Float(_),
6097-
..
6098-
}) => report_invalid_type_expression(format_args!(
6099-
"Float literals are not allowed in type expressions"
6100-
)),
6101-
6102-
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
6103-
value: ast::Number::Complex { .. },
6104-
..
6105-
}) => report_invalid_type_expression(format_args!(
6106-
"Complex literals are not allowed in type expressions"
6107-
)),
6108-
6109-
// TODO: add a subdiagnostic linking to type-expression grammar
6110-
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
6111-
ast::Expr::BooleanLiteral(_) => report_invalid_type_expression(format_args!(
6112-
"Boolean literals are not allowed in this context in a type expression"
6113-
)),
6114-
61156077
ast::Expr::Subscript(subscript) => {
61166078
let ast::ExprSubscript {
61176079
value,
@@ -6141,100 +6103,225 @@ impl<'db> TypeInferenceBuilder<'db> {
61416103
}
61426104
}
61436105

6144-
// TODO PEP 646
6145-
ast::Expr::Starred(starred) => {
6146-
self.infer_starred_expression(starred);
6147-
todo_type!()
6148-
}
6149-
61506106
// Avoid inferring the types of invalid type expressions that have been parsed from a
61516107
// string annotation, as they are not present in the semantic index.
61526108
_ if self.deferred_state.in_string_annotation() => Type::unknown(),
61536109

6110+
// =====================================================================================
61546111
// Forms which are invalid in the context of annotation expressions: we infer their
61556112
// nested expressions as normal expressions, but the type of the top-level expression is
61566113
// always `Type::unknown` in these cases.
6114+
// =====================================================================================
6115+
6116+
// TODO: add a subdiagnostic linking to type-expression grammar
6117+
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
6118+
ast::Expr::BytesLiteral(_) => self.report_invalid_type_expression(
6119+
expression,
6120+
format_args!("Bytes literals are not allowed in this context in a type expression"),
6121+
),
6122+
6123+
// TODO: add a subdiagnostic linking to type-expression grammar
6124+
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
6125+
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
6126+
value: ast::Number::Int(_),
6127+
..
6128+
}) => self.report_invalid_type_expression(
6129+
expression,
6130+
format_args!("Int literals are not allowed in this context in a type expression"),
6131+
),
6132+
6133+
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
6134+
value: ast::Number::Float(_),
6135+
..
6136+
}) => self.report_invalid_type_expression(
6137+
expression,
6138+
format_args!("Float literals are not allowed in type expressions"),
6139+
),
6140+
6141+
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
6142+
value: ast::Number::Complex { .. },
6143+
..
6144+
}) => self.report_invalid_type_expression(
6145+
expression,
6146+
format_args!("Complex literals are not allowed in type expressions"),
6147+
),
6148+
6149+
// TODO: add a subdiagnostic linking to type-expression grammar
6150+
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
6151+
ast::Expr::BooleanLiteral(_) => self.report_invalid_type_expression(
6152+
expression,
6153+
format_args!(
6154+
"Boolean literals are not allowed in this context in a type expression"
6155+
),
6156+
),
6157+
61576158
ast::Expr::BoolOp(bool_op) => {
61586159
self.infer_boolean_expression(bool_op);
6159-
Type::unknown()
6160+
self.report_invalid_type_expression(
6161+
expression,
6162+
format_args!("Boolean operations are not allowed in type expressions"),
6163+
)
61606164
}
6165+
61616166
ast::Expr::Named(named) => {
61626167
self.infer_named_expression(named);
6163-
Type::unknown()
6168+
self.report_invalid_type_expression(
6169+
expression,
6170+
format_args!("Named expressions are not allowed in type expressions"),
6171+
)
61646172
}
6173+
61656174
ast::Expr::UnaryOp(unary) => {
61666175
self.infer_unary_expression(unary);
6167-
Type::unknown()
6176+
self.report_invalid_type_expression(
6177+
expression,
6178+
format_args!("Unary operations are not allowed in type expressions"),
6179+
)
61686180
}
6181+
61696182
ast::Expr::Lambda(lambda_expression) => {
61706183
self.infer_lambda_expression(lambda_expression);
6171-
Type::unknown()
6184+
self.report_invalid_type_expression(
6185+
expression,
6186+
format_args!("`lambda` expressions are not allowed in type expressions"),
6187+
)
61726188
}
6189+
61736190
ast::Expr::If(if_expression) => {
61746191
self.infer_if_expression(if_expression);
6175-
Type::unknown()
6192+
self.report_invalid_type_expression(
6193+
expression,
6194+
format_args!("`if` expressions are not allowed in type expressions"),
6195+
)
61766196
}
6197+
61776198
ast::Expr::Dict(dict) => {
61786199
self.infer_dict_expression(dict);
6179-
Type::unknown()
6200+
self.report_invalid_type_expression(
6201+
expression,
6202+
format_args!("Dict literals are not allowed in type expressions"),
6203+
)
61806204
}
6205+
61816206
ast::Expr::Set(set) => {
61826207
self.infer_set_expression(set);
6183-
Type::unknown()
6208+
self.report_invalid_type_expression(
6209+
expression,
6210+
format_args!("Set literals are not allowed in type expressions"),
6211+
)
6212+
}
6213+
6214+
ast::Expr::DictComp(dictcomp) => {
6215+
self.infer_dict_comprehension_expression(dictcomp);
6216+
self.report_invalid_type_expression(
6217+
expression,
6218+
format_args!("Dict comprehensions are not allowed in type expressions"),
6219+
)
61846220
}
6221+
61856222
ast::Expr::ListComp(listcomp) => {
61866223
self.infer_list_comprehension_expression(listcomp);
6187-
Type::unknown()
6224+
self.report_invalid_type_expression(
6225+
expression,
6226+
format_args!("List comprehensions are not allowed in type expressions"),
6227+
)
61886228
}
6229+
61896230
ast::Expr::SetComp(setcomp) => {
61906231
self.infer_set_comprehension_expression(setcomp);
6191-
Type::unknown()
6192-
}
6193-
ast::Expr::DictComp(dictcomp) => {
6194-
self.infer_dict_comprehension_expression(dictcomp);
6195-
Type::unknown()
6232+
self.report_invalid_type_expression(
6233+
expression,
6234+
format_args!("Set comprehensions are not allowed in type expressions"),
6235+
)
61966236
}
6237+
61976238
ast::Expr::Generator(generator) => {
61986239
self.infer_generator_expression(generator);
6199-
Type::unknown()
6240+
self.report_invalid_type_expression(
6241+
expression,
6242+
format_args!("Generator expressions are not allowed in type expressions"),
6243+
)
62006244
}
6245+
62016246
ast::Expr::Await(await_expression) => {
62026247
self.infer_await_expression(await_expression);
6203-
Type::unknown()
6248+
self.report_invalid_type_expression(
6249+
expression,
6250+
format_args!("`await` expressions are not allowed in type expressions"),
6251+
)
62046252
}
6253+
62056254
ast::Expr::Yield(yield_expression) => {
62066255
self.infer_yield_expression(yield_expression);
6207-
Type::unknown()
6256+
self.report_invalid_type_expression(
6257+
expression,
6258+
format_args!("`yield` expressions are not allowed in type expressions"),
6259+
)
62086260
}
6261+
62096262
ast::Expr::YieldFrom(yield_from) => {
62106263
self.infer_yield_from_expression(yield_from);
6211-
Type::unknown()
6264+
self.report_invalid_type_expression(
6265+
expression,
6266+
format_args!("`yield from` expressions are not allowed in type expressions"),
6267+
)
62126268
}
6269+
62136270
ast::Expr::Compare(compare) => {
62146271
self.infer_compare_expression(compare);
6215-
Type::unknown()
6272+
self.report_invalid_type_expression(
6273+
expression,
6274+
format_args!("Comparison expressions are not allowed in type expressions"),
6275+
)
62166276
}
6277+
62176278
ast::Expr::Call(call_expr) => {
62186279
self.infer_call_expression(call_expr);
6219-
Type::unknown()
6280+
self.report_invalid_type_expression(
6281+
expression,
6282+
format_args!("Function calls are not allowed in type expressions"),
6283+
)
62206284
}
6285+
62216286
ast::Expr::FString(fstring) => {
62226287
self.infer_fstring_expression(fstring);
6223-
Type::unknown()
6288+
self.report_invalid_type_expression(
6289+
expression,
6290+
format_args!("F-strings are not allowed in type expressions"),
6291+
)
6292+
}
6293+
6294+
ast::Expr::Slice(slice) => {
6295+
self.infer_slice_expression(slice);
6296+
self.report_invalid_type_expression(
6297+
expression,
6298+
format_args!("Slices are not allowed in type expressions"),
6299+
)
6300+
}
6301+
6302+
// =================================================================================
6303+
// Branches where we probably should emit diagnostics in some context, but don't yet
6304+
// =================================================================================
6305+
ast::Expr::IpyEscapeCommand(_) => todo!("Implement Ipy escape command support"),
6306+
6307+
ast::Expr::EllipsisLiteral(_) => {
6308+
todo_type!("ellipsis literal in type expression")
62246309
}
6310+
62256311
ast::Expr::List(list) => {
62266312
self.infer_list_expression(list);
62276313
Type::unknown()
62286314
}
6315+
62296316
ast::Expr::Tuple(tuple) => {
62306317
self.infer_tuple_expression(tuple);
62316318
Type::unknown()
62326319
}
6233-
ast::Expr::Slice(slice) => {
6234-
self.infer_slice_expression(slice);
6235-
Type::unknown()
6320+
6321+
ast::Expr::Starred(starred) => {
6322+
self.infer_starred_expression(starred);
6323+
todo_type!("PEP 646")
62366324
}
6237-
ast::Expr::IpyEscapeCommand(_) => todo!("Implement Ipy escape command support"),
62386325
}
62396326
}
62406327

0 commit comments

Comments
 (0)