-
Notifications
You must be signed in to change notification settings - Fork 243
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Conformance tests and spec change for generic type erasure (#1589)
- Loading branch information
1 parent
ebb1a42
commit 8279fa6
Showing
6 changed files
with
106 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
conformant = "Partial" | ||
notes = """ | ||
Infers Node[Never] instead of Node[Any] when argument is not provided. | ||
False negative on instance attribute access on type(node). | ||
""" | ||
output = """ | ||
generics_type_erasure.py:17: error: Expression is of type "Node[Never]", not "Node[Any]" [assert-type] | ||
generics_type_erasure.py:20: error: Expression is of type Never, not "Any" [assert-type] | ||
generics_type_erasure.py:36: error: Argument 1 to "Node" has incompatible type "str"; expected "int | None" [arg-type] | ||
generics_type_erasure.py:38: error: Argument 1 to "Node" has incompatible type "int"; expected "str | None" [arg-type] | ||
generics_type_erasure.py:40: error: Access to generic instance variables via class is ambiguous [misc] | ||
generics_type_erasure.py:41: error: Access to generic instance variables via class is ambiguous [misc] | ||
generics_type_erasure.py:42: error: Access to generic instance variables via class is ambiguous [misc] | ||
generics_type_erasure.py:43: error: Access to generic instance variables via class is ambiguous [misc] | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
conformant = "Partial" | ||
notes = """ | ||
Doesn't allow using Node[Any] in assert_type expression. | ||
False negatives on instance attribute access on the type. | ||
""" | ||
output = """ | ||
generics_type_erasure.py:11:0 Uninitialized attribute [13]: Attribute `label` is declared in class `Node` to have type `Variable[T]` but is never initialized. | ||
generics_type_erasure.py:17:25 Incompatible parameter type [6]: In call `typing.GenericMeta.__getitem__`, for 1st positional argument, expected `Type[Variable[T]]` but got `object`. | ||
generics_type_erasure.py:36:15 Incompatible parameter type [6]: In call `Node.__init__`, for 1st positional argument, expected `Optional[int]` but got `str`. | ||
generics_type_erasure.py:38:15 Incompatible parameter type [6]: In call `Node.__init__`, for 1st positional argument, expected `Optional[str]` but got `int`. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
conformant = "Partial" | ||
notes = """ | ||
False negatives on instance attribute access on the type. | ||
""" | ||
output = """ | ||
generics_type_erasure.py:36:16 - error: Argument of type "Literal['']" cannot be assigned to parameter "label" of type "int | None" in function "__init__" | ||
Type "Literal['']" cannot be assigned to type "int | None" | ||
"Literal['']" is incompatible with "int" | ||
"Literal['']" is incompatible with "None" (reportGeneralTypeIssues) | ||
generics_type_erasure.py:38:16 - error: Argument of type "Literal[0]" cannot be assigned to parameter "label" of type "str | None" in function "__init__" | ||
Type "Literal[0]" cannot be assigned to type "str | None" | ||
"Literal[0]" is incompatible with "str" | ||
"Literal[0]" is incompatible with "None" (reportGeneralTypeIssues) | ||
generics_type_erasure.py:42:6 - error: Cannot assign member "label" for type "type[Node[T@Node]]" | ||
Expression of type "Literal[1]" cannot be assigned to member "label" of class "Node[T@Node]" | ||
Member "__set__" is unknown | ||
Type "Literal[1]" cannot be assigned to type "T@Node" (reportGeneralTypeIssues) | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
conformant = "Unsupported" | ||
output = """ | ||
NotImplementedError: ParameterizedClass | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#instantiating-generic-classes-and-type-erasure | ||
|
||
from typing import Any, TypeVar, Generic, assert_type | ||
|
||
T = TypeVar("T") | ||
|
||
# > If the constructor (__init__ or __new__) uses T in its signature, and a | ||
# > corresponding argument value is passed, the type of the corresponding | ||
# > argument(s) is substituted. Otherwise, Any is assumed. | ||
|
||
class Node(Generic[T]): | ||
label: T | ||
def __init__(self, label: T | None = None) -> None: ... | ||
|
||
assert_type(Node(''), Node[str]) | ||
assert_type(Node(0), Node[int]) | ||
assert_type(Node(), Node[Any]) | ||
|
||
assert_type(Node(0).label, int) | ||
assert_type(Node().label, Any) | ||
|
||
# > In case the inferred type uses [Any] but the intended type is more specific, | ||
# > you can use an annotation to force the type of the variable, e.g.: | ||
|
||
n1: Node[int] = Node() | ||
assert_type(n1, Node[int]) | ||
n2: Node[str] = Node() | ||
assert_type(n2, Node[str]) | ||
|
||
n3 = Node[int]() | ||
assert_type(n3, Node[int]) | ||
n4 = Node[str]() | ||
assert_type(n4, Node[str]) | ||
|
||
n5 = Node[int](0) # OK | ||
n6 = Node[int]("") # Type error | ||
n7 = Node[str]("") # OK | ||
n8 = Node[str](0) # Type error | ||
|
||
Node[int].label = 1 # Type error | ||
Node[int].label # Type error | ||
Node.label = 1 # Type error | ||
Node.label # Type error | ||
type(n1).label # Type error | ||
assert_type(n1.label, int) | ||
assert_type(Node[int]().label, int) | ||
n1.label = 1 # OK | ||
|
||
# > [...] generic versions of concrete collections can be instantiated: | ||
|
||
from typing import DefaultDict | ||
|
||
data = DefaultDict[int, bytes]() | ||
assert_type(data[0], bytes) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters