Skip to content

Commit 9d5d0e9

Browse files
beezeemsullivan
authored andcommitted
Fix errors in decorated generic methods (python#7933)
Type variables need to be freshened in this case as well. Fixes python#7863.
1 parent bbb192d commit 9d5d0e9

File tree

4 files changed

+67
-12
lines changed

4 files changed

+67
-12
lines changed

mypy/checkmember.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -528,14 +528,15 @@ def analyze_var(name: str,
528528
if typ:
529529
if isinstance(typ, PartialType):
530530
return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context)
531-
t = get_proper_type(expand_type_by_instance(typ, itype))
532531
if mx.is_lvalue and var.is_property and not var.is_settable_property:
533532
# TODO allow setting attributes in subclass (although it is probably an error)
534533
mx.msg.read_only_property(name, itype.type, mx.context)
535534
if mx.is_lvalue and var.is_classvar:
536535
mx.msg.cant_assign_to_classvar(name, mx.context)
536+
t = get_proper_type(expand_type_by_instance(typ, itype))
537537
result = t # type: Type
538-
if var.is_initialized_in_class and isinstance(t, FunctionLike) and not t.is_type_obj():
538+
typ = get_proper_type(typ)
539+
if var.is_initialized_in_class and isinstance(typ, FunctionLike) and not typ.is_type_obj():
539540
if mx.is_lvalue:
540541
if var.is_property:
541542
if not var.is_settable_property:
@@ -546,7 +547,7 @@ def analyze_var(name: str,
546547
if not var.is_staticmethod:
547548
# Class-level function objects and classmethods become bound methods:
548549
# the former to the instance, the latter to the class.
549-
functype = t
550+
functype = typ
550551
# Use meet to narrow original_type to the dispatched type.
551552
# For example, assume
552553
# * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A)
@@ -555,15 +556,17 @@ def analyze_var(name: str,
555556
# In `x.f`, when checking `x` against A1 we assume x is compatible with A
556557
# and similarly for B1 when checking agains B
557558
dispatched_type = meet.meet_types(mx.original_type, itype)
558-
functype = check_self_arg(functype, dispatched_type, var.is_classmethod,
559+
signature = freshen_function_type_vars(functype)
560+
signature = check_self_arg(signature, dispatched_type, var.is_classmethod,
559561
mx.context, name, mx.msg)
560-
signature = bind_self(functype, mx.self_type, var.is_classmethod)
562+
signature = bind_self(signature, mx.self_type, var.is_classmethod)
563+
expanded_signature = get_proper_type(expand_type_by_instance(signature, itype))
561564
if var.is_property:
562565
# A property cannot have an overloaded type => the cast is fine.
563-
assert isinstance(signature, CallableType)
564-
result = signature.ret_type
566+
assert isinstance(expanded_signature, CallableType)
567+
result = expanded_signature.ret_type
565568
else:
566-
result = signature
569+
result = expanded_signature
567570
else:
568571
if not var.is_ready:
569572
mx.not_ready_callback(var.name, mx.context)

test-data/unit/check-generics.test

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,3 +2287,54 @@ class B(A):
22872287
def from_config(cls) -> B:
22882288
return B()
22892289
[builtins fixtures/classmethod.pyi]
2290+
2291+
[case testAbstractGenericMethodInference]
2292+
from abc import ABC, abstractmethod
2293+
from typing import Callable, Generic, TypeVar
2294+
2295+
A = TypeVar('A')
2296+
B = TypeVar('B')
2297+
C = TypeVar('C')
2298+
2299+
class TwoTypes(Generic[A, B]):
2300+
2301+
def __call__(self) -> B: pass
2302+
2303+
class MakeTwoAbstract(ABC, Generic[A]):
2304+
2305+
def __init__(self) -> None: pass
2306+
2307+
@abstractmethod
2308+
def __call__(self, b: B) -> TwoTypes[A, B]: pass
2309+
2310+
class MakeTwoConcrete(Generic[A]):
2311+
2312+
def __call__(self, b: B) -> TwoTypes[A, B]: pass
2313+
2314+
2315+
class MakeTwoGenericSubAbstract(Generic[C], MakeTwoAbstract[C]):
2316+
2317+
def __call__(self, b: B) -> TwoTypes[C, B]: pass
2318+
2319+
class MakeTwoAppliedSubAbstract(MakeTwoAbstract[str]):
2320+
2321+
def __call__(self, b: B) -> TwoTypes[str, B]: pass
2322+
2323+
class Test():
2324+
2325+
def make_two(self,
2326+
mts: MakeTwoAbstract[A],
2327+
mte: MakeTwoConcrete[A],
2328+
mtgsa: MakeTwoGenericSubAbstract[A],
2329+
mtasa: MakeTwoAppliedSubAbstract) -> None:
2330+
reveal_type(mts(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]'
2331+
reveal_type(mte(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]'
2332+
reveal_type(mtgsa(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]'
2333+
reveal_type(mtasa(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]'
2334+
reveal_type(MakeTwoConcrete[int]()('foo')) # N: Revealed type is '__main__.TwoTypes[builtins.int, builtins.str*]'
2335+
reveal_type(MakeTwoConcrete[str]()(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]'
2336+
reveal_type(MakeTwoAppliedSubAbstract()('foo')) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.str*]'
2337+
reveal_type(MakeTwoAppliedSubAbstract()(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]'
2338+
reveal_type(MakeTwoGenericSubAbstract[str]()('foo')) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.str*]'
2339+
reveal_type(MakeTwoGenericSubAbstract[str]()(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]'
2340+

test-data/unit/check-selftype.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -468,13 +468,13 @@ class B(A[Q]):
468468
a: A[int]
469469
b: B[str]
470470
reveal_type(a.g) # N: Revealed type is 'builtins.int'
471-
reveal_type(a.gt) # N: Revealed type is 'builtins.int*'
471+
reveal_type(a.gt) # N: Revealed type is 'builtins.int'
472472
reveal_type(a.f()) # N: Revealed type is 'builtins.int'
473-
reveal_type(a.ft()) # N: Revealed type is '__main__.A*[builtins.int]'
473+
reveal_type(a.ft()) # N: Revealed type is '__main__.A[builtins.int]'
474474
reveal_type(b.g) # N: Revealed type is 'builtins.int'
475-
reveal_type(b.gt) # N: Revealed type is 'builtins.str*'
475+
reveal_type(b.gt) # N: Revealed type is 'builtins.str'
476476
reveal_type(b.f()) # N: Revealed type is 'builtins.int'
477-
reveal_type(b.ft()) # N: Revealed type is '__main__.B*[builtins.str]'
477+
reveal_type(b.ft()) # N: Revealed type is '__main__.B[builtins.str]'
478478
[builtins fixtures/property.pyi]
479479

480480
[case testSelfTypeRestrictedMethod]

test-data/unit/lib-stub/abc.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ from typing import Type, Any, TypeVar
22

33
T = TypeVar('T', bound=Type[Any])
44

5+
class ABC(type): pass
56
class ABCMeta(type):
67
def register(cls, tp: T) -> T: pass
78
abstractmethod = object()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy