@@ -8,13 +8,13 @@ when generics are involved, the type of an outer expression can sometimes be use
88inner expressions. Bidirectional type inference is a mechanism that propagates such "expected types"
99to the inference of inner expressions.
1010
11- ## Propagating target type annotation
12-
1311``` toml
1412[environment ]
1513python-version = " 3.12"
1614```
1715
16+ ## Propagating target type annotation
17+
1818``` py
1919from typing import Literal
2020
@@ -80,11 +80,6 @@ def _() -> TD:
8080
8181## Propagating return type annotation
8282
83- ``` toml
84- [environment ]
85- python-version = " 3.12"
86- ```
87-
8883``` py
8984from typing import overload, Callable
9085
@@ -192,11 +187,6 @@ def f() -> list[Literal[1]]:
192187
193188## Instance attributes
194189
195- ``` toml
196- [environment ]
197- python-version = " 3.12"
198- ```
199-
200190Both meta and class/instance attribute annotations are used as type context:
201191
202192``` py
@@ -240,13 +230,99 @@ def _(xy: X | Y):
240230 xy.x = reveal_type([1 ]) # revealed: list[int]
241231```
242232
243- ## Class constructor parameters
233+ ## Overload evaluation
244234
245- ``` toml
246- [environment ]
247- python-version = " 3.12"
235+ The type context of all matching overloads are considered during argument inference:
236+
237+ ``` py
238+ from typing import overload, TypedDict
239+
240+ def int_or_str () -> int | str :
241+ raise NotImplementedError
242+
243+ @overload
244+ def f1 (x : list[int | None ], y : int ) -> int : ...
245+ @overload
246+ def f1 (x : list[int | str ], y : str ) -> str : ...
247+ def f1 (x , y ) -> int | str :
248+ raise NotImplementedError
249+
250+ # TODO : We should reveal `list[int]` here.
251+ x1 = f1(reveal_type([1 ]), 1 ) # revealed: list[int]
252+ reveal_type(x1) # revealed: int
253+
254+ x2 = f1(reveal_type([1 ]), int_or_str()) # revealed: list[int]
255+ reveal_type(x2) # revealed: int | str
256+
257+ @overload
258+ def f2[T](x: T, y: int ) -> T: ...
259+ @overload
260+ def f2 (x : list[int | str ], y : str ) -> object : ...
261+ def f2 (x , y ) -> object : ...
262+
263+ x3 = f2(reveal_type([1 ]), 1 ) # revealed: list[int]
264+ reveal_type(x3) # revealed: list[int]
265+
266+ class TD (TypedDict ):
267+ x: list[int | str ]
268+
269+ class TD2 (TypedDict ):
270+ x: list[int | None ]
271+
272+ @overload
273+ def f3 (x : TD , y : int ) -> int : ...
274+ @overload
275+ def f3 (x : TD2 , y : str ) -> str : ...
276+ def f3 (x , y ) -> object : ...
277+
278+ # TODO : We should reveal `TD2` here.
279+ x4 = f3(reveal_type({" x" : [1 ]}), " 1" ) # revealed: dict[str, list[int]]
280+ reveal_type(x4) # revealed: str
281+
282+ x5 = f3(reveal_type({" x" : [1 ]}), int_or_str()) # revealed: dict[str, list[int]]
283+ reveal_type(x5) # revealed: int | str
284+
285+ @overload
286+ def f4[T](_: list[T]) -> list[T]: ...
287+ @overload
288+ def f4 (_ : list[str ]) -> list[str ]: ...
289+ def f4 (_ : object ): ...
290+
291+ x6 = f4(reveal_type([])) # revealed: list[Unknown]
292+ reveal_type(x6) # revealed: list[Unknown]
293+
294+ @overload
295+ def f5 (_ : list[int | str ]) -> int : ...
296+ @overload
297+ def f5 (_ : set[int | str ]) -> str : ...
298+ def f5 (_ ) -> object :
299+ raise NotImplementedError
300+
301+ def list_or_set[T](x: T) -> list[T] | set[T]:
302+ raise NotImplementedError
303+
304+ # TODO : We should reveal `list[int | str] | set[int | str]` here.
305+ x7 = f5(reveal_type(list_or_set(1 ))) # revealed: list[int] | set[int]
306+ reveal_type(x7) # revealed: int | str
307+
308+ @overload
309+ def f6 (_ : list[int | None ]) -> int : ...
310+ @overload
311+ def f6 (_ : set[int | str ]) -> str : ...
312+ def f6 (_ ) -> object :
313+ raise NotImplementedError
314+
315+ def list_or_set2[T, U](x: T, y: U) -> list[T] | set[U]:
316+ raise NotImplementedError
317+
318+ # TODO : We should not error here.
319+ # error: [no-matching-overload]
320+ x8 = f6(reveal_type(list_or_set2(1 , 1 ))) # revealed: list[int] | set[int]
321+ reveal_type(x8) # revealed: Unknown
248322```
249323
324+ ## Class constructor parameters
325+
250326The parameters of both ` __init__ ` and ` __new__ ` are used as type context sources for constructor
251327calls:
252328
@@ -269,11 +345,6 @@ A(f([]))
269345
270346## Conditional expressions
271347
272- ``` toml
273- [environment ]
274- python-version = " 3.12"
275- ```
276-
277348The type context is propagated through both branches of conditional expressions:
278349
279350``` py
@@ -290,11 +361,6 @@ def _(flag: bool):
290361
291362## Dunder Calls
292363
293- ``` toml
294- [environment ]
295- python-version = " 3.12"
296- ```
297-
298364The key and value parameters types are used as type context for ` __setitem__ ` dunder calls:
299365
300366``` py
@@ -387,11 +453,6 @@ def _(x: Intersection[X, Y]):
387453
388454## Multi-inference diagnostics
389455
390- ``` toml
391- [environment ]
392- python-version = " 3.12"
393- ```
394-
395456Diagnostics unrelated to the type-context are only reported once:
396457
397458``` py
0 commit comments