Skip to content

Commit

Permalink
[red-knot] Cleanup various todo_type!() messages (#15063)
Browse files Browse the repository at this point in the history
Co-authored-by: Micha Reiser <[email protected]>
  • Loading branch information
AlexWaygood and MichaReiser authored Dec 19, 2024
1 parent 596d80c commit 40cba5d
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ qux = (foo, bar)
reveal_type(qux) # revealed: tuple[Literal["foo"], Literal["bar"]]

# 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 = "{}, {}"
reveal_type(template) # revealed: Literal["{}, {}"]
# 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ class Manager:

async def test():
async with Manager() as f:
reveal_type(f) # revealed: @Todo(async with statement)
reveal_type(f) # revealed: @Todo(async `with` statement)
```
51 changes: 22 additions & 29 deletions crates/red_knot_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1458,15 +1458,10 @@ impl<'db> Type<'db> {
}

match self {
Type::Any => Type::Any.into(),
Type::Never => {
// TODO: attribute lookup on Never type
todo_type!().into()
}
Type::Unknown => Type::Unknown.into(),
Type::Any | Type::Unknown | Type::Todo(_) => self.into(),
Type::Never => todo_type!("attribute lookup on Never").into(),
Type::FunctionLiteral(_) => {
// TODO: attribute lookup on function type
todo_type!().into()
todo_type!("Attribute access on `FunctionLiteral` types").into()
}
Type::ModuleLiteral(module_ref) => {
// `__dict__` is a very special member that is never overridden by module globals;
Expand Down Expand Up @@ -1581,40 +1576,38 @@ impl<'db> Type<'db> {
Type::Intersection(_) => {
// TODO perform the get_member on each type in the intersection
// TODO return the intersection of those results
todo_type!().into()
todo_type!("Attribute access on `Intersection` types").into()
}
Type::IntLiteral(_) => {
// TODO raise error
todo_type!().into()
Type::IntLiteral(_) => todo_type!("Attribute access on `IntLiteral` types").into(),
Type::BooleanLiteral(_) => {
todo_type!("Attribute access on `BooleanLiteral` types").into()
}
Type::BooleanLiteral(_) => todo_type!().into(),
Type::StringLiteral(_) => {
// TODO defer to `typing.LiteralString`/`builtins.str` methods
// from typeshed's stubs
todo_type!().into()
todo_type!("Attribute access on `StringLiteral` types").into()
}
Type::LiteralString => {
// TODO defer to `typing.LiteralString`/`builtins.str` methods
// from typeshed's stubs
todo_type!().into()
todo_type!("Attribute access on `LiteralString` types").into()
}
Type::BytesLiteral(_) => {
// TODO defer to Type::Instance(<bytes from typeshed>).member
todo_type!().into()
todo_type!("Attribute access on `BytesLiteral` types").into()
}
Type::SliceLiteral(_) => {
// TODO defer to `builtins.slice` methods
todo_type!().into()
todo_type!("Attribute access on `SliceLiteral` types").into()
}
Type::Tuple(_) => {
// TODO: implement tuple methods
todo_type!().into()
todo_type!("Attribute access on heterogeneous tuple types").into()
}
Type::AlwaysTruthy | Type::AlwaysFalsy => {
// TODO return `Callable[[], Literal[True/False]]` for `__bool__` access
KnownClass::Object.to_instance(db).member(db, name)
}
&todo @ Type::Todo(_) => todo.into(),
}
}

Expand Down Expand Up @@ -1819,12 +1812,8 @@ impl<'db> Type<'db> {
}
}

// `Any` is callable, and its return type is also `Any`.
Type::Any => CallOutcome::callable(Type::Any),

Type::Todo(_) => CallOutcome::callable(todo_type!("call todo")),

Type::Unknown => CallOutcome::callable(Type::Unknown),
// Dynamic types are callable, and the return type is the same dynamic type
Type::Any | Type::Todo(_) | Type::Unknown => CallOutcome::callable(self),

Type::Union(union) => CallOutcome::union(
self,
Expand All @@ -1834,8 +1823,7 @@ impl<'db> Type<'db> {
.map(|elem| elem.call(db, arg_types)),
),

// TODO: intersection types
Type::Intersection(_) => CallOutcome::callable(todo_type!()),
Type::Intersection(_) => CallOutcome::callable(todo_type!("Type::Intersection.call()")),

_ => CallOutcome::not_callable(self),
}
Expand Down Expand Up @@ -1936,8 +1924,7 @@ impl<'db> Type<'db> {
}) => Type::instance(*class),
Type::SubclassOf(_) => Type::Any,
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(_) => todo_type!("Type::Intersection.to_instance()"),
// 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:
Type::BooleanLiteral(_)
Expand Down Expand Up @@ -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
/// in a type expression context, and the type we should therefore fallback to
/// for the problematic type expression.
Expand Down
57 changes: 27 additions & 30 deletions crates/red_knot_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ impl<'db> TypeInferenceBuilder<'db> {
) -> Type<'db> {
// TODO: Handle async with statements (they use `aenter` and `aexit`)
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());
Expand Down Expand Up @@ -1680,7 +1680,8 @@ impl<'db> TypeInferenceBuilder<'db> {
default,
} = node;
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(
Expand All @@ -1694,7 +1695,8 @@ impl<'db> TypeInferenceBuilder<'db> {
default,
} = node;
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) {
Expand Down Expand Up @@ -1729,7 +1731,11 @@ impl<'db> TypeInferenceBuilder<'db> {
// 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
// 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) {
Expand Down Expand Up @@ -2483,8 +2489,7 @@ impl<'db> TypeInferenceBuilder<'db> {
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::IpyEscapeCommand(_) => {
// TODO Implement Ipy escape command support
todo_type!()
todo_type!("Ipy escape command support")
}
};

Expand Down Expand Up @@ -2922,8 +2927,7 @@ impl<'db> TypeInferenceBuilder<'db> {
self.infer_parameters(parameters);
}

// TODO function type
todo_type!()
todo_type!("typing.Callable type")
}

fn infer_call_expression(&mut self, call_expression: &ast::ExprCall) -> Type<'db> {
Expand Down Expand Up @@ -2959,11 +2963,8 @@ impl<'db> TypeInferenceBuilder<'db> {

fn infer_yield_expression(&mut self, yield_expression: &ast::ExprYield) -> Type<'db> {
let ast::ExprYield { range: _, value } = yield_expression;

self.infer_optional_expression(value.as_deref());

// TODO awaitable type
todo_type!()
todo_type!("yield expressions")
}

fn infer_yield_from_expression(&mut self, yield_from: &ast::ExprYieldFrom) -> Type<'db> {
Expand All @@ -2975,16 +2976,13 @@ impl<'db> TypeInferenceBuilder<'db> {
.unwrap_with_diagnostic(&self.context, value.as_ref().into());

// 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> {
let ast::ExprAwait { range: _, value } = await_expression;

self.infer_expression(value);

// TODO awaitable type
todo_type!()
todo_type!("generic `typing.Awaitable` type")
}

/// Look up a name reference that isn't bound in the local scope.
Expand Down Expand Up @@ -3521,7 +3519,7 @@ impl<'db> TypeInferenceBuilder<'db> {
(left, Type::BooleanLiteral(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")),
}
}

Expand Down Expand Up @@ -4040,10 +4038,9 @@ impl<'db> TypeInferenceBuilder<'db> {
}
}
}
// TODO: handle more types
_ => match op {
ast::CmpOp::Is | ast::CmpOp::IsNot => Ok(KnownClass::Bool.to_instance(self.db())),
_ => Ok(todo_type!()),
_ => Ok(todo_type!("Binary comparisons between more types")),
},
}
}
Expand Down Expand Up @@ -4795,7 +4792,7 @@ impl<'db> TypeInferenceBuilder<'db> {
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) {
todo_type!()
todo_type!("full tuple[...] support")
} else {
Type::tuple(self.db(), [single_element_ty])
}
Expand Down Expand Up @@ -5034,39 +5031,39 @@ impl<'db> TypeInferenceBuilder<'db> {

KnownInstanceType::ReadOnly => {
self.infer_type_expression(arguments_slice);
todo_type!("Required[] type qualifier")
todo_type!("`ReadOnly[]` type qualifier")
}
KnownInstanceType::NotRequired => {
self.infer_type_expression(arguments_slice);
todo_type!("NotRequired[] type qualifier")
todo_type!("`NotRequired[]` type qualifier")
}
KnownInstanceType::ClassVar => {
self.infer_type_expression(arguments_slice);
todo_type!("ClassVar[] type qualifier")
todo_type!("`ClassVar[]` type qualifier")
}
KnownInstanceType::Final => {
self.infer_type_expression(arguments_slice);
todo_type!("Final[] type qualifier")
todo_type!("`Final[]` type qualifier")
}
KnownInstanceType::Required => {
self.infer_type_expression(arguments_slice);
todo_type!("Required[] type qualifier")
todo_type!("`Required[]` type qualifier")
}
KnownInstanceType::TypeIs => {
self.infer_type_expression(arguments_slice);
todo_type!("TypeIs[] special form")
todo_type!("`TypeIs[]` special form")
}
KnownInstanceType::TypeGuard => {
self.infer_type_expression(arguments_slice);
todo_type!("TypeGuard[] special form")
todo_type!("`TypeGuard[]` special form")
}
KnownInstanceType::Concatenate => {
self.infer_type_expression(arguments_slice);
todo_type!("Concatenate[] special form")
todo_type!("`Concatenate[]` special form")
}
KnownInstanceType::Unpack => {
self.infer_type_expression(arguments_slice);
todo_type!("Unpack[] special form")
todo_type!("`Unpack[]` special form")
}
KnownInstanceType::NoReturn | KnownInstanceType::Never | KnownInstanceType::Any => {
self.context.report_lint(
Expand Down

0 comments on commit 40cba5d

Please sign in to comment.