From a33aebd99247527ff77ccd51bfb46238e98648e0 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Thu, 28 Nov 2019 13:05:38 +0000 Subject: [PATCH 1/4] Apply generic class fix also to non-callable types --- mypy/checkmember.py | 2 +- test-data/unit/check-generics.test | 47 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 7d82fd89e737..d8d729bbc7ed 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -855,7 +855,7 @@ class B(A[str]): pass builtin_type, original_type, original_vars=original_vars)) for item in t.items()]) - return t + return expand_type_by_instance(t, isuper) def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> ProperType: diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 82bbe58463f3..3a1346e31e57 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2337,3 +2337,50 @@ class Test(): 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*]' + +[case testGenericClassPropertyBound] +from typing import Generic, TypeVar, Callable, Type, List, Dict + +T = TypeVar('T') +U = TypeVar('U') + +def classproperty(f: Callable[..., U]) -> U: ... + +class C(Generic[T]): + @classproperty + def test(self) -> T: ... + +class D(C[str]): ... +class G(C[List[T]]): ... + +x: C[int] +y: Type[C[int]] +reveal_type(x.test) # N: Revealed type is 'builtins.int*' +reveal_type(y.test) # N: Revealed type is 'builtins.int*' + +xd: D +yd: Type[D] +reveal_type(xd.test) # N: Revealed type is 'builtins.str*' +reveal_type(yd.test) # N: Revealed type is 'builtins.str*' + +xg: G[int] +yg: Type[G[int]] +reveal_type(xg.test) # N: Revealed type is 'builtins.list*[builtins.int*]' +reveal_type(yg.test) # N: Revealed type is 'builtins.list*[builtins.int*]' + +class Sup: + attr: int +S = TypeVar('S', bound=Sup) + +def func(tp: Type[C[S]]) -> S: + reveal_type(tp.test.attr) # N: Revealed type is 'builtins.int' + + reg: Dict[S, G[S]] + reveal_type(reg[tp.test]) # N: Revealed type is '__main__.G*[S`-1]' + reveal_type(reg[tp.test].test) # N: Revealed type is 'builtins.list*[S`-1]' + + if bool(): + return tp.test + else: + return reg[tp.test].test[0] +[builtins fixtures/dict.pyi] From 165b04c14362ba85201e99edaea3be8a02dde170 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Thu, 28 Nov 2019 13:19:56 +0000 Subject: [PATCH 2/4] Fix self-check --- mypy/checkmember.py | 4 +++- mypy/expandtype.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index d8d729bbc7ed..5dd1b62de396 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -855,7 +855,9 @@ class B(A[str]): pass builtin_type, original_type, original_vars=original_vars)) for item in t.items()]) - return expand_type_by_instance(t, isuper) + if isuper is not None: + t = cast(ProperType, expand_type_by_instance(t, isuper)) + return t def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> ProperType: diff --git a/mypy/expandtype.py b/mypy/expandtype.py index 128f187e3d88..cdcb9c77dec2 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -19,6 +19,7 @@ def expand_type(typ: Type, env: Mapping[TypeVarId, Type]) -> Type: def expand_type_by_instance(typ: Type, instance: Instance) -> Type: """Substitute type variables in type using values from an Instance. Type variables are considered to be bound by the class declaration.""" + # TODO: use an overloaded signature? (ProperType stays proper after expansion.) if instance.args == []: return typ else: From 603c858e1cea8f88fd2640c7832db72789f64485 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Thu, 28 Nov 2019 19:21:46 +0000 Subject: [PATCH 3/4] Remove unused arg; improve docstring; add tests --- mypy/checkmember.py | 25 +++++++++++++++---------- test-data/unit/check-generics.test | 13 +++++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 5dd1b62de396..239874f164d2 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -764,8 +764,8 @@ def analyze_class_attribute_access(itype: Instance, t = get_proper_type(t) if isinstance(t, FunctionLike) and is_classmethod: t = check_self_arg(t, mx.self_type, False, mx.context, name, mx.msg) - result = add_class_tvars(t, itype, isuper, is_classmethod, - mx.builtin_type, mx.self_type, original_vars=original_vars) + result = add_class_tvars(t, isuper, is_classmethod, + mx.self_type, original_vars=original_vars) if not mx.is_lvalue: result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type, mx.msg, mx.context, chk=mx.chk) @@ -808,9 +808,8 @@ def analyze_class_attribute_access(itype: Instance, return typ -def add_class_tvars(t: ProperType, itype: Instance, isuper: Optional[Instance], +def add_class_tvars(t: ProperType, isuper: Optional[Instance], is_classmethod: bool, - builtin_type: Callable[[str], Instance], original_type: Type, original_vars: Optional[List[TypeVarDef]] = None) -> Type: """Instantiate type variables during analyze_class_attribute_access, @@ -821,12 +820,18 @@ class A(Generic[T]): def foo(cls: Type[Q]) -> Tuple[T, Q]: ... class B(A[str]): pass - B.foo() - original_type is the value of the type B in the expression B.foo() or the corresponding - component in case if a union (this is used to bind the self-types); original_vars are type - variables of the class callable on which the method was accessed. + Args: + t: Declared type of the method (or property); + isuper: Current instance mapped to the superclass where method was defined, this + is usually done by map_instance_to_supertype(); + is_classmethod: True if this method is decorated with @classmethod; + original_type: The value of the type B in the expression B.foo() or the corresponding + component in case of a union (this is used to bind the self-types); + original_vars: Type variables of the class callable on which the method was accessed. + Returns: + Expanded method type with added type variables (when needed). """ # TODO: verify consistency between Q and T @@ -851,8 +856,8 @@ class B(A[str]): pass t = cast(CallableType, expand_type_by_instance(t, isuper)) return t.copy_modified(variables=tvars + t.variables) elif isinstance(t, Overloaded): - return Overloaded([cast(CallableType, add_class_tvars(item, itype, isuper, is_classmethod, - builtin_type, original_type, + return Overloaded([cast(CallableType, add_class_tvars(item, isuper, + is_classmethod, original_type, original_vars=original_vars)) for item in t.items()]) if isuper is not None: diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 3a1346e31e57..d9fc52b7a5c3 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2351,7 +2351,10 @@ class C(Generic[T]): def test(self) -> T: ... class D(C[str]): ... +class E1(C[T], Generic[T, U]): ... +class E2(C[U], Generic[T, U]): ... class G(C[List[T]]): ... +class F(G[List[int]]): ... x: C[int] y: Type[C[int]] @@ -2363,11 +2366,21 @@ yd: Type[D] reveal_type(xd.test) # N: Revealed type is 'builtins.str*' reveal_type(yd.test) # N: Revealed type is 'builtins.str*' +ye1: Type[E1[int, str]] +ye2: Type[E2[int, str]] +reveal_type(ye1.test) # N: Revealed type is 'builtins.int*' +reveal_type(ye2.test) # N: Revealed type is 'builtins.str*' + xg: G[int] yg: Type[G[int]] reveal_type(xg.test) # N: Revealed type is 'builtins.list*[builtins.int*]' reveal_type(yg.test) # N: Revealed type is 'builtins.list*[builtins.int*]' +xf: F +yf: Type[F] +reveal_type(xf.test) # N: Revealed type is 'builtins.list*[builtins.list*[builtins.int]]' +reveal_type(yf.test) # N: Revealed type is 'builtins.list*[builtins.list*[builtins.int]]' + class Sup: attr: int S = TypeVar('S', bound=Sup) From 40b98dbbbd48a73af3d02cac19fe4443a5d94e9b Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Fri, 29 Nov 2019 13:15:56 +0000 Subject: [PATCH 4/4] Fix docstring punctuation; remove redundant tests --- mypy/checkmember.py | 10 +++++----- test-data/unit/check-generics.test | 6 ------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 239874f164d2..e63dd73335fd 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -823,13 +823,13 @@ class B(A[str]): pass B.foo() Args: - t: Declared type of the method (or property); + t: Declared type of the method (or property) isuper: Current instance mapped to the superclass where method was defined, this - is usually done by map_instance_to_supertype(); - is_classmethod: True if this method is decorated with @classmethod; + is usually done by map_instance_to_supertype() + is_classmethod: True if this method is decorated with @classmethod original_type: The value of the type B in the expression B.foo() or the corresponding - component in case of a union (this is used to bind the self-types); - original_vars: Type variables of the class callable on which the method was accessed. + component in case of a union (this is used to bind the self-types) + original_vars: Type variables of the class callable on which the method was accessed Returns: Expanded method type with added type variables (when needed). """ diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index d9fc52b7a5c3..63e3470c8f56 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2354,7 +2354,6 @@ class D(C[str]): ... class E1(C[T], Generic[T, U]): ... class E2(C[U], Generic[T, U]): ... class G(C[List[T]]): ... -class F(G[List[int]]): ... x: C[int] y: Type[C[int]] @@ -2376,11 +2375,6 @@ yg: Type[G[int]] reveal_type(xg.test) # N: Revealed type is 'builtins.list*[builtins.int*]' reveal_type(yg.test) # N: Revealed type is 'builtins.list*[builtins.int*]' -xf: F -yf: Type[F] -reveal_type(xf.test) # N: Revealed type is 'builtins.list*[builtins.list*[builtins.int]]' -reveal_type(yf.test) # N: Revealed type is 'builtins.list*[builtins.list*[builtins.int]]' - class Sup: attr: int S = TypeVar('S', bound=Sup) 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