Skip to content

Commit 1a25e14

Browse files
committed
[ty] Understand classes that inherited from subscripted Protocol[] as generic
1 parent 5a91bad commit 1a25e14

File tree

26 files changed

+316
-131
lines changed

26 files changed

+316
-131
lines changed

crates/ty_python_semantic/resources/mdtest/annotations/invalid.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ async def outer(): # avoid unrelated syntax errors on yield, yield from, and aw
9999
def _(
100100
a: {1: 2}, # error: [invalid-type-form] "Dict literals are not allowed in type expressions"
101101
b: {1, 2}, # error: [invalid-type-form] "Set literals are not allowed in type expressions"
102+
# TODO: the `[not-iterable]` error here is a false positive
103+
# error: [not-iterable] "Object of type `_T` is not iterable"
102104
c: {k: v for k, v in [(1, 2)]}, # error: [invalid-type-form] "Dict comprehensions are not allowed in type expressions"
103105
d: [k for k in [1, 2]], # error: [invalid-type-form] "List comprehensions are not allowed in type expressions"
104106
e: {k for k in [1, 2]}, # error: [invalid-type-form] "Set comprehensions are not allowed in type expressions"

crates/ty_python_semantic/resources/mdtest/annotations/starred.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Ts = TypeVarTuple("Ts")
1414

1515
def append_int(*args: *Ts) -> tuple[*Ts, int]:
1616
# TODO: tuple[*Ts]
17-
reveal_type(args) # revealed: tuple
17+
reveal_type(args) # revealed: tuple[Unknown, ...]
1818

1919
return (*args, 1)
2020

crates/ty_python_semantic/resources/mdtest/annotations/stdlib_typing_aliases.md

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,17 @@ def f(
3030
ordered_dict_bare: typing.OrderedDict,
3131
ordered_dict_parametrized: typing.OrderedDict[int, str],
3232
):
33-
# TODO: revealed: list[Unknown]
34-
reveal_type(list_bare) # revealed: list
33+
reveal_type(list_bare) # revealed: list[Unknown]
3534
# TODO: revealed: list[int]
36-
reveal_type(list_parametrized) # revealed: list
35+
reveal_type(list_parametrized) # revealed: list[Unknown]
3736

3837
reveal_type(dict_bare) # revealed: dict[Unknown, Unknown]
3938
# TODO: revealed: dict[int, str]
4039
reveal_type(dict_parametrized) # revealed: dict[Unknown, Unknown]
4140

42-
# TODO: revealed: set[Unknown]
43-
reveal_type(set_bare) # revealed: set
41+
reveal_type(set_bare) # revealed: set[Unknown]
4442
# TODO: revealed: set[int]
45-
reveal_type(set_parametrized) # revealed: set
43+
reveal_type(set_parametrized) # revealed: set[Unknown]
4644

4745
# TODO: revealed: frozenset[Unknown]
4846
reveal_type(frozen_set_bare) # revealed: frozenset
@@ -61,10 +59,9 @@ def f(
6159
# TODO: revealed: defaultdict[str, int]
6260
reveal_type(default_dict_parametrized) # revealed: defaultdict[Unknown, Unknown]
6361

64-
# TODO: revealed: deque[Unknown]
65-
reveal_type(deque_bare) # revealed: deque
62+
reveal_type(deque_bare) # revealed: deque[Unknown]
6663
# TODO: revealed: deque[str]
67-
reveal_type(deque_parametrized) # revealed: deque
64+
reveal_type(deque_parametrized) # revealed: deque[Unknown]
6865

6966
reveal_type(ordered_dict_bare) # revealed: OrderedDict[Unknown, Unknown]
7067
# TODO: revealed: OrderedDict[int, str]
@@ -84,20 +81,18 @@ import typing
8481

8582
class ListSubclass(typing.List): ...
8683

87-
# TODO: generic protocols
88-
# revealed: tuple[Literal[ListSubclass], Literal[list], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
84+
# revealed: tuple[Literal[ListSubclass], Literal[list[Unknown]], Literal[MutableSequence[_T]], Literal[Sequence[_T]], Literal[Reversible[_T_co]], Literal[Collection[_T_co]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], Literal[object]]
8985
reveal_type(ListSubclass.__mro__)
9086

9187
class DictSubclass(typing.Dict): ...
9288

93-
# TODO: generic protocols
94-
# revealed: tuple[Literal[DictSubclass], Literal[dict[Unknown, Unknown]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
89+
# TODO: should not have `Generic` multiple times
90+
# revealed: tuple[Literal[DictSubclass], Literal[dict[Unknown, Unknown]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection[_KT]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], Literal[object]]
9591
reveal_type(DictSubclass.__mro__)
9692

9793
class SetSubclass(typing.Set): ...
9894

99-
# TODO: generic protocols
100-
# revealed: tuple[Literal[SetSubclass], Literal[set], Literal[MutableSet], Literal[AbstractSet], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
95+
# revealed: tuple[Literal[SetSubclass], Literal[set[Unknown]], Literal[MutableSet[_T]], Literal[AbstractSet[_T]], Literal[Collection[_T_co]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], Literal[object]]
10196
reveal_type(SetSubclass.__mro__)
10297

10398
class FrozenSetSubclass(typing.FrozenSet): ...
@@ -112,31 +107,30 @@ reveal_type(FrozenSetSubclass.__mro__)
112107

113108
class ChainMapSubclass(typing.ChainMap): ...
114109

115-
# TODO: generic protocols
116-
# revealed: tuple[Literal[ChainMapSubclass], Literal[ChainMap[Unknown, Unknown]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
110+
# TODO: should not have `Generic` multiple times
111+
# revealed: tuple[Literal[ChainMapSubclass], Literal[ChainMap[Unknown, Unknown]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection[_KT]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], Literal[object]]
117112
reveal_type(ChainMapSubclass.__mro__)
118113

119114
class CounterSubclass(typing.Counter): ...
120115

121-
# TODO: Should be (CounterSubclass, Counter, dict, MutableMapping, Mapping, Collection, Sized, Iterable, Container, Generic, object)
122-
# revealed: tuple[Literal[CounterSubclass], Literal[Counter[Unknown]], Literal[dict[_T, int]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], typing.Generic[_T], Literal[object]]
116+
# TODO: Should not have `Generic` multiple times
117+
# revealed: tuple[Literal[CounterSubclass], Literal[Counter[Unknown]], Literal[dict[_T, int]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection[_KT]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], typing.Generic[_T], Literal[object]]
123118
reveal_type(CounterSubclass.__mro__)
124119

125120
class DefaultDictSubclass(typing.DefaultDict): ...
126121

127-
# TODO: Should be (DefaultDictSubclass, defaultdict, dict, MutableMapping, Mapping, Collection, Sized, Iterable, Container, Generic, object)
128-
# revealed: tuple[Literal[DefaultDictSubclass], Literal[defaultdict[Unknown, Unknown]], Literal[dict[_KT, _VT]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
122+
# TODO: Should not have `Generic` multiple times
123+
# revealed: tuple[Literal[DefaultDictSubclass], Literal[defaultdict[Unknown, Unknown]], Literal[dict[_KT, _VT]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection[_KT]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], Literal[object]]
129124
reveal_type(DefaultDictSubclass.__mro__)
130125

131126
class DequeSubclass(typing.Deque): ...
132127

133-
# TODO: generic protocols
134-
# revealed: tuple[Literal[DequeSubclass], Literal[deque], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
128+
# revealed: tuple[Literal[DequeSubclass], Literal[deque[Unknown]], Literal[MutableSequence[_T]], Literal[Sequence[_T]], Literal[Reversible[_T_co]], Literal[Collection[_T_co]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], Literal[object]]
135129
reveal_type(DequeSubclass.__mro__)
136130

137131
class OrderedDictSubclass(typing.OrderedDict): ...
138132

139-
# TODO: Should be (OrderedDictSubclass, OrderedDict, dict, MutableMapping, Mapping, Collection, Sized, Iterable, Container, Generic, object)
140-
# revealed: tuple[Literal[OrderedDictSubclass], Literal[OrderedDict[Unknown, Unknown]], Literal[dict[_KT, _VT]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
133+
# TODO: Should not have multiple `Generic` bases
134+
# revealed: tuple[Literal[OrderedDictSubclass], Literal[OrderedDict[Unknown, Unknown]], Literal[dict[_KT, _VT]], Literal[MutableMapping[_KT, _VT]], Literal[Mapping[_KT, _VT]], Literal[Collection[_KT]], Literal[Iterable[_T_co]], Literal[Container[_T_co]], typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], Literal[object]]
141135
reveal_type(OrderedDictSubclass.__mro__)
142136
```

crates/ty_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ Alias: TypeAlias = int
1616

1717
def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]:
1818
# TODO: should understand the annotation
19-
reveal_type(args) # revealed: tuple
19+
reveal_type(args) # revealed: tuple[Unknown, ...]
2020

2121
reveal_type(Alias) # revealed: @Todo(Support for `typing.TypeAlias`)
2222

2323
def g() -> TypeGuard[int]: ...
2424
def h() -> TypeIs[int]: ...
2525
def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.kwargs) -> R_co:
2626
# TODO: should understand the annotation
27-
reveal_type(args) # revealed: tuple
27+
reveal_type(args) # revealed: tuple[Unknown, ...]
2828
reveal_type(kwargs) # revealed: dict[str, @Todo(Support for `typing.ParamSpec`)]
2929
return callback(42, *args, **kwargs)
3030

crates/ty_python_semantic/resources/mdtest/assignment/annotations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ reveal_type(d) # revealed: tuple[tuple[str, str], tuple[int, int]]
6161
reveal_type(e) # revealed: @Todo(full tuple[...] support)
6262
reveal_type(f) # revealed: @Todo(full tuple[...] support)
6363
reveal_type(g) # revealed: @Todo(full tuple[...] support)
64-
reveal_type(h) # revealed: tuple[@Todo(specialized non-generic class), @Todo(specialized non-generic class)]
64+
reveal_type(h) # revealed: tuple[list[int], list[int]]
6565

6666
reveal_type(i) # revealed: tuple[str | int, str | int]
6767
reveal_type(j) # revealed: tuple[str | int]
@@ -76,7 +76,7 @@ a: tuple[()] = (1, 2)
7676
# error: [invalid-assignment] "Object of type `tuple[Literal["foo"]]` is not assignable to `tuple[int]`"
7777
b: tuple[int] = ("foo",)
7878

79-
# error: [invalid-assignment] "Object of type `tuple[list, Literal["foo"]]` is not assignable to `tuple[str | int, str]`"
79+
# error: [invalid-assignment] "Object of type `tuple[list[Unknown], Literal["foo"]]` is not assignable to `tuple[str | int, str]`"
8080
c: tuple[str | int, str] = ([], "foo")
8181
```
8282

crates/ty_python_semantic/resources/mdtest/attributes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,7 @@ reveal_type(False.real) # revealed: Literal[0]
17281728
All attribute access on literal `bytes` types is currently delegated to `builtins.bytes`:
17291729

17301730
```py
1731-
# revealed: bound method Literal[b"foo"].join(iterable_of_bytes: @Todo(specialized non-generic class), /) -> bytes
1731+
# revealed: bound method Literal[b"foo"].join(iterable_of_bytes: Iterable[@Todo(Support for `typing.TypeAlias`)], /) -> bytes
17321732
reveal_type(b"foo".join)
17331733
# revealed: bound method Literal[b"foo"].endswith(suffix: @Todo(Support for `typing.TypeAlias`), start: SupportsIndex | None = ellipsis, end: SupportsIndex | None = ellipsis, /) -> bool
17341734
reveal_type(b"foo".endswith)

crates/ty_python_semantic/resources/mdtest/expression/lambda.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ lambda x=1: reveal_type(x) # revealed: Unknown | Literal[1]
7979
Using a variadic parameter:
8080

8181
```py
82-
# TODO: should be `tuple[Unknown, ...]` (needs generics)
83-
lambda *args: reveal_type(args) # revealed: tuple
82+
lambda *args: reveal_type(args) # revealed: tuple[Unknown, ...]
8483
```
8584

8685
Using a keyword-variadic parameter:

crates/ty_python_semantic/resources/mdtest/function/parameters.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ def f(a, b: int, c=1, d: int = 2, /, e=3, f: Literal[4] = 4, *args: object, g=5,
2525
reveal_type(f) # revealed: Literal[4]
2626
reveal_type(g) # revealed: Unknown | Literal[5]
2727
reveal_type(h) # revealed: Literal[6]
28-
# TODO: should be `tuple[object, ...]` (needs generics)
29-
reveal_type(args) # revealed: tuple
28+
# TODO: should be `tuple[object, ...]`
29+
reveal_type(args) # revealed: tuple[Unknown, ...]
3030
reveal_type(kwargs) # revealed: dict[str, str]
3131
```
3232

@@ -36,8 +36,7 @@ def f(a, b: int, c=1, d: int = 2, /, e=3, f: Literal[4] = 4, *args: object, g=5,
3636

3737
```py
3838
def g(*args, **kwargs):
39-
# TODO: should be `tuple[Unknown, ...]` (needs generics)
40-
reveal_type(args) # revealed: tuple
39+
reveal_type(args) # revealed: tuple[Unknown, ...]
4140
reveal_type(kwargs) # revealed: dict[str, Unknown]
4241
```
4342

crates/ty_python_semantic/resources/mdtest/generics/legacy/variables.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ T = TypeVar("T")
3838
U: TypeVar = TypeVar("U")
3939

4040
# error: [invalid-legacy-type-variable] "A legacy `typing.TypeVar` must be immediately assigned to a variable"
41+
# error: [invalid-type-form] "Function calls are not allowed in type expressions"
4142
TestList = list[TypeVar("W")]
4243
```
4344

crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ from typing import Generic, TypeVar
6565

6666
T = TypeVar("T")
6767

68-
# error: [invalid-generic-class] "Cannot both inherit from `Generic` and use PEP 695 type variables"
68+
# error: [invalid-generic-class] "Cannot both inherit from `typing.Generic` and use PEP 695 type variables"
6969
class BothGenericSyntaxes[U](Generic[T]): ...
7070
```
7171

0 commit comments

Comments
 (0)