Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions conformance/results/mypy/dataclasses_hash.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
conformant = "Partial"
conformant = "Unsupported"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me that mypy has implemented support for any of the functionality tested in dataclasses_hash.py, so I downgraded its score from "Partial" to "Unsupported". I'm very happy to revert this change if anybody feels this is unfair or if I've missed something!

notes = """
Does not synthesize `__hash__ = None` as a class attribute for unhashable dataclasses.
Does not report when an unhashable dataclass has `__hash__` called directly on an instance.
Does not report when dataclass is not compatible with Hashable protocol.
"""
output = """
dataclasses_hash.py:14: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]
dataclasses_hash.py:29: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]
dataclasses_hash.py:40: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]
dataclasses_hash.py:55: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]
dataclasses_hash.py:69: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]
dataclasses_hash.py:85: error: Expression is of type "Callable[[DC6], int]", not "None" [assert-type]
dataclasses_hash.py:102: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]
"""
conformance_automated = "Fail"
errors_diff = """
Line 15: Expected 1 errors
Line 32: Expected 1 errors
Line 17: Expected 1 errors
Line 18: Expected 1 errors
Line 43: Expected 1 errors
Line 44: Expected 1 errors
Line 14: Unexpected errors ['dataclasses_hash.py:14: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]']
Line 40: Unexpected errors ['dataclasses_hash.py:40: error: Expression is of type "Callable[[object], int]", not "None" [assert-type]']
"""
11 changes: 9 additions & 2 deletions conformance/results/pyrefly/dataclasses_hash.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ conformance_automated = "Pass"
errors_diff = """
"""
output = """
ERROR dataclasses_hash.py:15:16-22: `DC1` is not assignable to `Hashable` [bad-assignment]
ERROR dataclasses_hash.py:32:16-22: `DC3` is not assignable to `Hashable` [bad-assignment]
ERROR dataclasses_hash.py:17:1-16: Expected a callable, got `None` [not-callable]
ERROR dataclasses_hash.py:18:16-22: `DC1` is not assignable to `Hashable` [bad-assignment]
ERROR dataclasses_hash.py:29:12-32: assert_type((self: DC2) -> int, None) failed [assert-type]
ERROR dataclasses_hash.py:43:1-16: Expected a callable, got `None` [not-callable]
ERROR dataclasses_hash.py:44:16-22: `DC3` is not assignable to `Hashable` [bad-assignment]
ERROR dataclasses_hash.py:55:12-32: assert_type((self: DC4) -> int, None) failed [assert-type]
ERROR dataclasses_hash.py:69:12-32: assert_type((self: DC5) -> int, None) failed [assert-type]
ERROR dataclasses_hash.py:85:12-32: assert_type((self: DC6) -> int, None) failed [assert-type]
ERROR dataclasses_hash.py:102:12-32: assert_type((self: DC7) -> int, None) failed [assert-type]
"""
11 changes: 9 additions & 2 deletions conformance/results/pyright/dataclasses_hash.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
conformant = "Pass"
output = """
dataclasses_hash.py:15:16 - error: Type "DC1" is not assignable to declared type "Hashable"
dataclasses_hash.py:17:1 - error: Object of type "None" cannot be called (reportOptionalCall)
dataclasses_hash.py:18:16 - error: Type "DC1" is not assignable to declared type "Hashable"
  "DC1" is incompatible with protocol "Hashable"
    "__hash__" is an incompatible type
      Type "None" is not assignable to type "() -> int" (reportAssignmentType)
dataclasses_hash.py:32:16 - error: Type "DC3" is not assignable to declared type "Hashable"
dataclasses_hash.py:29:13 - error: "assert_type" mismatch: expected "None" but received "(self: DC2) -> int" (reportAssertTypeFailure)
dataclasses_hash.py:43:1 - error: Object of type "None" cannot be called (reportOptionalCall)
dataclasses_hash.py:44:16 - error: Type "DC3" is not assignable to declared type "Hashable"
  "DC3" is incompatible with protocol "Hashable"
    "__hash__" is an incompatible type
      Type "None" is not assignable to type "() -> int" (reportAssignmentType)
dataclasses_hash.py:55:13 - error: "assert_type" mismatch: expected "None" but received "(self: DC4) -> int" (reportAssertTypeFailure)
dataclasses_hash.py:69:13 - error: "assert_type" mismatch: expected "None" but received "(self: DC5) -> int" (reportAssertTypeFailure)
dataclasses_hash.py:85:13 - error: "assert_type" mismatch: expected "None" but received "(self: DC6) -> int" (reportAssertTypeFailure)
dataclasses_hash.py:102:13 - error: "assert_type" mismatch: expected "None" but received "(self: DC7) -> int" (reportAssertTypeFailure)
"""
conformance_automated = "Pass"
errors_diff = """
Expand Down
4 changes: 2 additions & 2 deletions conformance/results/results.html
Original file line number Diff line number Diff line change
Expand Up @@ -737,9 +737,9 @@ <h3>Python Type System Conformance Test Results</h3>
<th class="column col2 conformant">Pass</th>
</tr>
<tr><th class="column col1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataclasses_hash</th>
<th class="column col2 partially-conformant"><div class="hover-text">Partial<span class="tooltip-text" id="bottom"><p>Does not report when dataclass is not compatible with Hashable protocol.</p></span></div></th>
<th class="column col2 conformant">Pass</th>
<th class="column col2 not-conformant"><div class="hover-text">Unsupported<span class="tooltip-text" id="bottom"><p>Does not synthesize `__hash__ = None` as a class attribute for unhashable dataclasses.</p><p>Does not report when an unhashable dataclass has `__hash__` called directly on an instance.</p><p>Does not report when dataclass is not compatible with Hashable protocol.</p></span></div></th>
<th class="column col2 conformant">Pass</th>
<th class="column col2 partially-conformant"><div class="hover-text">Partial<span class="tooltip-text" id="bottom"><p>Does not synthesize a `__hash__ = None` class attribute for unhashable dataclasses.</p></span></div></th>
<th class="column col2 conformant">Pass</th>
</tr>
<tr><th class="column col1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataclasses_inheritance</th>
Expand Down
21 changes: 18 additions & 3 deletions conformance/results/zuban/dataclasses_hash.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
conformance_automated = "Pass"
conformance_automated = "Fail"
conformant = "Partial"
notes = """
Does not synthesize a `__hash__ = None` class attribute for unhashable dataclasses.
"""
errors_diff = """
Line 14: Unexpected errors ['dataclasses_hash.py:14: error: Expression is of type "Callable[[object], int]", not "None" [misc]']
Line 40: Unexpected errors ['dataclasses_hash.py:40: error: Expression is of type "Callable[[object], int]", not "None" [misc]']
"""
output = """
dataclasses_hash.py:15: error: Incompatible types in assignment (expression has type "DC1", variable has type "Hashable") [assignment]
dataclasses_hash.py:32: error: Incompatible types in assignment (expression has type "DC3", variable has type "Hashable") [assignment]
dataclasses_hash.py:14: error: Expression is of type "Callable[[object], int]", not "None" [misc]
dataclasses_hash.py:17: error: "DC1" has no attribute "__hash__" [attr-defined]
dataclasses_hash.py:18: error: Incompatible types in assignment (expression has type "DC1", variable has type "Hashable") [assignment]
dataclasses_hash.py:29: error: Expression is of type "Callable[[object], int]", not "None" [misc]
dataclasses_hash.py:40: error: Expression is of type "Callable[[object], int]", not "None" [misc]
dataclasses_hash.py:43: error: "DC3" has no attribute "__hash__" [attr-defined]
dataclasses_hash.py:44: error: Incompatible types in assignment (expression has type "DC3", variable has type "Hashable") [assignment]
dataclasses_hash.py:55: error: Expression is of type "Callable[[object], int]", not "None" [misc]
dataclasses_hash.py:69: error: Expression is of type "Callable[[object], int]", not "None" [misc]
dataclasses_hash.py:85: error: Expression is of type "Callable[[DC6], int]", not "None" [misc]
dataclasses_hash.py:102: error: Expression is of type "Callable[[object], int]", not "None" [misc]
"""
51 changes: 43 additions & 8 deletions conformance/tests/dataclasses_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
"""

