Skip to content

Commit 7beb24b

Browse files
committed
use declared variable types as bidirectional type context
1 parent 66885e4 commit 7beb24b

File tree

4 files changed

+295
-132
lines changed

4 files changed

+295
-132
lines changed

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ reveal_type(q) # revealed: dict[int | str, int]
144144

145145
r: dict[int | str, int | str] = {1: 1, 2: 2, 3: 3}
146146
reveal_type(r) # revealed: dict[int | str, int | str]
147+
148+
s: dict[int | str, int | str]
149+
s = {1: 1, 2: 2, 3: 3}
150+
reveal_type(s) # revealed: dict[int | str, int | str]
151+
(s := {1: 1, 2: 2, 3: 3})
152+
reveal_type(s) # revealed: dict[int | str, int | str]
147153
```
148154

149155
## Incorrect collection literal assignments are complained aobut
@@ -229,6 +235,49 @@ reveal_type(q) # revealed: list[int]
229235

230236
r: list[Literal[1, 2, 3, 4]] = [1, 2]
231237
reveal_type(r) # revealed: list[Literal[1, 2, 3, 4]]
238+
239+
s: list[Literal[1]]
240+
s = [1]
241+
reveal_type(s) # revealed: list[Literal[1]]
242+
(s := [1])
243+
reveal_type(s) # revealed: list[Literal[1]]
244+
```
245+
246+
## Class attribute annotations are understood
247+
248+
```py
249+
from typing import TypedDict, Literal
250+
251+
class TD(TypedDict):
252+
x: int
253+
254+
class X:
255+
a: list[Literal[1]]
256+
b: list[int | str]
257+
c: TD
258+
259+
d: TD = { "x": 1 }
260+
261+
def _(x: X):
262+
x.a = [1]
263+
reveal_type(x.a) # revealed: list[Literal[1]]
264+
265+
x.b = [2]
266+
reveal_type(x.b) # revealed: list[int | str]
267+
268+
# error: [invalid-key] "Invalid key access on TypedDict `TD`: Unknown key "y""
269+
# error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
270+
x.c = { "y": 1 }
271+
272+
x.c = { "x": 1 }
273+
reveal_type(x.c) # revealed: TD
274+
275+
# error: [invalid-key] "Invalid key access on TypedDict `TD`: Unknown key "y""
276+
# error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
277+
X.d = { "y": 1 }
278+
279+
X.d = { "x": 1 }
280+
reveal_type(X.d) # revealed: TD
232281
```
233282

234283
## PEP-604 annotations are supported

crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,13 @@ no longer valid in the inner lazy scope.
310310
def f(l: list[str | None]):
311311
if l[0] is not None:
312312
def _():
313-
reveal_type(l[0]) # revealed: str | None | Unknown
313+
reveal_type(l[0]) # revealed: str | None
314314
l = [None]
315315

316316
def f(l: list[str | None]):
317317
l[0] = "a"
318318
def _():
319-
reveal_type(l[0]) # revealed: str | None | Unknown
319+
reveal_type(l[0]) # revealed: str | None
320320
l = [None]
321321

322322
def f(l: list[str | None]):

crates/ty_python_semantic/resources/mdtest/typed_dict.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,12 @@ Person({"name": "Alice"})
194194

195195
# error: [missing-typed-dict-key] "Missing required key 'age' in TypedDict `Person` constructor"
196196
accepts_person({"name": "Alice"})
197-
# TODO: this should be an error, similar to the above
197+
198+
# error: [missing-typed-dict-key] "Missing required key 'age' in TypedDict `Person` constructor"
198199
house.owner = {"name": "Alice"}
200+
199201
a_person: Person
200-
# TODO: this should be an error, similar to the above
202+
# error: [missing-typed-dict-key] "Missing required key 'age' in TypedDict `Person` constructor"
201203
a_person = {"name": "Alice"}
202204
```
203205

@@ -213,11 +215,15 @@ Person({"name": None, "age": 30})
213215

214216
# error: [invalid-argument-type] "Invalid argument to key "name" with declared type `str` on TypedDict `Person`: value of type `None`"
215217
accepts_person({"name": None, "age": 30})
216-
# TODO: this should be an error, similar to the above
218+
219+
# error: [invalid-argument-type] "Invalid argument to key "name" with declared type `str` on TypedDict `Person`: value of type `None`"
217220
house.owner = {"name": None, "age": 30}
221+
218222
a_person: Person
219-
# TODO: this should be an error, similar to the above
223+
# error: [invalid-argument-type] "Invalid argument to key "name" with declared type `str` on TypedDict `Person`: value of type `None`"
220224
a_person = {"name": None, "age": 30}
225+
# error: [invalid-argument-type] "Invalid argument to key "name" with declared type `str` on TypedDict `Person`: value of type `None`"
226+
(a_person := {"name": None, "age": 30})
221227
```
222228

223229
All of these have an extra field that is not defined in the `TypedDict`:
@@ -232,11 +238,15 @@ Person({"name": "Alice", "age": 30, "extra": True})
232238

233239
# error: [invalid-key] "Invalid key access on TypedDict `Person`: Unknown key "extra""
234240
accepts_person({"name": "Alice", "age": 30, "extra": True})
235-
# TODO: this should be an error
241+
242+
# error: [invalid-key] "Invalid key access on TypedDict `Person`: Unknown key "extra""
236243
house.owner = {"name": "Alice", "age": 30, "extra": True}
237-
# TODO: this should be an error
244+
238245
a_person: Person
246+
# error: [invalid-key] "Invalid key access on TypedDict `Person`: Unknown key "extra""
239247
a_person = {"name": "Alice", "age": 30, "extra": True}
248+
# error: [invalid-key] "Invalid key access on TypedDict `Person`: Unknown key "extra""
249+
(a_person := {"name": "Alice", "age": 30, "extra": True})
240250
```
241251

242252
## Type ignore compatibility issues

0 commit comments

Comments
 (0)