[ty] Simplify and fix CallableTypeOf[..] implementation (#20797)

## Summary

Simplify and fix the implementation of
`ty_extensions.CallableTypeOf[..]`.

closes https://github.com/astral-sh/ty/issues/1331

## Test Plan

Added regression test.
This commit is contained in:
David Peter 2025-10-10 12:04:37 +02:00 committed by GitHub
parent a82833a998
commit 949a4f1c42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 8 additions and 39 deletions

View file

@ -689,7 +689,7 @@ def _(
# revealed: (obj: type) -> None
reveal_type(e)
# revealed: (fget: ((Any, /) -> Any) | None = None, fset: ((Any, Any, /) -> None) | None = None, fdel: ((Any, /) -> Any) | None = None, doc: str | None = None) -> Unknown
# revealed: (fget: ((Any, /) -> Any) | None = EllipsisType, fset: ((Any, Any, /) -> None) | None = EllipsisType, fdel: ((Any, /) -> None) | None = EllipsisType, doc: str | None = EllipsisType) -> property
reveal_type(f)
# revealed: Overload[(self: property, instance: None, owner: type, /) -> Unknown, (self: property, instance: object, owner: type | None = None, /) -> Unknown]

View file

@ -493,16 +493,14 @@ def _(
c5: CallableTypeOf[Foo(42).__call__],
c6: CallableTypeOf[Foo(42).returns_self],
c7: CallableTypeOf[Foo.class_method],
c8: CallableTypeOf[Foo(42)],
) -> None:
reveal_type(c1) # revealed: () -> Unknown
reveal_type(c2) # revealed: () -> int
reveal_type(c3) # revealed: (x: int, y: str) -> None
# TODO: should be `(x: int) -> Foo`
reveal_type(c4) # revealed: (...) -> Foo
reveal_type(c4) # revealed: (x: int) -> Foo
reveal_type(c5) # revealed: (x: int) -> str
reveal_type(c6) # revealed: (x: int) -> Foo
reveal_type(c7) # revealed: (x: int) -> Foo
reveal_type(c8) # revealed: (x: int) -> str
```

View file

@ -1108,13 +1108,6 @@ impl<'db> Type<'db> {
matches!(self, Type::FunctionLiteral(..))
}
pub(crate) const fn into_bound_method(self) -> Option<BoundMethodType<'db>> {
match self {
Type::BoundMethod(bound_method) => Some(bound_method),
_ => None,
}
}
pub(crate) fn is_union_of_single_valued(&self, db: &'db dyn Db) -> bool {
self.into_union().is_some_and(|union| {
union.elements(db).iter().all(|ty| {

View file

@ -7,7 +7,7 @@ use crate::types::diagnostic::{
report_invalid_arguments_to_annotated, report_invalid_arguments_to_callable,
};
use crate::types::enums::is_enum_class;
use crate::types::signatures::{CallableSignature, Signature};
use crate::types::signatures::Signature;
use crate::types::string_annotation::parse_string_annotation;
use crate::types::tuple::{TupleSpecBuilder, TupleType};
use crate::types::visitor::any_over_type;
@ -1156,26 +1156,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
let argument_type = self.infer_expression(&arguments[0], TypeContext::default());
let bindings = argument_type.bindings(db);
// SAFETY: This is enforced by the constructor methods on `Bindings` even in
// the case of a non-callable union.
let callable_binding = bindings
.into_iter()
.next()
.expect("`Bindings` should have at least one `CallableBinding`");
let mut signature_iter = callable_binding.into_iter().map(|binding| {
if let Some(bound_method) = argument_type.into_bound_method() {
binding
.signature
.bind_self(self.db(), Some(bound_method.typing_self_type(db)))
} else {
binding.signature.clone()
}
});
let Some(signature) = signature_iter.next() else {
let Some(callable_type) = argument_type.into_callable(db) else {
if let Some(builder) = self
.context
.report_lint(&INVALID_TYPE_FORM, arguments_slice)
@ -1193,14 +1175,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
return Type::unknown();
};
let signature = CallableSignature::from_overloads(
std::iter::once(signature).chain(signature_iter),
);
let callable_type_of = Type::Callable(CallableType::new(db, signature, false));
if arguments_slice.is_tuple_expr() {
self.store_expression_type(arguments_slice, callable_type_of);
self.store_expression_type(arguments_slice, callable_type);
}
callable_type_of
callable_type
}
SpecialFormType::ChainMap => self.infer_parameterized_legacy_typing_alias(