from dataclasses import dataclass
from typing import Hashable
from typing import Hashable, assert_type


@dataclass
class DC1:
a: int


# This should generate an error because DC1 isn't hashable.
assert_type(DC1.__hash__, None)

# These should generate errors because DC1 isn't hashable.
DC1(0).__hash__() # E
v1: Hashable = DC1(0) # E


Expand All @@ -20,15 +23,24 @@ class DC2:
a: int


v2: Hashable = DC2(0)
# Because `DC2` is frozen, type checkers should synthesize
# a callable `__hash__` method for it, and therefore should
# emit a diagnostic here:
assert_type(DC2.__hash__, None) # E

DC2(0).__hash__() # OK
v2: Hashable = DC2(0) # OK


@dataclass(eq=True)
class DC3:
a: int


# This should generate an error because DC3 isn't hashable.
assert_type(DC3.__hash__, None)

# These should generate errors because DC3 isn't hashable.
DC3(0).__hash__() # E
v3: Hashable = DC3(0) # E


Expand All @@ -37,15 +49,27 @@ class DC4:
a: int


v4: Hashable = DC4(0)
# Because `DC4` is frozen, type checkers should synthesize
# a callable `__hash__` method for it, and therefore should
# emit a diagnostic here:
assert_type(DC4.__hash__, None) # E

DC4(0).__hash__() # OK
v4: Hashable = DC4(0) # OK


@dataclass(eq=True, unsafe_hash=True)
class DC5:
a: int


v5: Hashable = DC5(0)
# Type checkers should synthesize a callable `__hash__`
# method for `DC5` due to `unsafe_hash=True`, and therefore
# should emit a diagnostic here:
assert_type(DC5.__hash__, None) # E

DC5(0).__hash__() # OK
v5: Hashable = DC5(0) # OK


@dataclass(eq=True)
Expand All @@ -56,7 +80,12 @@ def __hash__(self) -> int:
return 0


v6: Hashable = DC6(0)
# Type checkers should respect the manually defined `__hash__`
# method for `DC6`, and therefore should emit a diagnostic here:
assert_type(DC6.__hash__, None) # E

DC6(0).__hash__() # OK
v6: Hashable = DC6(0) # OK


@dataclass(frozen=True)
Expand All @@ -67,4 +96,10 @@ def __eq__(self, other) -> bool:
return self.a == other.a


v7: Hashable = DC7(0)
# Because `DC7` is frozen, type checkers should synthesize
# a callable `__hash__` method for it, and therefore should
# emit a diagnostic here:
assert_type(DC7.__hash__, None) # E

DC7(0).__hash__() # OK
v7: Hashable = DC7(0) # OK