Skip to content

Commit 91b8610

Browse files
committed
Make None compatible with Hashable (python#9371)
Fixes python#8768.
1 parent d284d19 commit 91b8610

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

mypy/subtypes.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,15 @@ def visit_any(self, left: AnyType) -> bool:
207207

208208
def visit_none_type(self, left: NoneType) -> bool:
209209
if state.strict_optional:
210-
return (isinstance(self.right, NoneType) or
211-
is_named_instance(self.right, 'builtins.object') or
212-
isinstance(self.right, Instance) and self.right.type.is_protocol and
213-
not self.right.type.protocol_members)
210+
if isinstance(self.right, NoneType) or is_named_instance(self.right,
211+
'builtins.object'):
212+
return True
213+
if isinstance(self.right, Instance) and self.right.type.is_protocol:
214+
members = self.right.type.protocol_members
215+
# None is compatible with Hashable (and other similar protocols). This is
216+
# slightly sloppy since we don't check the signature of "__hash__".
217+
return not members or members == ["__hash__"]
218+
return False
214219
else:
215220
return True
216221

test-data/unit/check-protocols.test

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,3 +2499,40 @@ reveal_type(abs(3)) # N: Revealed type is 'builtins.int*'
24992499
reveal_type(abs(ALL)) # N: Revealed type is 'builtins.int*'
25002500
[builtins fixtures/float.pyi]
25012501
[typing fixtures/typing-full.pyi]
2502+
2503+
[case testProtocolWithSlots]
2504+
from typing import Protocol
2505+
2506+
class A(Protocol):
2507+
__slots__ = ()
2508+
2509+
[builtins fixtures/tuple.pyi]
2510+
2511+
[case testNoneVsProtocol]
2512+
# mypy: strict-optional
2513+
from typing_extensions import Protocol
2514+
2515+
class MyHashable(Protocol):
2516+
def __hash__(self) -> int: ...
2517+
2518+
def f(h: MyHashable) -> None: pass
2519+
f(None)
2520+
2521+
class Proto(Protocol):
2522+
def __hash__(self) -> int: ...
2523+
def method(self) -> None: ...
2524+
2525+
def g(h: Proto) -> None: pass
2526+
g(None) # E: Argument 1 to "g" has incompatible type "None"; expected "Proto"
2527+
2528+
class Proto2(Protocol):
2529+
def hash(self) -> None: ...
2530+
2531+
def h(h: Proto2) -> None: pass
2532+
h(None) # E: Argument 1 to "h" has incompatible type "None"; expected "Proto2"
2533+
2534+
class EmptyProto(Protocol): ...
2535+
2536+
def hh(h: EmptyProto) -> None: pass
2537+
hh(None)
2538+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)
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