Skip to content

Commit 7ae011c

Browse files
committed
Merge branch 'main' into dcreager/module-resolution
* main: [red-knot] Use `type[Unknown]` rather than `Unknown` as the fallback metaclass for invalid classes (#14961) [red-knot] Make `is_subtype_of` exhaustive (#14924) [red-knot] Alphabetize rules (#14960) [red-knot] Understand `Annotated` (#14950)
2 parents d707e9f + 90a5439 commit 7ae011c

File tree

11 files changed

+671
-415
lines changed

11 files changed

+671
-415
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# `Annotated`
2+
3+
`Annotated` attaches arbitrary metadata to a given type.
4+
5+
## Usages
6+
7+
`Annotated[T, ...]` is equivalent to `T`: All metadata arguments are simply ignored.
8+
9+
```py
10+
from typing_extensions import Annotated
11+
12+
def _(x: Annotated[int, "foo"]):
13+
reveal_type(x) # revealed: int
14+
15+
def _(x: Annotated[int, lambda: 0 + 1 * 2 // 3, _(4)]):
16+
reveal_type(x) # revealed: int
17+
18+
def _(x: Annotated[int, "arbitrary", "metadata", "elements", "are", "fine"]):
19+
reveal_type(x) # revealed: int
20+
21+
def _(x: Annotated[tuple[str, int], bytes]):
22+
reveal_type(x) # revealed: tuple[str, int]
23+
```
24+
25+
## Parameterization
26+
27+
It is invalid to parameterize `Annotated` with less than two arguments.
28+
29+
```py
30+
from typing_extensions import Annotated
31+
32+
# TODO: This should be an error
33+
def _(x: Annotated):
34+
reveal_type(x) # revealed: Unknown
35+
36+
# error: [invalid-type-form]
37+
def _(x: Annotated[()]):
38+
reveal_type(x) # revealed: Unknown
39+
40+
# error: [invalid-type-form]
41+
def _(x: Annotated[int]):
42+
# `Annotated[T]` is invalid and will raise an error at runtime,
43+
# but we treat it the same as `T` to provide better diagnostics later on.
44+
# The subscription itself is still reported, regardless.
45+
# Same for the `(int,)` form below.
46+
reveal_type(x) # revealed: int
47+
48+
# error: [invalid-type-form]
49+
def _(x: Annotated[(int,)]):
50+
reveal_type(x) # revealed: int
51+
```
52+
53+
## Inheritance
54+
55+
### Correctly parameterized
56+
57+
Inheriting from `Annotated[T, ...]` is equivalent to inheriting from `T` itself.
58+
59+
```py
60+
from typing_extensions import Annotated
61+
62+
# TODO: False positive
63+
# error: [invalid-base]
64+
class C(Annotated[int, "foo"]): ...
65+
66+
# TODO: Should be `tuple[Literal[C], Literal[int], Literal[object]]`
67+
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Unknown, Literal[object]]
68+
```
69+
70+
### Not parameterized
71+
72+
```py
73+
from typing_extensions import Annotated
74+
75+
# At runtime, this is an error.
76+
# error: [invalid-base]
77+
class C(Annotated): ...
78+
79+
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Unknown, Literal[object]]
80+
```

crates/red_knot_python_semantic/resources/mdtest/annotations/any.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def _(s: Subclass):
7777
```py
7878
from typing import Any
7979

80-
# error: [invalid-type-parameter] "Type `typing.Any` expected no type parameter"
80+
# error: [invalid-type-form] "Type `typing.Any` expected no type parameter"
8181
def f(x: Any[int]):
8282
reveal_type(x) # revealed: Unknown
8383
```

crates/red_knot_python_semantic/resources/mdtest/annotations/literal_string.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,19 @@ def f():
2727
```py
2828
from typing_extensions import Literal, LiteralString
2929

30-
bad_union: Literal["hello", LiteralString] # error: [invalid-literal-parameter]
31-
bad_nesting: Literal[LiteralString] # error: [invalid-literal-parameter]
30+
bad_union: Literal["hello", LiteralString] # error: [invalid-type-form]
31+
bad_nesting: Literal[LiteralString] # error: [invalid-type-form]
3232
```
3333

34-
### Parametrized
34+
### Parameterized
3535

36-
`LiteralString` cannot be parametrized.
36+
`LiteralString` cannot be parameterized.
3737

3838
```py
3939
from typing_extensions import LiteralString
4040

41-
a: LiteralString[str] # error: [invalid-type-parameter]
42-
b: LiteralString["foo"] # error: [invalid-type-parameter]
41+
a: LiteralString[str] # error: [invalid-type-form]
42+
b: LiteralString["foo"] # error: [invalid-type-form]
4343
```
4444

4545
### As a base class

crates/red_knot_python_semantic/resources/mdtest/annotations/never.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ reveal_type(stop())
2121
```py
2222
from typing_extensions import NoReturn, Never, Any
2323

24-
# error: [invalid-type-parameter] "Type `typing.Never` expected no type parameter"
24+
# error: [invalid-type-form] "Type `typing.Never` expected no type parameter"
2525
x: Never[int]
2626
a1: NoReturn
2727
a2: Never

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ Some of these are not subscriptable:
6161
```py
6262
from typing_extensions import Self, TypeAlias
6363

64-
X: TypeAlias[T] = int # error: [invalid-type-parameter]
64+
X: TypeAlias[T] = int # error: [invalid-type-form]
6565

6666
class Foo[T]:
67-
# error: [invalid-type-parameter] "Special form `typing.Self` expected no type parameter"
68-
# error: [invalid-type-parameter] "Special form `typing.Self` expected no type parameter"
67+
# error: [invalid-type-form] "Special form `typing.Self` expected no type parameter"
68+
# error: [invalid-type-form] "Special form `typing.Self` expected no type parameter"
6969
def method(self: Self[int]) -> Self[int]:
7070
reveal_type(self) # revealed: Unknown
7171
```

crates/red_knot_python_semantic/resources/mdtest/literal/literal.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,19 @@ def f():
4545
# TODO: This should be Color.RED
4646
reveal_type(b1) # revealed: Literal[0]
4747

48-
# error: [invalid-literal-parameter]
48+
# error: [invalid-type-form]
4949
invalid1: Literal[3 + 4]
50-
# error: [invalid-literal-parameter]
50+
# error: [invalid-type-form]
5151
invalid2: Literal[4 + 3j]
52-
# error: [invalid-literal-parameter]
52+
# error: [invalid-type-form]
5353
invalid3: Literal[(3, 4)]
5454

5555
hello = "hello"
5656
invalid4: Literal[
57-
1 + 2, # error: [invalid-literal-parameter]
57+
1 + 2, # error: [invalid-type-form]
5858
"foo",
59-
hello, # error: [invalid-literal-parameter]
60-
(1, 2, 3), # error: [invalid-literal-parameter]
59+
hello, # error: [invalid-type-form]
60+
(1, 2, 3), # error: [invalid-type-form]
6161
]
6262
```
6363

crates/red_knot_python_semantic/resources/mdtest/metaclass.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class B(metaclass=M2): ...
6868
# error: [conflicting-metaclass] "The metaclass of a derived class (`C`) must be a subclass of the metaclasses of all its bases, but `M1` (metaclass of base class `A`) and `M2` (metaclass of base class `B`) have no subclass relationship"
6969
class C(A, B): ...
7070

71-
reveal_type(C.__class__) # revealed: Unknown
71+
reveal_type(C.__class__) # revealed: type[Unknown]
7272
```
7373

7474
## Conflict (2)
@@ -85,7 +85,7 @@ class A(metaclass=M1): ...
8585
# error: [conflicting-metaclass] "The metaclass of a derived class (`B`) must be a subclass of the metaclasses of all its bases, but `M2` (metaclass of `B`) and `M1` (metaclass of base class `A`) have no subclass relationship"
8686
class B(A, metaclass=M2): ...
8787

88-
reveal_type(B.__class__) # revealed: Unknown
88+
reveal_type(B.__class__) # revealed: type[Unknown]
8989
```
9090

9191
## Common metaclass
@@ -129,7 +129,7 @@ class C(metaclass=M12): ...
129129
# error: [conflicting-metaclass] "The metaclass of a derived class (`D`) must be a subclass of the metaclasses of all its bases, but `M1` (metaclass of base class `A`) and `M2` (metaclass of base class `B`) have no subclass relationship"
130130
class D(A, B, C): ...
131131

132-
reveal_type(D.__class__) # revealed: Unknown
132+
reveal_type(D.__class__) # revealed: type[Unknown]
133133
```
134134

135135
## Unknown
@@ -183,7 +183,7 @@ class A(B): ... # error: [cyclic-class-definition]
183183
class B(C): ... # error: [cyclic-class-definition]
184184
class C(A): ... # error: [cyclic-class-definition]
185185

186-
reveal_type(A.__class__) # revealed: Unknown
186+
reveal_type(A.__class__) # revealed: type[Unknown]
187187
```
188188

189189
## PEP 695 generic

0 commit comments

Comments
 (0)