From b52839da82a6f451ae8bae4669303c2aa6e85181 Mon Sep 17 00:00:00 2001 From: elazar Date: Sun, 9 Apr 2017 05:33:23 +0300 Subject: [PATCH 1/5] start fix --- mypy/checkmember.py | 6 ++++-- mypy/messages.py | 5 ++++- mypy/types.py | 8 +++++++- test-data/unit/check-classes.test | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 6c934dccb022..9442e7ed4b8e 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -218,7 +218,6 @@ def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, if isinstance(vv, Decorator): # The associated Var node of a decorator contains the type. v = vv.var - if isinstance(v, Var): return analyze_var(name, v, itype, info, node, is_lvalue, msg, original_type, not_ready_callback) @@ -632,11 +631,14 @@ def expand(target: Type) -> Type: arg_types = func.arg_types[1:] ret_type = func.ret_type variables = func.variables + if isinstance(original_type, FunctionLike) and original_type.is_type_obj(): + original_type = original_type.fallback res = func.copy_modified(arg_types=arg_types, arg_kinds=func.arg_kinds[1:], arg_names=func.arg_names[1:], variables=variables, - ret_type=ret_type) + ret_type=ret_type, + bound_args=[original_type]) return cast(F, res) diff --git a/mypy/messages.py b/mypy/messages.py index da1b2bfb4c04..b327347d2c22 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -485,7 +485,10 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type: target = '' if callee.name: name = callee.name - base = extract_type(name) + if callee.bound_args and callee.bound_args[0] is not None: + base = self.format(callee.bound_args[0]) + else: + base = extract_type(name) for op, method in op_methods.items(): for variant in method, '__r' + method[2:]: diff --git a/mypy/types.py b/mypy/types.py index 1bba37724ced..2ebf2d545be6 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -534,6 +534,8 @@ class CallableType(FunctionLike): # Was this callable generated by analyzing Type[...] instantiation? from_type_type = False # type: bool + bound_args = None # type: List[Type] + def __init__(self, arg_types: List[Type], arg_kinds: List[int], @@ -550,6 +552,7 @@ def __init__(self, is_classmethod_class: bool = False, special_sig: Optional[str] = None, from_type_type: bool = False, + bound_args: List[Type] = None, ) -> None: if variables is None: variables = [] @@ -571,6 +574,7 @@ def __init__(self, self.is_classmethod_class = is_classmethod_class self.special_sig = special_sig self.from_type_type = from_type_type + self.bound_args = bound_args or [] super().__init__(line, column) def copy_modified(self, @@ -586,7 +590,8 @@ def copy_modified(self, column: int = _dummy, is_ellipsis_args: bool = _dummy, special_sig: Optional[str] = _dummy, - from_type_type: bool = _dummy) -> 'CallableType': + from_type_type: bool = _dummy, + bound_args: List[Type] = _dummy) -> 'CallableType': return CallableType( arg_types=arg_types if arg_types is not _dummy else self.arg_types, arg_kinds=arg_kinds if arg_kinds is not _dummy else self.arg_kinds, @@ -604,6 +609,7 @@ def copy_modified(self, is_classmethod_class=self.is_classmethod_class, special_sig=special_sig if special_sig is not _dummy else self.special_sig, from_type_type=from_type_type if from_type_type is not _dummy else self.from_type_type, + bound_args=bound_args if bound_args is not _dummy else self.bound_args, ) def is_type_obj(self) -> bool: diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 56893383b4fd..f2b20fc60dce 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -3035,7 +3035,7 @@ class Meta(type): def __add__(cls, x: X) -> str: ... class Concrete(metaclass=Meta): - pass + def __add__(cls, x: X) -> str: ... reveal_type(Concrete + X()) # E: Revealed type is 'builtins.str' Concrete + "hello" # E: Unsupported operand types for + ("Meta" and "str") From ded2dd345f231428c6314bc0c73215968a3daaa0 Mon Sep 17 00:00:00 2001 From: elazar Date: Sun, 9 Apr 2017 06:28:29 +0300 Subject: [PATCH 2/5] testcheck pass --- test-data/unit/check-generics.test | 12 ++++++------ test-data/unit/check-isinstance.test | 2 +- test-data/unit/check-newsyntax.test | 2 +- test-data/unit/check-optional.test | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 64d010e313fd..9d1a0ae8899e 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -284,9 +284,9 @@ class B: pass class C: pass [out] main:8: error: Incompatible types in assignment (expression has type "C", variable has type "B") -main:9: error: Unsupported operand types for + ("A" and "C") +main:9: error: Unsupported operand types for + (A[B, C] and "C") main:10: error: Incompatible types in assignment (expression has type "B", variable has type "C") -main:11: error: Invalid index type "B" for "A"; expected type "C" +main:11: error: Invalid index type "B" for A[B, C]; expected type "C" [case testOperatorAssignmentWithIndexLvalue1] from typing import TypeVar, Generic @@ -310,7 +310,7 @@ class C: [out] main:7: error: Unsupported operand types for + ("C" and "B") main:7: error: Incompatible types in assignment (expression has type "B", target has type "C") -main:8: error: Invalid index type "C" for "A"; expected type "B" +main:8: error: Invalid index type "C" for A[C]; expected type "B" [case testOperatorAssignmentWithIndexLvalue2] from typing import TypeVar, Generic @@ -331,9 +331,9 @@ class B: pass class C: def __add__(self, o: 'C') -> 'C': pass [out] -main:7: error: Invalid index type "B" for "A"; expected type "C" -main:8: error: Invalid index type "C" for "A"; expected type "B" -main:9: error: Invalid index type "B" for "A"; expected type "C" +main:7: error: Invalid index type "B" for A[C]; expected type "C" +main:8: error: Invalid index type "C" for A[C]; expected type "B" +main:9: error: Invalid index type "B" for A[C]; expected type "C" -- Nested generic types diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index fb6f88871a30..af06f6205e45 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -679,7 +679,7 @@ while bool(): x + 'a' break x + [1] - x + 'a' # E: Unsupported operand types for + ("list" and "str") + x + 'a' # E: Unsupported operand types for + (List[int] and "str") x + [1] # E: Unsupported operand types for + (likely involving Union) [builtins fixtures/isinstancelist.pyi] diff --git a/test-data/unit/check-newsyntax.test b/test-data/unit/check-newsyntax.test index 25fc499e37e3..9f3f87853e63 100644 --- a/test-data/unit/check-newsyntax.test +++ b/test-data/unit/check-newsyntax.test @@ -29,7 +29,7 @@ from typing import Dict, Any d: Dict[int, str] = {} d[42] = 'ab' d[42] = 42 # E: Incompatible types in assignment (expression has type "int", target has type "str") -d['ab'] = 'ab' # E: Invalid index type "str" for "dict"; expected type "int" +d['ab'] = 'ab' # E: Invalid index type "str" for Dict[int, str]; expected type "int" [builtins fixtures/dict.pyi] [out] diff --git a/test-data/unit/check-optional.test b/test-data/unit/check-optional.test index af0f28d74157..e4fb2a16025c 100644 --- a/test-data/unit/check-optional.test +++ b/test-data/unit/check-optional.test @@ -196,7 +196,7 @@ x = {None: None} x["bar"] = 1 [builtins fixtures/dict.pyi] [out] -main:2: error: Invalid index type "str" for "dict"; expected type None +main:2: error: Invalid index type "str" for Dict[None, None]; expected type None main:2: error: Incompatible types in assignment (expression has type "int", target has type None) [case testInferNonOptionalDictType] From 37555da08d56fa179e83d9e97b9dfb41a292408e Mon Sep 17 00:00:00 2001 From: elazar Date: Sun, 9 Apr 2017 07:31:36 +0300 Subject: [PATCH 3/5] fix eval tests --- mypy/checkmember.py | 4 ++-- test-data/unit/check-classes.test | 4 ++-- test-data/unit/pythoneval.test | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 9442e7ed4b8e..f4d1528bff3e 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -631,8 +631,8 @@ def expand(target: Type) -> Type: arg_types = func.arg_types[1:] ret_type = func.ret_type variables = func.variables - if isinstance(original_type, FunctionLike) and original_type.is_type_obj(): - original_type = original_type.fallback + if isinstance(original_type, CallableType) and original_type.is_type_obj(): + original_type = TypeType(original_type.ret_type) res = func.copy_modified(arg_types=arg_types, arg_kinds=func.arg_kinds[1:], arg_names=func.arg_names[1:], diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index f2b20fc60dce..6cb42d70eb86 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -3035,10 +3035,10 @@ class Meta(type): def __add__(cls, x: X) -> str: ... class Concrete(metaclass=Meta): - def __add__(cls, x: X) -> str: ... + pass reveal_type(Concrete + X()) # E: Revealed type is 'builtins.str' -Concrete + "hello" # E: Unsupported operand types for + ("Meta" and "str") +Concrete + "hello" # E: Unsupported operand types for + (Type[Concrete] and "str") [case testMetaclassGetitem] class M(type): diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index d1c2b314019e..567b9a836812 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -577,7 +577,7 @@ print(tuple(a)) import typing [1] + iter([2, 3]) [out] -_program.py:2: error: Unsupported operand types for + ("list" and Iterator[int]) +_program.py:2: error: Unsupported operand types for + (List[int] and Iterator[int]) [case testInferHeterogeneousListOfIterables] from typing import Sequence @@ -1095,10 +1095,10 @@ MyDDict(dict)['0'] MyDDict(dict)[0] [out] _program.py:6: error: Argument 1 to "defaultdict" has incompatible type List[_T]; expected Callable[[], str] -_program.py:9: error: Invalid index type "str" for "dict"; expected type "int" +_program.py:9: error: Invalid index type "str" for defaultdict[int, str]; expected type "int" _program.py:9: error: Incompatible types in assignment (expression has type "int", target has type "str") _program.py:19: error: Dict entry 0 has incompatible type "str": List[] -_program.py:23: error: Invalid index type "str" for "dict"; expected type "int" +_program.py:23: error: Invalid index type "str" for MyDDict[Dict[_KT, _VT]]; expected type "int" [case testNoSubcriptionOfStdlibCollections] import collections @@ -1120,7 +1120,7 @@ def f(d: collections.defaultdict[int, str]) -> None: _program.py:5: error: "defaultdict" is not subscriptable _program.py:6: error: "Counter" is not subscriptable _program.py:9: error: "defaultdict" is not subscriptable -_program.py:12: error: Invalid index type "int" for "dict"; expected type "str" +_program.py:12: error: Invalid index type "int" for defaultdict[str, int]; expected type "str" _program.py:14: error: "defaultdict" is not subscriptable, use "typing.DefaultDict" instead [case testCollectionsAliases] @@ -1148,7 +1148,7 @@ reveal_type(o6) [out] _testCollectionsAliases.py:5: error: Revealed type is 'collections.Counter[builtins.int]' -_testCollectionsAliases.py:6: error: Invalid index type "str" for "dict"; expected type "int" +_testCollectionsAliases.py:6: error: Invalid index type "str" for Counter[int]; expected type "int" _testCollectionsAliases.py:9: error: Revealed type is 'collections.ChainMap[builtins.int, builtins.str]' _testCollectionsAliases.py:12: error: Revealed type is 'collections.deque[builtins.int]' _testCollectionsAliases.py:15: error: Revealed type is 'collections.Counter[builtins.int*]' From ce41922c8f922a715175472f12048b457de2fb87 Mon Sep 17 00:00:00 2001 From: elazar Date: Sun, 9 Apr 2017 07:59:34 +0300 Subject: [PATCH 4/5] remove whitespace --- mypy/checkmember.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index f4d1528bff3e..1a22602b8b02 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -218,6 +218,7 @@ def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, if isinstance(vv, Decorator): # The associated Var node of a decorator contains the type. v = vv.var + if isinstance(v, Var): return analyze_var(name, v, itype, info, node, is_lvalue, msg, original_type, not_ready_callback) From 4d0a95d746f7cbe4bd463c2518c5d424f0d74e52 Mon Sep 17 00:00:00 2001 From: elazar Date: Sun, 9 Apr 2017 08:08:40 +0300 Subject: [PATCH 5/5] handle serialization --- mypy/types.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypy/types.py b/mypy/types.py index 2ebf2d545be6..9a1b1838e9cf 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -745,6 +745,8 @@ def serialize(self) -> JsonDict: 'is_ellipsis_args': self.is_ellipsis_args, 'implicit': self.implicit, 'is_classmethod_class': self.is_classmethod_class, + 'bound_args': [(None if t is None else t.serialize()) + for t in self.bound_args], } @classmethod @@ -762,6 +764,8 @@ def deserialize(cls, data: JsonDict) -> 'CallableType': is_ellipsis_args=data['is_ellipsis_args'], implicit=data['implicit'], is_classmethod_class=data['is_classmethod_class'], + bound_args=[(None if t is None else deserialize_type(t)) + for t in data['bound_args']], )