[red-knot] Cleanup various todo_type!() messages (#15063)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Alex Waygood 2024-12-19 13:03:41 +00:00 committed by GitHub
parent 596d80cc8e
commit 40cba5dc8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 52 additions and 62 deletions

View file

@ -73,12 +73,12 @@ qux = (foo, bar)
reveal_type(qux) # revealed: tuple[Literal["foo"], Literal["bar"]] reveal_type(qux) # revealed: tuple[Literal["foo"], Literal["bar"]]
# TODO: Infer "LiteralString" # TODO: Infer "LiteralString"
reveal_type(foo.join(qux)) # revealed: @Todo(call todo) reveal_type(foo.join(qux)) # revealed: @Todo(Attribute access on `StringLiteral` types)
template: LiteralString = "{}, {}" template: LiteralString = "{}, {}"
reveal_type(template) # revealed: Literal["{}, {}"] reveal_type(template) # revealed: Literal["{}, {}"]
# TODO: Infer `LiteralString` # TODO: Infer `LiteralString`
reveal_type(template.format(foo, bar)) # revealed: @Todo(call todo) reveal_type(template.format(foo, bar)) # revealed: @Todo(Attribute access on `StringLiteral` types)
``` ```
### Assignability ### Assignability

View file

@ -17,5 +17,5 @@ class Manager:
async def test(): async def test():
async with Manager() as f: async with Manager() as f:
reveal_type(f) # revealed: @Todo(async with statement) reveal_type(f) # revealed: @Todo(async `with` statement)
``` ```

View file

@ -1458,15 +1458,10 @@ impl<'db> Type<'db> {
} }
match self { match self {
Type::Any => Type::Any.into(), Type::Any | Type::Unknown | Type::Todo(_) => self.into(),
Type::Never => { Type::Never => todo_type!("attribute lookup on Never").into(),
// TODO: attribute lookup on Never type
todo_type!().into()
}
Type::Unknown => Type::Unknown.into(),
Type::FunctionLiteral(_) => { Type::FunctionLiteral(_) => {
// TODO: attribute lookup on function type todo_type!("Attribute access on `FunctionLiteral` types").into()
todo_type!().into()
} }
Type::ModuleLiteral(module_ref) => { Type::ModuleLiteral(module_ref) => {
// `__dict__` is a very special member that is never overridden by module globals; // `__dict__` is a very special member that is never overridden by module globals;
@ -1581,40 +1576,38 @@ impl<'db> Type<'db> {
Type::Intersection(_) => { Type::Intersection(_) => {
// TODO perform the get_member on each type in the intersection // TODO perform the get_member on each type in the intersection
// TODO return the intersection of those results // TODO return the intersection of those results
todo_type!().into() todo_type!("Attribute access on `Intersection` types").into()
} }
Type::IntLiteral(_) => { Type::IntLiteral(_) => todo_type!("Attribute access on `IntLiteral` types").into(),
// TODO raise error Type::BooleanLiteral(_) => {
todo_type!().into() todo_type!("Attribute access on `BooleanLiteral` types").into()
} }
Type::BooleanLiteral(_) => todo_type!().into(),
Type::StringLiteral(_) => { Type::StringLiteral(_) => {
// TODO defer to `typing.LiteralString`/`builtins.str` methods // TODO defer to `typing.LiteralString`/`builtins.str` methods
// from typeshed's stubs // from typeshed's stubs
todo_type!().into() todo_type!("Attribute access on `StringLiteral` types").into()
} }
Type::LiteralString => { Type::LiteralString => {
// TODO defer to `typing.LiteralString`/`builtins.str` methods // TODO defer to `typing.LiteralString`/`builtins.str` methods
// from typeshed's stubs // from typeshed's stubs
todo_type!().into() todo_type!("Attribute access on `LiteralString` types").into()
} }
Type::BytesLiteral(_) => { Type::BytesLiteral(_) => {
// TODO defer to Type::Instance(<bytes from typeshed>).member // TODO defer to Type::Instance(<bytes from typeshed>).member
todo_type!().into() todo_type!("Attribute access on `BytesLiteral` types").into()
} }
Type::SliceLiteral(_) => { Type::SliceLiteral(_) => {
// TODO defer to `builtins.slice` methods // TODO defer to `builtins.slice` methods
todo_type!().into() todo_type!("Attribute access on `SliceLiteral` types").into()
} }
Type::Tuple(_) => { Type::Tuple(_) => {
// TODO: implement tuple methods // TODO: implement tuple methods
todo_type!().into() todo_type!("Attribute access on heterogeneous tuple types").into()
} }
Type::AlwaysTruthy | Type::AlwaysFalsy => { Type::AlwaysTruthy | Type::AlwaysFalsy => {
// TODO return `Callable[[], Literal[True/False]]` for `__bool__` access // TODO return `Callable[[], Literal[True/False]]` for `__bool__` access
KnownClass::Object.to_instance(db).member(db, name) KnownClass::Object.to_instance(db).member(db, name)
} }
&todo @ Type::Todo(_) => todo.into(),
} }
} }
@ -1819,12 +1812,8 @@ impl<'db> Type<'db> {
} }
} }
// `Any` is callable, and its return type is also `Any`. // Dynamic types are callable, and the return type is the same dynamic type
Type::Any => CallOutcome::callable(Type::Any), Type::Any | Type::Todo(_) | Type::Unknown => CallOutcome::callable(self),
Type::Todo(_) => CallOutcome::callable(todo_type!("call todo")),
Type::Unknown => CallOutcome::callable(Type::Unknown),
Type::Union(union) => CallOutcome::union( Type::Union(union) => CallOutcome::union(
self, self,
@ -1834,8 +1823,7 @@ impl<'db> Type<'db> {
.map(|elem| elem.call(db, arg_types)), .map(|elem| elem.call(db, arg_types)),
), ),
// TODO: intersection types Type::Intersection(_) => CallOutcome::callable(todo_type!("Type::Intersection.call()")),
Type::Intersection(_) => CallOutcome::callable(todo_type!()),
_ => CallOutcome::not_callable(self), _ => CallOutcome::not_callable(self),
} }
@ -1936,8 +1924,7 @@ impl<'db> Type<'db> {
}) => Type::instance(*class), }) => Type::instance(*class),
Type::SubclassOf(_) => Type::Any, Type::SubclassOf(_) => Type::Any,
Type::Union(union) => union.map(db, |element| element.to_instance(db)), Type::Union(union) => union.map(db, |element| element.to_instance(db)),
// TODO: we can probably do better here: --Alex Type::Intersection(_) => todo_type!("Type::Intersection.to_instance()"),
Type::Intersection(_) => todo_type!(),
// TODO: calling `.to_instance()` on any of these should result in a diagnostic, // TODO: calling `.to_instance()` on any of these should result in a diagnostic,
// since they already indicate that the object is an instance of some kind: // since they already indicate that the object is an instance of some kind:
Type::BooleanLiteral(_) Type::BooleanLiteral(_)
@ -2170,6 +2157,12 @@ impl<'db> From<Type<'db>> for Symbol<'db> {
} }
} }
impl<'db> From<&Type<'db>> for Symbol<'db> {
fn from(value: &Type<'db>) -> Self {
Self::from(*value)
}
}
/// Error struct providing information on type(s) that were deemed to be invalid /// Error struct providing information on type(s) that were deemed to be invalid
/// in a type expression context, and the type we should therefore fallback to /// in a type expression context, and the type we should therefore fallback to
/// for the problematic type expression. /// for the problematic type expression.

