From eeecabaab190119674230be1acadfe3922354d4d Mon Sep 17 00:00:00 2001 From: beezee Date: Tue, 12 Nov 2019 06:37:40 -0500 Subject: [PATCH 01/11] bind_self . freshen_function_type_vars need to happen before get_proper_type . expand_type_by_instance --- mypy/checkmember.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 859bd6afcc6d..42170949077d 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -526,12 +526,12 @@ def analyze_var(name: str, if typ: if isinstance(typ, PartialType): return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context) - t = get_proper_type(expand_type_by_instance(typ, itype)) if mx.is_lvalue and var.is_property and not var.is_settable_property: # TODO allow setting attributes in subclass (although it is probably an error) mx.msg.read_only_property(name, itype.type, mx.context) if mx.is_lvalue and var.is_classvar: mx.msg.cant_assign_to_classvar(name, mx.context) + t = get_proper_type(expand_type_by_instance(typ, itype)) result = t # type: Type if var.is_initialized_in_class and isinstance(t, FunctionLike) and not t.is_type_obj(): if mx.is_lvalue: @@ -544,7 +544,7 @@ def analyze_var(name: str, if not var.is_staticmethod: # Class-level function objects and classmethods become bound methods: # the former to the instance, the latter to the class. - functype = t + functype = typ # Use meet to narrow original_type to the dispatched type. # For example, assume # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A) @@ -555,7 +555,9 @@ def analyze_var(name: str, dispatched_type = meet.meet_types(mx.original_type, itype) functype = check_self_arg(functype, dispatched_type, var.is_classmethod, mx.context, name, mx.msg) - signature = bind_self(functype, mx.self_type, var.is_classmethod) + signature = freshen_function_type_vars(functype) + signature = bind_self(signature, mx.self_type, var.is_classmethod) + signature = get_proper_type(expand_type_by_instance(signature, itype)) if var.is_property: # A property cannot have an overloaded type => the cast is fine. assert isinstance(signature, CallableType) From 5fb04e39d6e44d915ee4cabdd34f9ef258187d65 Mon Sep 17 00:00:00 2001 From: beezee Date: Tue, 12 Nov 2019 07:19:46 -0500 Subject: [PATCH 02/11] update self type method test, we now bind_self before substituting type vars --- test-data/unit/check-selftype.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index c4d1bb3d2e53..467579a112d2 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -468,13 +468,13 @@ class B(A[Q]): a: A[int] b: B[str] reveal_type(a.g) # N: Revealed type is 'builtins.int' -reveal_type(a.gt) # N: Revealed type is 'builtins.int*' +reveal_type(a.gt) # N: Revealed type is 'builtins.int' reveal_type(a.f()) # N: Revealed type is 'builtins.int' -reveal_type(a.ft()) # N: Revealed type is '__main__.A*[builtins.int]' +reveal_type(a.ft()) # N: Revealed type is '__main__.A[builtins.int]' reveal_type(b.g) # N: Revealed type is 'builtins.int' -reveal_type(b.gt) # N: Revealed type is 'builtins.str*' +reveal_type(b.gt) # N: Revealed type is 'builtins.str' reveal_type(b.f()) # N: Revealed type is 'builtins.int' -reveal_type(b.ft()) # N: Revealed type is '__main__.B*[builtins.str]' +reveal_type(b.ft()) # N: Revealed type is '__main__.B[builtins.str]' [builtins fixtures/property.pyi] [case testSelfTypeRestrictedMethod] From 08049fa33b61aa5b5f6bd722d7108f960e1ab2e5 Mon Sep 17 00:00:00 2001 From: beezee Date: Tue, 12 Nov 2019 08:45:20 -0500 Subject: [PATCH 03/11] add test cases for bugfix --- test-data/unit/check-generics.test | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 09a3616fb3a2..35a661475ad0 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2128,3 +2128,50 @@ class B(A): def from_config(cls) -> B: return B() [builtins fixtures/classmethod.pyi] + +[case testAbstractGenericMethodInference] +from abc import abstractmethod +from typing import Callable, Generic, TypeVar + +A = TypeVar('A') +B = TypeVar('B') +C = TypeVar('C') + +class TwoTypes(Generic[A, B]): + + def __call__(self) -> B: pass + +# TODO - This should extend ABC but test errors that ABC not in abc on import +class MakeTwoAbstract(Generic[A]): + + @abstractmethod + def __call__(self, b: B) -> TwoTypes[A, B]: pass + +class MakeTwoConcrete(Generic[A]): + + def __call__(self, b: B) -> TwoTypes[A, B]: pass + + +class MakeTwoAbstractSubAbstract(Generic[C], MakeTwoAbstract[C]): + + def __call__(self, b: B) -> TwoTypes[C, B]: pass + +class MakeTwoConcreteSubAbstract(MakeTwoAbstract[str]): + + def __call__(self, b: B) -> TwoTypes[str, B]: pass + +class Test(): + + def make_two(self, + mts: MakeTwoAbstract[A], + mte: MakeTwoConcrete[A], + mtasa: MakeTwoAbstractSubAbstract[A], + mtcsa: MakeTwoConcreteSubAbstract) -> None: + reveal_type(mts.__call__) # N: Revealed type is 'def [B] (b: B`1) -> __main__.TwoTypes[A`-1, B`1]' + reveal_type(mts(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' + reveal_type(mte.__call__) # N: Revealed type is 'def [B] (b: B`4) -> __main__.TwoTypes[A`-1, B`4]' + reveal_type(mte(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' + reveal_type(mtasa.__call__) # N: Revealed type is 'def [B] (b: B`7) -> __main__.TwoTypes[A`-1, B`7]' + reveal_type(mtasa(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' + reveal_type(mtcsa.__call__) # N: Revealed type is 'def [B] (b: B`10) -> __main__.TwoTypes[builtins.str, B`10]' + reveal_type(mtcsa(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' From b74ad74e96d597e638fb02333e034fa670de4ea3 Mon Sep 17 00:00:00 2001 From: beezee Date: Tue, 12 Nov 2019 09:18:44 -0500 Subject: [PATCH 04/11] fix very legitimate problem that typechecker caught --- mypy/checkmember.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 42170949077d..89f0e33073d7 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -533,7 +533,7 @@ def analyze_var(name: str, mx.msg.cant_assign_to_classvar(name, mx.context) t = get_proper_type(expand_type_by_instance(typ, itype)) result = t # type: Type - if var.is_initialized_in_class and isinstance(t, FunctionLike) and not t.is_type_obj(): + if var.is_initialized_in_class and isinstance(typ, FunctionLike) and not typ.is_type_obj(): if mx.is_lvalue: if var.is_property: if not var.is_settable_property: @@ -557,13 +557,12 @@ def analyze_var(name: str, mx.context, name, mx.msg) signature = freshen_function_type_vars(functype) signature = bind_self(signature, mx.self_type, var.is_classmethod) - signature = get_proper_type(expand_type_by_instance(signature, itype)) if var.is_property: # A property cannot have an overloaded type => the cast is fine. assert isinstance(signature, CallableType) result = signature.ret_type else: - result = signature + result = get_proper_type(expand_type_by_instance(signature, itype)) else: if not var.is_ready: mx.not_ready_callback(var.name(), mx.context) From a2b8bad1186e3e3bb9e4252f1de8c155ac9497e1 Mon Sep 17 00:00:00 2001 From: beezee Date: Wed, 13 Nov 2019 06:26:00 -0500 Subject: [PATCH 05/11] get_proper_type before isinstance, balance is_property branch --- mypy/checkmember.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 89f0e33073d7..7d1aa9e436ee 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -533,6 +533,7 @@ def analyze_var(name: str, mx.msg.cant_assign_to_classvar(name, mx.context) t = get_proper_type(expand_type_by_instance(typ, itype)) result = t # type: Type + typ = get_proper_type(typ) if var.is_initialized_in_class and isinstance(typ, FunctionLike) and not typ.is_type_obj(): if mx.is_lvalue: if var.is_property: @@ -557,12 +558,13 @@ def analyze_var(name: str, mx.context, name, mx.msg) signature = freshen_function_type_vars(functype) signature = bind_self(signature, mx.self_type, var.is_classmethod) + expanded_signature = get_proper_type(expand_type_by_instance(signature, itype)) if var.is_property: # A property cannot have an overloaded type => the cast is fine. - assert isinstance(signature, CallableType) - result = signature.ret_type + assert isinstance(expanded_signature, CallableType) + result = expanded_signature.ret_type else: - result = get_proper_type(expand_type_by_instance(signature, itype)) + result = expanded_signature else: if not var.is_ready: mx.not_ready_callback(var.name(), mx.context) From 008dc7494cdbda74b9394e7ed5ceb32065ac3b68 Mon Sep 17 00:00:00 2001 From: beezee Date: Wed, 13 Nov 2019 06:26:31 -0500 Subject: [PATCH 06/11] add ABC to stubs, use in added tests, better naming --- test-data/unit/check-generics.test | 20 ++++++++++---------- test-data/unit/lib-stub/abc.pyi | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 35a661475ad0..7e05e7ede216 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2130,7 +2130,7 @@ class B(A): [builtins fixtures/classmethod.pyi] [case testAbstractGenericMethodInference] -from abc import abstractmethod +from abc import ABC, abstractmethod from typing import Callable, Generic, TypeVar A = TypeVar('A') @@ -2142,7 +2142,7 @@ class TwoTypes(Generic[A, B]): def __call__(self) -> B: pass # TODO - This should extend ABC but test errors that ABC not in abc on import -class MakeTwoAbstract(Generic[A]): +class MakeTwoAbstract(ABC, Generic[A]): @abstractmethod def __call__(self, b: B) -> TwoTypes[A, B]: pass @@ -2152,11 +2152,11 @@ class MakeTwoConcrete(Generic[A]): def __call__(self, b: B) -> TwoTypes[A, B]: pass -class MakeTwoAbstractSubAbstract(Generic[C], MakeTwoAbstract[C]): +class MakeTwoGenericSubAbstract(Generic[C], MakeTwoAbstract[C]): def __call__(self, b: B) -> TwoTypes[C, B]: pass -class MakeTwoConcreteSubAbstract(MakeTwoAbstract[str]): +class MakeTwoAppliedSubAbstract(MakeTwoAbstract[str]): def __call__(self, b: B) -> TwoTypes[str, B]: pass @@ -2165,13 +2165,13 @@ class Test(): def make_two(self, mts: MakeTwoAbstract[A], mte: MakeTwoConcrete[A], - mtasa: MakeTwoAbstractSubAbstract[A], - mtcsa: MakeTwoConcreteSubAbstract) -> None: + mtgsa: MakeTwoGenericSubAbstract[A], + mtasa: MakeTwoAppliedSubAbstract) -> None: reveal_type(mts.__call__) # N: Revealed type is 'def [B] (b: B`1) -> __main__.TwoTypes[A`-1, B`1]' reveal_type(mts(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' reveal_type(mte.__call__) # N: Revealed type is 'def [B] (b: B`4) -> __main__.TwoTypes[A`-1, B`4]' reveal_type(mte(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mtasa.__call__) # N: Revealed type is 'def [B] (b: B`7) -> __main__.TwoTypes[A`-1, B`7]' - reveal_type(mtasa(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mtcsa.__call__) # N: Revealed type is 'def [B] (b: B`10) -> __main__.TwoTypes[builtins.str, B`10]' - reveal_type(mtcsa(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' + reveal_type(mtgsa.__call__) # N: Revealed type is 'def [B] (b: B`7) -> __main__.TwoTypes[A`-1, B`7]' + reveal_type(mtgsa(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' + reveal_type(mtasa.__call__) # N: Revealed type is 'def [B] (b: B`10) -> __main__.TwoTypes[builtins.str, B`10]' + reveal_type(mtasa(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' diff --git a/test-data/unit/lib-stub/abc.pyi b/test-data/unit/lib-stub/abc.pyi index 0b1a51c78f5c..da90b588fca3 100644 --- a/test-data/unit/lib-stub/abc.pyi +++ b/test-data/unit/lib-stub/abc.pyi @@ -2,6 +2,7 @@ from typing import Type, Any, TypeVar T = TypeVar('T', bound=Type[Any]) +class ABC(type): pass class ABCMeta(type): def register(cls, tp: T) -> T: pass abstractmethod = object() From 03d49dd59128335f26660a0a27488ea1040b2b9f Mon Sep 17 00:00:00 2001 From: beezee Date: Wed, 13 Nov 2019 07:00:29 -0500 Subject: [PATCH 07/11] build appears deterministic, get to green then discuss brittleness --- test-data/unit/check-generics.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 7e05e7ede216..788ad882e8f0 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2167,11 +2167,11 @@ class Test(): mte: MakeTwoConcrete[A], mtgsa: MakeTwoGenericSubAbstract[A], mtasa: MakeTwoAppliedSubAbstract) -> None: - reveal_type(mts.__call__) # N: Revealed type is 'def [B] (b: B`1) -> __main__.TwoTypes[A`-1, B`1]' + reveal_type(mts.__call__) # N: Revealed type is 'def [B] (b: B`33) -> __main__.TwoTypes[A`-33, B`33]' reveal_type(mts(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mte.__call__) # N: Revealed type is 'def [B] (b: B`4) -> __main__.TwoTypes[A`-1, B`4]' + reveal_type(mte.__call__) # N: Revealed type is 'def [B] (b: B`36) -> __main__.TwoTypes[A`-1, B`36]' reveal_type(mte(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mtgsa.__call__) # N: Revealed type is 'def [B] (b: B`7) -> __main__.TwoTypes[A`-1, B`7]' + reveal_type(mtgsa.__call__) # N: Revealed type is 'def [B] (b: B`39) -> __main__.TwoTypes[A`-1, B`39]' reveal_type(mtgsa(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mtasa.__call__) # N: Revealed type is 'def [B] (b: B`10) -> __main__.TwoTypes[builtins.str, B`10]' + reveal_type(mtasa.__call__) # N: Revealed type is 'def [B] (b: B`42) -> __main__.TwoTypes[builtins.str, B`42]' reveal_type(mtasa(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' From 37275c99976b59158cbf58c013ed19ef2c612480 Mon Sep 17 00:00:00 2001 From: beezee Date: Wed, 13 Nov 2019 07:23:24 -0500 Subject: [PATCH 08/11] overdid it replace on the last commit --- test-data/unit/check-generics.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 788ad882e8f0..d4c91f9b88f2 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2167,7 +2167,7 @@ class Test(): mte: MakeTwoConcrete[A], mtgsa: MakeTwoGenericSubAbstract[A], mtasa: MakeTwoAppliedSubAbstract) -> None: - reveal_type(mts.__call__) # N: Revealed type is 'def [B] (b: B`33) -> __main__.TwoTypes[A`-33, B`33]' + reveal_type(mts.__call__) # N: Revealed type is 'def [B] (b: B`33) -> __main__.TwoTypes[A`-1, B`33]' reveal_type(mts(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' reveal_type(mte.__call__) # N: Revealed type is 'def [B] (b: B`36) -> __main__.TwoTypes[A`-1, B`36]' reveal_type(mte(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' From 4be10a658abb86f85170f9e318e43ded1dbc8bbd Mon Sep 17 00:00:00 2001 From: beezee Date: Thu, 14 Nov 2019 04:50:41 -0500 Subject: [PATCH 09/11] dont include generic types in assertions --- test-data/unit/check-generics.test | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index d4c91f9b88f2..b8939e7bbb1b 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2144,6 +2144,8 @@ class TwoTypes(Generic[A, B]): # TODO - This should extend ABC but test errors that ABC not in abc on import class MakeTwoAbstract(ABC, Generic[A]): + def __init__(self) -> None: pass + @abstractmethod def __call__(self, b: B) -> TwoTypes[A, B]: pass @@ -2167,11 +2169,14 @@ class Test(): mte: MakeTwoConcrete[A], mtgsa: MakeTwoGenericSubAbstract[A], mtasa: MakeTwoAppliedSubAbstract) -> None: - reveal_type(mts.__call__) # N: Revealed type is 'def [B] (b: B`33) -> __main__.TwoTypes[A`-1, B`33]' reveal_type(mts(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mte.__call__) # N: Revealed type is 'def [B] (b: B`36) -> __main__.TwoTypes[A`-1, B`36]' reveal_type(mte(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mtgsa.__call__) # N: Revealed type is 'def [B] (b: B`39) -> __main__.TwoTypes[A`-1, B`39]' reveal_type(mtgsa(2)) # N: Revealed type is '__main__.TwoTypes[A`-1, builtins.int*]' - reveal_type(mtasa.__call__) # N: Revealed type is 'def [B] (b: B`42) -> __main__.TwoTypes[builtins.str, B`42]' reveal_type(mtasa(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' + reveal_type(MakeTwoConcrete[int]()('foo')) # N: Revealed type is '__main__.TwoTypes[builtins.int, builtins.str*]' + reveal_type(MakeTwoConcrete[str]()(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' + reveal_type(MakeTwoAppliedSubAbstract()('foo')) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.str*]' + reveal_type(MakeTwoAppliedSubAbstract()(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' + reveal_type(MakeTwoGenericSubAbstract[str]()('foo')) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.str*]' + reveal_type(MakeTwoGenericSubAbstract[str]()(2)) # N: Revealed type is '__main__.TwoTypes[builtins.str, builtins.int*]' + From 18aa7f8a2d5e87a6bf25ae48eb055023ae7daf91 Mon Sep 17 00:00:00 2001 From: beezee Date: Thu, 14 Nov 2019 04:51:57 -0500 Subject: [PATCH 10/11] remove stale comment --- test-data/unit/check-generics.test | 1 - 1 file changed, 1 deletion(-) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index b8939e7bbb1b..7ec6bfec8446 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2141,7 +2141,6 @@ class TwoTypes(Generic[A, B]): def __call__(self) -> B: pass -# TODO - This should extend ABC but test errors that ABC not in abc on import class MakeTwoAbstract(ABC, Generic[A]): def __init__(self) -> None: pass From 6c6da16338db58f955ddc4b1e85fc7006b021405 Mon Sep 17 00:00:00 2001 From: beezee Date: Thu, 14 Nov 2019 04:56:10 -0500 Subject: [PATCH 11/11] freshen_function_type_vars before check_self_arg --- mypy/checkmember.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 7d1aa9e436ee..5244b1e18ccd 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -554,9 +554,9 @@ def analyze_var(name: str, # In `x.f`, when checking `x` against A1 we assume x is compatible with A # and similarly for B1 when checking agains B dispatched_type = meet.meet_types(mx.original_type, itype) - functype = check_self_arg(functype, dispatched_type, var.is_classmethod, - mx.context, name, mx.msg) signature = freshen_function_type_vars(functype) + signature = check_self_arg(signature, dispatched_type, var.is_classmethod, + mx.context, name, mx.msg) signature = bind_self(signature, mx.self_type, var.is_classmethod) expanded_signature = get_proper_type(expand_type_by_instance(signature, itype)) if var.is_property: 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