From 3f8c6cbf2d1d174065971d478e61144ed9c7a225 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sat, 10 Aug 2024 13:33:11 -0700 Subject: [PATCH] Resolve TypeVar upper bounds in functools.partial (#17660) Mostly fixes #17646 --- mypy/checker.py | 2 ++ test-data/unit/check-functools.test | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 82633a5b6c0e..db65660bbfbd 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -683,6 +683,8 @@ 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, TypeVarLikeType): + inner_type = get_proper_type(inner_type.upper_bound) if isinstance(inner_type, TypeType): if isinstance(inner_type.item, Instance): inner_type = expand_type_by_instance( diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index 710d3e66dfad..9f8fbd42440b 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -541,3 +541,19 @@ p(1, "no") # E: Argument 2 to "A" has incompatible type "str"; expected "int" q: partial[A] = partial(A, 1) # OK [builtins fixtures/tuple.pyi] + +[case testFunctoolsPartialTypeVarBound] +from typing import Callable, TypeVar, Type +import functools + +T = TypeVar("T", bound=Callable[[str, int], str]) +S = TypeVar("S", bound=Type[int]) + +def foo(f: T) -> T: + g = functools.partial(f, "foo") + return f + +def bar(f: S) -> S: + g = functools.partial(f, "foo") + return f +[builtins fixtures/primitives.pyi]