-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Some AST nodes are always invalid in type expressions; we should emit an invalid-type-form diagnostic in red-knot if we see one of these in a type expression. This applies to all of these branches:
ruff/crates/red_knot_python_semantic/src/types/infer.rs
Lines 6150 to 6233 in 7ca5f13
| // Forms which are invalid in the context of annotation expressions: we infer their | |
| // nested expressions as normal expressions, but the type of the top-level expression is | |
| // always `Type::unknown` in these cases. | |
| ast::Expr::BoolOp(bool_op) => { | |
| self.infer_boolean_expression(bool_op); | |
| Type::unknown() | |
| } | |
| ast::Expr::Named(named) => { | |
| self.infer_named_expression(named); | |
| Type::unknown() | |
| } | |
| ast::Expr::UnaryOp(unary) => { | |
| self.infer_unary_expression(unary); | |
| Type::unknown() | |
| } | |
| ast::Expr::Lambda(lambda_expression) => { | |
| self.infer_lambda_expression(lambda_expression); | |
| Type::unknown() | |
| } | |
| ast::Expr::If(if_expression) => { | |
| self.infer_if_expression(if_expression); | |
| Type::unknown() | |
| } | |
| ast::Expr::Dict(dict) => { | |
| self.infer_dict_expression(dict); | |
| Type::unknown() | |
| } | |
| ast::Expr::Set(set) => { | |
| self.infer_set_expression(set); | |
| Type::unknown() | |
| } | |
| ast::Expr::ListComp(listcomp) => { | |
| self.infer_list_comprehension_expression(listcomp); | |
| Type::unknown() | |
| } | |
| ast::Expr::SetComp(setcomp) => { | |
| self.infer_set_comprehension_expression(setcomp); | |
| Type::unknown() | |
| } | |
| ast::Expr::DictComp(dictcomp) => { | |
| self.infer_dict_comprehension_expression(dictcomp); | |
| Type::unknown() | |
| } | |
| ast::Expr::Generator(generator) => { | |
| self.infer_generator_expression(generator); | |
| Type::unknown() | |
| } | |
| ast::Expr::Await(await_expression) => { | |
| self.infer_await_expression(await_expression); | |
| Type::unknown() | |
| } | |
| ast::Expr::Yield(yield_expression) => { | |
| self.infer_yield_expression(yield_expression); | |
| Type::unknown() | |
| } | |
| ast::Expr::YieldFrom(yield_from) => { | |
| self.infer_yield_from_expression(yield_from); | |
| Type::unknown() | |
| } | |
| ast::Expr::Compare(compare) => { | |
| self.infer_compare_expression(compare); | |
| Type::unknown() | |
| } | |
| ast::Expr::Call(call_expr) => { | |
| self.infer_call_expression(call_expr); | |
| Type::unknown() | |
| } | |
| ast::Expr::FString(fstring) => { | |
| self.infer_fstring_expression(fstring); | |
| Type::unknown() | |
| } | |
| ast::Expr::List(list) => { | |
| self.infer_list_expression(list); | |
| Type::unknown() | |
| } | |
| ast::Expr::Tuple(tuple) => { | |
| self.infer_tuple_expression(tuple); | |
| Type::unknown() | |
| } | |
| ast::Expr::Slice(slice) => { | |
| self.infer_slice_expression(slice); | |
| Type::unknown() | |
| } | |
| ast::Expr::IpyEscapeCommand(_) => todo!("Implement Ipy escape command support"), |
Similarly, an ellipsis literal is only valid in very specific contexts in type expressions: as part of a Callable type expression (e.g. Callable[..., int] or as part of a tuple-subscript type expression (e.g. tuple[int, ...]. We should never call infer_type_expression_no_store with an ellipsis literal node if we're visiting a sub-expression in either of those type expressions. So we should also be emitting a diagnostic if we hit this branch:
ruff/crates/red_knot_python_semantic/src/types/infer.rs
Lines 6070 to 6074 in 7ca5f13
| // TODO: an Ellipsis literal *on its own* does not have any meaning in annotation | |
| // expressions, but is meaningful in the context of a number of special forms. | |
| ast::Expr::EllipsisLiteral(_literal) => { | |
| todo_type!("ellipsis literal in type expression") | |
| } |
This would be a good contributor task. The changes required will be very similar to the ones done in #16765. @MatthewMckee4, you might be interested in taking this one on, possibly? :-)