Skip to content

Commit 3f8c6cb

Browse files
authored
Resolve TypeVar upper bounds in functools.partial (#17660)
Mostly fixes #17646
1 parent 9d56820 commit 3f8c6cb

File tree

2 files changed

+18
-0
lines changed

2 files changed

+18
-0
lines changed

mypy/checker.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,8 @@ def extract_callable_type(self, inner_type: Type | None, ctx: Context) -> Callab
683683
inner_type = get_proper_type(inner_type)
684684
outer_type: CallableType | None = None
685685
if inner_type is not None and not isinstance(inner_type, AnyType):
686+
if isinstance(inner_type, TypeVarLikeType):
687+
inner_type = get_proper_type(inner_type.upper_bound)
686688
if isinstance(inner_type, TypeType):
687689
if isinstance(inner_type.item, Instance):
688690
inner_type = expand_type_by_instance(

test-data/unit/check-functools.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,19 @@ p(1, "no") # E: Argument 2 to "A" has incompatible type "str"; expected "int"
541541

542542
q: partial[A] = partial(A, 1) # OK
543543
[builtins fixtures/tuple.pyi]
544+
545+
[case testFunctoolsPartialTypeVarBound]
546+
from typing import Callable, TypeVar, Type
547+
import functools
548+
549+
T = TypeVar("T", bound=Callable[[str, int], str])
550+
S = TypeVar("S", bound=Type[int])
551+
552+
def foo(f: T) -> T:
553+
g = functools.partial(f, "foo")
554+
return f
555+
556+
def bar(f: S) -> S:
557+
g = functools.partial(f, "foo")
558+
return f
559+
[builtins fixtures/primitives.pyi]

0 commit comments

Comments
 (0)