From 03f144a16da52bb71d88c4b8e4ba050094c51024 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Fri, 17 Feb 2017 22:22:41 +0100 Subject: [PATCH 1/2] Fix generic type expansion for attribute acces on class --- mypy/checkmember.py | 3 ++- test-data/unit/check-generics.test | 33 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 7390bb7baf93..12c68c7fb60e 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -383,7 +383,8 @@ def analyze_class_attribute_access(itype: Instance, if isinstance(t, PartialType): return handle_partial_attribute_type(t, is_lvalue, msg, node.node) is_classmethod = is_decorated and cast(Decorator, node.node).func.is_class - return add_class_tvars(t, itype, is_classmethod, builtin_type, original_type) + res = add_class_tvars(t, itype, is_classmethod, builtin_type, original_type) + return expand_type_by_instance(res, itype) elif isinstance(node.node, Var): not_ready_callback(name, context) return AnyType() diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 1c0c730b2a2e..5acf824f2a92 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -1534,6 +1534,39 @@ class A: def f(cls) -> None: pass [builtins fixtures/classmethod.pyi] +[case testGenericTypeExpansionOnClassAccess] +from typing import TypeVar, Generic +from typing import Generic, TypeVar + +T = TypeVar('T') +class A(Generic[T]): + def f(self, x: T) -> None: + pass +class B(Generic[T]): + x = None # type: A[T] + +B[int].x.f(0) +B[int].x.f('hi') # E: Argument 1 to "f" of "A" has incompatible type "str"; expected "int" +[builtins fixtures/classmethod.pyi] + +[case testGenericClassVariableTypeExpansion] +from typing import TypeVar, Generic, List, Tuple, Union +T = TypeVar('T') +S = TypeVar('S') +class A(Generic[T]): + x = None # type: List[T] + +A[int].x.append(42) +A[int].x.append('hi') # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int" + +class B(Generic[T, S]): + x = None # type: Tuple[T, S] + y = None # type: Union[T, A[S]] + +reveal_type(B[int, str].x) # E: Revealed type is 'Tuple[builtins.int*, builtins.str*]' +reveal_type(B[int, str].y) # E: Revealed type is 'Union[builtins.int*, __maun__.A[builtins.str*]]' +[builtins fixtures/list.pyi] + [case testGenericOperatorMethodOverlapping] from typing import TypeVar, Generic, Tuple T = TypeVar('T') From 4c8e29f9ac365b8600c775f9c0957cf20e53f47d Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Fri, 17 Feb 2017 22:34:22 +0100 Subject: [PATCH 2/2] Fix typo --- 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 5acf824f2a92..c37a46c8092b 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -1564,7 +1564,7 @@ class B(Generic[T, S]): y = None # type: Union[T, A[S]] reveal_type(B[int, str].x) # E: Revealed type is 'Tuple[builtins.int*, builtins.str*]' -reveal_type(B[int, str].y) # E: Revealed type is 'Union[builtins.int*, __maun__.A[builtins.str*]]' +reveal_type(B[int, str].y) # E: Revealed type is 'Union[builtins.int*, __main__.A[builtins.str*]]' [builtins fixtures/list.pyi] [case testGenericOperatorMethodOverlapping]