diff --git a/mypy/checker.py b/mypy/checker.py index b8a1e98130712..72bbc3d284ef0 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -681,6 +681,11 @@ def extract_callable_type(self, inner_type: Type | None, ctx: Context) -> Callab inner_type = get_proper_type(inner_type) outer_type: CallableType | None = None if inner_type is not None and not isinstance(inner_type, AnyType): + if isinstance(inner_type, TypeType): + if isinstance(inner_type.item, Instance): + inner_type = expand_type_by_instance( + type_object_type(inner_type.item.type, self.named_type), inner_type.item + ) if isinstance(inner_type, CallableType): outer_type = inner_type elif isinstance(inner_type, Instance): diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index 30ab36abef01d..38083ad98f213 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -303,12 +303,12 @@ p(1) # E: Argument 1 to "A" has incompatible type "int"; expected "str" p(z=1) # E: Unexpected keyword argument "z" for "A" def main(t: Type[A]) -> None: - p = functools.partial(t, 1) # E: "Type[A]" not callable + p = functools.partial(t, 1) reveal_type(p) # N: Revealed type is "functools.partial[__main__.A]" p("a") # OK - p(1) # False negative - p(z=1) # False negative + p(1) # E: Argument 1 to "A" has incompatible type "int"; expected "str" + p(z=1) # E: Unexpected keyword argument "z" for "A" [builtins fixtures/dict.pyi] @@ -346,3 +346,29 @@ reveal_type(functools.partial(fn3, 2)()) # E: "str" not callable \ # N: Revealed type is "builtins.int" \ # E: Argument 1 to "partial" has incompatible type "Union[Callable[[int], int], str]"; expected "Callable[..., int]" [builtins fixtures/tuple.pyi] + +[case testFunctoolsPartialTypeObject] +import functools +from typing import Type, Generic, TypeVar + +class A: + def __init__(self, val: int) -> None: ... + +cls1: Type[A] +reveal_type(functools.partial(cls1, 2)()) # N: Revealed type is "__main__.A" +functools.partial(cls1, "asdf") # E: Argument 1 to "A" has incompatible type "str"; expected "int" + +T = TypeVar("T") +class B(Generic[T]): + def __init__(self, val: T) -> None: ... + +cls2: Type[B[int]] +reveal_type(functools.partial(cls2, 2)()) # N: Revealed type is "__main__.B[builtins.int]" +functools.partial(cls2, "asdf") # E: Argument 1 to "B" has incompatible type "str"; expected "int" + +def foo(cls3: Type[B[T]]): + reveal_type(functools.partial(cls3, "asdf")) # N: Revealed type is "functools.partial[__main__.B[T`-1]]" \ + # E: Argument 1 to "B" has incompatible type "str"; expected "T" + reveal_type(functools.partial(cls3, 2)()) # N: Revealed type is "__main__.B[T`-1]" \ + # E: Argument 1 to "B" has incompatible type "int"; expected "T" +[builtins fixtures/tuple.pyi]