View file

@ -1447,7 +1447,7 @@ impl<'db> TypeInferenceBuilder<'db> {
) -> Type<'db> { ) -> Type<'db> {
// TODO: Handle async with statements (they use `aenter` and `aexit`) // TODO: Handle async with statements (they use `aenter` and `aexit`)
if is_async { if is_async {
return todo_type!("async with statement"); return todo_type!("async `with` statement");
} }
let context_manager_ty = context_expression_ty.to_meta_type(self.db()); let context_manager_ty = context_expression_ty.to_meta_type(self.db());
@ -1680,7 +1680,8 @@ impl<'db> TypeInferenceBuilder<'db> {
default, default,
} = node; } = node;
self.infer_optional_expression(default.as_deref()); self.infer_optional_expression(default.as_deref());
self.add_declaration_with_binding(node.into(), definition, todo_type!(), todo_type!()); let pep_695_todo = todo_type!("PEP-695 ParamSpec definition types");
self.add_declaration_with_binding(node.into(), definition, pep_695_todo, pep_695_todo);
} }
fn infer_typevartuple_definition( fn infer_typevartuple_definition(
@ -1694,7 +1695,8 @@ impl<'db> TypeInferenceBuilder<'db> {
default, default,
} = node; } = node;
self.infer_optional_expression(default.as_deref()); self.infer_optional_expression(default.as_deref());
self.add_declaration_with_binding(node.into(), definition, todo_type!(), todo_type!()); let pep_695_todo = todo_type!("PEP-695 TypeVarTuple definition types");
self.add_declaration_with_binding(node.into(), definition, pep_695_todo, pep_695_todo);
} }
fn infer_match_statement(&mut self, match_statement: &ast::StmtMatch) { fn infer_match_statement(&mut self, match_statement: &ast::StmtMatch) {
@ -1729,7 +1731,11 @@ impl<'db> TypeInferenceBuilder<'db> {
// against the subject expression type (which we can query via `infer_expression_types`) // against the subject expression type (which we can query via `infer_expression_types`)
// and extract the type at the `index` position if the pattern matches. This will be // and extract the type at the `index` position if the pattern matches. This will be
// similar to the logic in `self.infer_assignment_definition`. // similar to the logic in `self.infer_assignment_definition`.
self.add_binding(pattern.into(), definition, todo_type!()); self.add_binding(
pattern.into(),
definition,
todo_type!("`match` pattern definition types"),
);
} }
fn infer_match_pattern(&mut self, pattern: &ast::Pattern) { fn infer_match_pattern(&mut self, pattern: &ast::Pattern) {
@ -2483,8 +2489,7 @@ impl<'db> TypeInferenceBuilder<'db> {
ast::Expr::YieldFrom(yield_from) => self.infer_yield_from_expression(yield_from), ast::Expr::YieldFrom(yield_from) => self.infer_yield_from_expression(yield_from),
ast::Expr::Await(await_expression) => self.infer_await_expression(await_expression), ast::Expr::Await(await_expression) => self.infer_await_expression(await_expression),
ast::Expr::IpyEscapeCommand(_) => { ast::Expr::IpyEscapeCommand(_) => {
// TODO Implement Ipy escape command support todo_type!("Ipy escape command support")
todo_type!()
} }
}; };
@ -2922,8 +2927,7 @@ impl<'db> TypeInferenceBuilder<'db> {
self.infer_parameters(parameters); self.infer_parameters(parameters);
} }
// TODO function type todo_type!("typing.Callable type")
todo_type!()
} }
fn infer_call_expression(&mut self, call_expression: &ast::ExprCall) -> Type<'db> { fn infer_call_expression(&mut self, call_expression: &ast::ExprCall) -> Type<'db> {
@ -2959,11 +2963,8 @@ impl<'db> TypeInferenceBuilder<'db> {
fn infer_yield_expression(&mut self, yield_expression: &ast::ExprYield) -> Type<'db> { fn infer_yield_expression(&mut self, yield_expression: &ast::ExprYield) -> Type<'db> {
let ast::ExprYield { range: _, value } = yield_expression; let ast::ExprYield { range: _, value } = yield_expression;
self.infer_optional_expression(value.as_deref()); self.infer_optional_expression(value.as_deref());
todo_type!("yield expressions")
// TODO awaitable type
todo_type!()
} }
fn infer_yield_from_expression(&mut self, yield_from: &ast::ExprYieldFrom) -> Type<'db> { fn infer_yield_from_expression(&mut self, yield_from: &ast::ExprYieldFrom) -> Type<'db> {
@ -2975,16 +2976,13 @@ impl<'db> TypeInferenceBuilder<'db> {
.unwrap_with_diagnostic(&self.context, value.as_ref().into()); .unwrap_with_diagnostic(&self.context, value.as_ref().into());
// TODO get type from `ReturnType` of generator // TODO get type from `ReturnType` of generator
todo_type!() todo_type!("Generic `typing.Generator` type")
} }
fn infer_await_expression(&mut self, await_expression: &ast::ExprAwait) -> Type<'db> { fn infer_await_expression(&mut self, await_expression: &ast::ExprAwait) -> Type<'db> {
let ast::ExprAwait { range: _, value } = await_expression; let ast::ExprAwait { range: _, value } = await_expression;
self.infer_expression(value); self.infer_expression(value);
todo_type!("generic `typing.Awaitable` type")
// TODO awaitable type
todo_type!()
} }
/// Look up a name reference that isn't bound in the local scope. /// Look up a name reference that isn't bound in the local scope.
@ -3521,7 +3519,7 @@ impl<'db> TypeInferenceBuilder<'db> {
(left, Type::BooleanLiteral(bool_value), op) => { (left, Type::BooleanLiteral(bool_value), op) => {
self.infer_binary_expression_type(left, Type::IntLiteral(i64::from(bool_value)), op) self.infer_binary_expression_type(left, Type::IntLiteral(i64::from(bool_value)), op)
} }
_ => Some(todo_type!()), // TODO _ => Some(todo_type!("Support for more binary expressions")),
} }
} }
@ -4040,10 +4038,9 @@ impl<'db> TypeInferenceBuilder<'db> {
} }
} }
} }
// TODO: handle more types
_ => match op { _ => match op {
ast::CmpOp::Is | ast::CmpOp::IsNot => Ok(KnownClass::Bool.to_instance(self.db())), ast::CmpOp::Is | ast::CmpOp::IsNot => Ok(KnownClass::Bool.to_instance(self.db())),
_ => Ok(todo_type!()), _ => Ok(todo_type!("Binary comparisons between more types")),
}, },
} }
} }
@ -4795,7 +4792,7 @@ impl<'db> TypeInferenceBuilder<'db> {
single_element => { single_element => {
let single_element_ty = self.infer_type_expression(single_element); let single_element_ty = self.infer_type_expression(single_element);
if element_could_alter_type_of_whole_tuple(single_element, single_element_ty) { if element_could_alter_type_of_whole_tuple(single_element, single_element_ty) {
todo_type!() todo_type!("full tuple[...] support")
} else { } else {
Type::tuple(self.db(), [single_element_ty]) Type::tuple(self.db(), [single_element_ty])
} }
@ -5034,39 +5031,39 @@ impl<'db> TypeInferenceBuilder<'db> {
KnownInstanceType::ReadOnly => { KnownInstanceType::ReadOnly => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("Required[] type qualifier") todo_type!("`ReadOnly[]` type qualifier")
} }
KnownInstanceType::NotRequired => { KnownInstanceType::NotRequired => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("NotRequired[] type qualifier") todo_type!("`NotRequired[]` type qualifier")
} }
KnownInstanceType::ClassVar => { KnownInstanceType::ClassVar => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("ClassVar[] type qualifier") todo_type!("`ClassVar[]` type qualifier")
} }
KnownInstanceType::Final => { KnownInstanceType::Final => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("Final[] type qualifier") todo_type!("`Final[]` type qualifier")
} }
KnownInstanceType::Required => { KnownInstanceType::Required => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("Required[] type qualifier") todo_type!("`Required[]` type qualifier")
} }
KnownInstanceType::TypeIs => { KnownInstanceType::TypeIs => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("TypeIs[] special form") todo_type!("`TypeIs[]` special form")
} }
KnownInstanceType::TypeGuard => { KnownInstanceType::TypeGuard => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("TypeGuard[] special form") todo_type!("`TypeGuard[]` special form")
} }
KnownInstanceType::Concatenate => { KnownInstanceType::Concatenate => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("Concatenate[] special form") todo_type!("`Concatenate[]` special form")
} }
KnownInstanceType::Unpack => { KnownInstanceType::Unpack => {
self.infer_type_expression(arguments_slice); self.infer_type_expression(arguments_slice);
todo_type!("Unpack[] special form") todo_type!("`Unpack[]` special form")
} }
KnownInstanceType::NoReturn | KnownInstanceType::Never | KnownInstanceType::Any => { KnownInstanceType::NoReturn | KnownInstanceType::Never | KnownInstanceType::Any => {
self.context.report_lint( self.context.report_lint(