From bfc78e77ae7937925cb8103a4de361568c53b71f Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 27 Sep 2020 23:58:34 -0700 Subject: [PATCH 1/3] Fix partial type crash during protocol checking In particular, this affected hashables. --- mypy/subtypes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 107a5abbebab..81726b1f9884 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -543,6 +543,10 @@ def f(self) -> A: ... # print(member, 'of', right, 'has type', supertype) if not subtype: return False + if isinstance(subtype, PartialType): + subtype = NoneType() if subtype.type is None else Instance( + subtype.type, [AnyType(TypeOfAny.unannotated)] * len(subtype.type.type_vars) + ) if not proper_subtype: # Nominal check currently ignores arg names # NOTE: If we ever change this, be sure to also change the call to From 43d587202ec0a55a133422906523742f8f69f229 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Mon, 28 Sep 2020 18:39:24 -0700 Subject: [PATCH 2/3] add tests --- test-data/unit/check-protocols.test | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 0c0865c0540e..447be4848dd5 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -2536,3 +2536,38 @@ class EmptyProto(Protocol): ... def hh(h: EmptyProto) -> None: pass hh(None) [builtins fixtures/tuple.pyi] + + +[case testPartialTypeProtocol] +from typing import Protocol + +class Flapper(Protocol): + def flap(self) -> int: ... + +class Blooper: + flap = None + + def bloop(self, x: Flapper) -> None: + reveal_type([self, x]) # N: Revealed type is 'builtins.list[builtins.object*]' + +class Gleemer: + flap = [] # E: Need type annotation for 'flap' (hint: "flap: List[] = ...") + + def gleem(self, x: Flapper) -> None: + reveal_type([self, x]) # N: Revealed type is 'builtins.list[builtins.object*]' +[builtins fixtures/tuple.pyi] + + +[case testPartialTypeProtocolHashable] +# flags: --strict-optional +from typing import Protocol + +class Hashable(Protocol): + def __hash__(self) -> int: ... + +class DataArray: + __hash__ = None + + def f(self, x: Hashable) -> None: + reveal_type([self, x]) # N: Revealed type is 'builtins.list[builtins.object*]' +[builtins fixtures/tuple.pyi] \ No newline at end of file From 85e301e5046880086349e930d276e4cb7b296607 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Mon, 28 Sep 2020 19:57:07 -0700 Subject: [PATCH 3/3] Fix up testPartialTypeProtocolHashable This test case was meant to use `--no-strict-optional`, not `--strict-optional`, but happened to crash anyway because object in the test stubs doesn't have __hash__. Both changes made. --- test-data/unit/check-protocols.test | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 447be4848dd5..30d33b917123 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -2559,15 +2559,18 @@ class Gleemer: [case testPartialTypeProtocolHashable] -# flags: --strict-optional +# flags: --no-strict-optional from typing import Protocol class Hashable(Protocol): def __hash__(self) -> int: ... -class DataArray: +class ObjectHashable: + def __hash__(self) -> int: ... + +class DataArray(ObjectHashable): __hash__ = None def f(self, x: Hashable) -> None: reveal_type([self, x]) # N: Revealed type is 'builtins.list[builtins.object*]' -[builtins fixtures/tuple.pyi] \ No newline at end of file +[builtins fixtures/tuple.pyi]