Skip to content

Commit 6b98a26

Browse files
[red-knot] Support assert_type (#15194)
## Summary See #15103. ## Test Plan Markdown tests and unit tests.
1 parent c874638 commit 6b98a26

File tree

5 files changed

+422
-38
lines changed

5 files changed

+422
-38
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# `assert_type`
2+
3+
## Basic
4+
5+
```py
6+
from typing_extensions import assert_type
7+
8+
def _(x: int):
9+
assert_type(x, int) # fine
10+
assert_type(x, str) # error: [type-assertion-failure]
11+
```
12+
13+
## Narrowing
14+
15+
The asserted type is checked against the inferred type, not the declared type.
16+
17+
```toml
18+
[environment]
19+
python-version = "3.10"
20+
```
21+
22+
```py
23+
from typing_extensions import assert_type
24+
25+
def _(x: int | str):
26+
if isinstance(x, int):
27+
reveal_type(x) # revealed: int
28+
assert_type(x, int) # fine
29+
```
30+
31+
## Equivalence
32+
33+
The actual type must match the asserted type precisely.
34+
35+
```py
36+
from typing import Any, Type, Union
37+
from typing_extensions import assert_type
38+
39+
# Subtype does not count
40+
def _(x: bool):
41+
assert_type(x, int) # error: [type-assertion-failure]
42+
43+
def _(a: type[int], b: type[Any]):
44+
assert_type(a, type[Any]) # error: [type-assertion-failure]
45+
assert_type(b, type[int]) # error: [type-assertion-failure]
46+
47+
# The expression constructing the type is not taken into account
48+
def _(a: type[int]):
49+
assert_type(a, Type[int]) # fine
50+
```
51+
52+
## Gradual types
53+
54+
```py
55+
from typing import Any
56+
from typing_extensions import Literal, assert_type
57+
58+
from knot_extensions import Unknown
59+
60+
# Any and Unknown are considered equivalent
61+
def _(a: Unknown, b: Any):
62+
reveal_type(a) # revealed: Unknown
63+
assert_type(a, Any) # fine
64+
65+
reveal_type(b) # revealed: Any
66+
assert_type(b, Unknown) # fine
67+
68+
def _(a: type[Unknown], b: type[Any]):
69+
# TODO: Should be `type[Unknown]`
70+
reveal_type(a) # revealed: @Todo(unsupported type[X] special form)
71+
# TODO: Should be fine
72+
assert_type(a, type[Any]) # error: [type-assertion-failure]
73+
74+
reveal_type(b) # revealed: type[Any]
75+
# TODO: Should be fine
76+
assert_type(b, type[Unknown]) # error: [type-assertion-failure]
77+
```
78+
79+
## Tuples
80+
81+
Tuple types with the same elements are the same.
82+
83+
```py
84+
from typing_extensions import assert_type
85+
86+
from knot_extensions import Unknown
87+
88+
def _(a: tuple[int, str, bytes]):
89+
assert_type(a, tuple[int, str, bytes]) # fine
90+
91+
assert_type(a, tuple[int, str]) # error: [type-assertion-failure]
92+
assert_type(a, tuple[int, str, bytes, None]) # error: [type-assertion-failure]
93+
assert_type(a, tuple[int, bytes, str]) # error: [type-assertion-failure]
94+
95+
def _(a: tuple[Any, ...], b: tuple[Unknown, ...]):
96+
assert_type(a, tuple[Any, ...]) # fine
97+
assert_type(a, tuple[Unknown, ...]) # fine
98+
99+
assert_type(b, tuple[Unknown, ...]) # fine
100+
assert_type(b, tuple[Any, ...]) # fine
101+
```
102+
103+
## Unions
104+
105+
Unions with the same elements are the same, regardless of order.
106+
107+
```toml
108+
[environment]
109+
python-version = "3.10"
110+
```
111+
112+
```py
113+
from typing_extensions import assert_type
114+
115+
def _(a: str | int):
116+
assert_type(a, str | int) # fine
117+
118+
# TODO: Order-independent union handling in type equivalence
119+
assert_type(a, int | str) # error: [type-assertion-failure]
120+
```
121+
122+
## Intersections
123+
124+
Intersections are the same when their positive and negative parts are respectively the same,
125+
regardless of order.
126+
127+
```py
128+
from typing_extensions import assert_type
129+
130+
from knot_extensions import Intersection, Not
131+
132+
class A: ...
133+
class B: ...
134+
class C: ...
135+
class D: ...
136+
137+
def _(a: A):
138+
if isinstance(a, B) and not isinstance(a, C) and not isinstance(a, D):
139+
reveal_type(a) # revealed: A & B & ~C & ~D
140+
141+
assert_type(a, Intersection[A, B, Not[C], Not[D]]) # fine
142+
143+
# TODO: Order-independent intersection handling in type equivalence
144+
assert_type(a, Intersection[B, A, Not[D], Not[C]]) # error: [type-assertion-failure]
145+
```

0 commit comments

Comments
 (0)