diff --git a/conformance/results/mypy/protocols_definition.toml b/conformance/results/mypy/protocols_definition.toml index 717b8cad5..e34a5fbba 100644 --- a/conformance/results/mypy/protocols_definition.toml +++ b/conformance/results/mypy/protocols_definition.toml @@ -51,6 +51,9 @@ protocols_definition.py:340: error: Incompatible types in assignment (expression protocols_definition.py:340: note: Protocol member Template6.val1 expected settable variable, got read-only attribute protocols_definition.py:341: error: Incompatible types in assignment (expression has type "Concrete6_Bad3", variable has type "Template6") [assignment] protocols_definition.py:341: note: Protocol member Template6.val1 expected settable variable, got read-only attribute +protocols_definition.py:369: error: Incompatible types in assignment (expression has type "Concrete7_Bad1", variable has type "Template7") [assignment] +protocols_definition.py:369: note: Protocol member Template7.val1 expected class variable, got instance variable +protocols_definition.py:370: error: Incompatible types in assignment (expression has type "Concrete7_Bad2", variable has type "Template7") [assignment] """ conformance_automated = "Fail" errors_diff = """ diff --git a/conformance/results/pycroscope/protocols_definition.toml b/conformance/results/pycroscope/protocols_definition.toml index 506df6a7a..d5e5f2dc7 100644 --- a/conformance/results/pycroscope/protocols_definition.toml +++ b/conformance/results/pycroscope/protocols_definition.toml @@ -1,5 +1,10 @@ -conformance_automated = "Pass" +conformance_automated = "Fail" +conformant = "Partial" +notes = """ +Incorrectly accepts an instance-only attribute as satisfying a `ClassVar` protocol member. +""" errors_diff = """ +Line 369: Expected 1 errors """ output = """ ./protocols_definition.py:30:10: Incompatible argument type for things: expected collections.abc.Iterable[./protocols_definition.py.SupportsClose] but got Literal[[1]] [incompatible_argument] @@ -23,4 +28,5 @@ output = """ ./protocols_definition.py:339:0: Incompatible assignment: expected ./protocols_definition.py.Template6, got ./protocols_definition.py.Concrete6_Bad1 [incompatible_assignment] ./protocols_definition.py:340:0: Incompatible assignment: expected ./protocols_definition.py.Template6, got ./protocols_definition.py.Concrete6_Bad2 [incompatible_assignment] ./protocols_definition.py:341:0: Incompatible assignment: expected ./protocols_definition.py.Template6, got ./protocols_definition.py.Concrete6_Bad3 [incompatible_assignment] +./protocols_definition.py:370:0: Incompatible assignment: expected ./protocols_definition.py.Template7, got ./protocols_definition.py.Concrete7_Bad2 [incompatible_assignment] """ diff --git a/conformance/results/pyrefly/protocols_definition.toml b/conformance/results/pyrefly/protocols_definition.toml index 766d78c3f..a02940d9b 100644 --- a/conformance/results/pyrefly/protocols_definition.toml +++ b/conformance/results/pyrefly/protocols_definition.toml @@ -24,4 +24,6 @@ ERROR protocols_definition.py:289:22-38: `Concrete5_Bad5` is not assignable to ` ERROR protocols_definition.py:339:22-38: `Concrete6_Bad1` is not assignable to `Template6` [bad-assignment] ERROR protocols_definition.py:340:22-38: `Concrete6_Bad2` is not assignable to `Template6` [bad-assignment] ERROR protocols_definition.py:341:22-38: `Concrete6_Bad3` is not assignable to `Template6` [bad-assignment] +ERROR protocols_definition.py:369:22-38: `Concrete7_Bad1` is not assignable to `Template7` [bad-assignment] +ERROR protocols_definition.py:370:22-38: `Concrete7_Bad2` is not assignable to `Template7` [bad-assignment] """ diff --git a/conformance/results/pyright/protocols_definition.toml b/conformance/results/pyright/protocols_definition.toml index b8252b8f7..2b983d502 100644 --- a/conformance/results/pyright/protocols_definition.toml +++ b/conformance/results/pyright/protocols_definition.toml @@ -97,6 +97,12 @@ protocols_definition.py:341:22 - error: Type "Concrete6_Bad3" is not assignable   "Concrete6_Bad3" is incompatible with protocol "Template6"     "val1" is writable in protocol     "val1" is not read-only in protocol (reportAssignmentType) +protocols_definition.py:369:22 - error: Type "Concrete7_Bad1" is not assignable to declared type "Template7" +  "Concrete7_Bad1" is incompatible with protocol "Template7" +    "val1" is defined as a ClassVar in protocol (reportAssignmentType) +protocols_definition.py:370:22 - error: Type "Concrete7_Bad2" is not assignable to declared type "Template7" +  "Concrete7_Bad2" is incompatible with protocol "Template7" +    "val1" is defined as a ClassVar in protocol (reportAssignmentType) """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/results.html b/conformance/results/results.html index 2a8c27f44..7c89516d1 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -1384,7 +1384,12 @@

Python Type System Conformance Test Results

  • Does not detect protocol mismatch if concrete method's parameters are position-only.
  • - Pass + + Partial + + Pass Pass Pass @@ -1536,7 +1541,7 @@

    Python Type System Conformance Test Results

    9.5 / 11 • 86.4% - 10 / 11 • 90.9% + 9.5 / 11 • 86.4% 10.5 / 11 • 95.5% 10.5 / 11 • 95.5% 6.5 / 11 • 59.1% @@ -2728,7 +2733,7 @@

    Python Type System Conformance Test Results

    108.5 / 145 • 74.8% - 128 / 145 • 88.3% + 127.5 / 145 • 87.9% 140.5 / 145 • 96.9% 135.5 / 145 • 93.4% 128 / 145 • 88.3% diff --git a/conformance/results/ty/protocols_definition.toml b/conformance/results/ty/protocols_definition.toml index 29e82bd3b..09ccdd19e 100644 --- a/conformance/results/ty/protocols_definition.toml +++ b/conformance/results/ty/protocols_definition.toml @@ -23,4 +23,6 @@ protocols_definition.py:289:22: error[invalid-assignment] Object of type `Concre protocols_definition.py:339:22: error[invalid-assignment] Object of type `Concrete6_Bad1` is not assignable to `Template6` protocols_definition.py:340:22: error[invalid-assignment] Object of type `Concrete6_Bad2` is not assignable to `Template6` protocols_definition.py:341:22: error[invalid-assignment] Object of type `Concrete6_Bad3` is not assignable to `Template6` +protocols_definition.py:369:22: error[invalid-assignment] Object of type `Concrete7_Bad1` is not assignable to `Template7` +protocols_definition.py:370:22: error[invalid-assignment] Object of type `Concrete7_Bad2` is not assignable to `Template7` """ diff --git a/conformance/results/zuban/protocols_definition.toml b/conformance/results/zuban/protocols_definition.toml index a0316e0ea..26d390b47 100644 --- a/conformance/results/zuban/protocols_definition.toml +++ b/conformance/results/zuban/protocols_definition.toml @@ -67,4 +67,7 @@ protocols_definition.py:340: error: Incompatible types in assignment (expression protocols_definition.py:340: note: Protocol member Template6.val1 expected settable variable, got read-only attribute protocols_definition.py:341: error: Incompatible types in assignment (expression has type "Concrete6_Bad3", variable has type "Template6") [assignment] protocols_definition.py:341: note: Protocol member Template6.val1 expected settable variable, got read-only attribute +protocols_definition.py:369: error: Incompatible types in assignment (expression has type "Concrete7_Bad1", variable has type "Template7") [assignment] +protocols_definition.py:369: note: Protocol member Template7.val1 expected class variable, got instance variable +protocols_definition.py:370: error: Incompatible types in assignment (expression has type "Concrete7_Bad2", variable has type "Template7") [assignment] """ diff --git a/conformance/tests/protocols_class_objects.py b/conformance/tests/protocols_class_objects.py index 79de51204..2a498438b 100644 --- a/conformance/tests/protocols_class_objects.py +++ b/conformance/tests/protocols_class_objects.py @@ -105,5 +105,5 @@ class ConcreteC3(metaclass=CMeta): pc2: ProtoC2 = ConcreteC1 # OK pc3: ProtoC1 = ConcreteC2 # E pc4: ProtoC2 = ConcreteC2 # E -pc5: ProtoC1 = ConcreteC3 # E +pc5: ProtoC1 = ConcreteC3 # E?: Explicit ClassVar matching is unspecified pc6: ProtoC2 = ConcreteC3 # OK diff --git a/conformance/tests/protocols_definition.py b/conformance/tests/protocols_definition.py index bf046ee8c..7252dfc16 100644 --- a/conformance/tests/protocols_definition.py +++ b/conformance/tests/protocols_definition.py @@ -114,7 +114,7 @@ class Concrete2_Bad4: v2_bad1: Template2 = Concrete2_Bad1() # E v2_bad2: Template2 = Concrete2_Bad2() # E v2_bad3: Template2 = Concrete2_Bad3() # E -v2_bad4: Template2 = Concrete2_Bad4() # E +v2_bad4: Template2 = Concrete2_Bad4() # E?: Explicit ClassVar matching is unspecified class Template3(Protocol): @@ -339,3 +339,32 @@ class Concrete6_Bad3: v6_bad1: Template6 = Concrete6_Bad1() # E v6_bad2: Template6 = Concrete6_Bad2() # E: named tuple is immutable v6_bad3: Template6 = Concrete6_Bad3() # E: dataclass is frozen + + +# The specification leaves two possible interpretations of a ClassVar protocol +# member. One interpretation requires the implementing attribute to be explicitly +# declared with ClassVar. The other interpretation imposes only structural +# requirements: the attribute must be readable and writable on the class object +# and readable on instances of the class. Both interpretations therefore require +# the following assignments to be rejected. + + +class Template7(Protocol): + val1: ClassVar[int] + + +class Concrete7_Bad1: + def __init__(self) -> None: + self.val1: int = 42 + + +class Concrete7Meta(type): + val1: int = 42 + + +class Concrete7_Bad2(metaclass=Concrete7Meta): + pass + + +v7_bad1: Template7 = Concrete7_Bad1() # E: val1 is not readable on the class object +v7_bad2: Template7 = Concrete7_Bad2() # E: val1 is not readable on instances