@@ -427,14 +427,13 @@ a = f("a")
427427reveal_type(a) # revealed: list[Literal["a"]]
428428
429429b: list[int | Literal[" a" ]] = f(" a" )
430- reveal_type(b) # revealed: list[Literal["a"] | int ]
430+ reveal_type(b) # revealed: list[int | Literal["a"]]
431431
432432c: list[int | str ] = f(" a" )
433- reveal_type(c) # revealed: list[str | int ]
433+ reveal_type(c) # revealed: list[int | str ]
434434
435435d: list[int | tuple[int , int ]] = f((1 , 2 ))
436- # TODO : We could avoid reordering the union elements here.
437- reveal_type(d) # revealed: list[tuple[int, int] | int]
436+ reveal_type(d) # revealed: list[int | tuple[int, int]]
438437
439438e: list[int ] = f(True )
440439reveal_type(e) # revealed: list[int]
@@ -455,7 +454,120 @@ j: int | str = f2(True)
455454reveal_type(j) # revealed: Literal[True]
456455```
457456
458- Types are not widened unnecessarily:
457+ The function arguments are also inferred using the type context:
458+
459+ ``` py
460+ from typing import TypedDict
461+
462+ class TD (TypedDict ):
463+ x: int
464+
465+ def f[T](x: list[T]) -> T:
466+ return x[0 ]
467+
468+ a: TD = f([{" x" : 0 }, {" x" : 1 }])
469+ reveal_type(a) # revealed: TD
470+
471+ b: TD | None = f([{" x" : 0 }, {" x" : 1 }])
472+ reveal_type(b) # revealed: TD
473+
474+ # error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
475+ # error: [invalid-key] "Invalid key for TypedDict `TD`: Unknown key "y""
476+ # error: [invalid-assignment] "Object of type `Unknown | dict[Unknown | str, Unknown | int]` is not assignable to `TD`"
477+ c: TD = f([{" y" : 0 }, {" x" : 1 }])
478+
479+ # error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
480+ # error: [invalid-key] "Invalid key for TypedDict `TD`: Unknown key "y""
481+ # error: [invalid-assignment] "Object of type `Unknown | dict[Unknown | str, Unknown | int]` is not assignable to `TD | None`"
482+ c: TD | None = f([{" y" : 0 }, {" x" : 1 }])
483+ ```
484+
485+ ## Prefer the declared type of generic classes
486+
487+ ``` toml
488+ [environment ]
489+ python-version = " 3.12"
490+ ```
491+
492+ ``` py
493+ from typing import Any
494+
495+ def f[T](x: T) -> list[T]:
496+ return [x]
497+
498+ def f2[T](x: T) -> list[T] | None :
499+ return [x]
500+
501+ def f3[T](x: T) -> list[T] | dict[T, T]:
502+ return [x]
503+
504+ a = f(1 )
505+ reveal_type(a) # revealed: list[Literal[1]]
506+
507+ b: list[Any] = f(1 )
508+ reveal_type(b) # revealed: list[Any]
509+
510+ c: list[Any] = [1 ]
511+ reveal_type(c) # revealed: list[Any]
512+
513+ d: list[Any] | None = f(1 )
514+ reveal_type(d) # revealed: list[Any]
515+
516+ e: list[Any] | None = [1 ]
517+ reveal_type(e) # revealed: list[Any]
518+
519+ f: list[Any] | None = f2(1 )
520+ # TODO : Better constraint solver.
521+ reveal_type(f) # revealed: list[Literal[1]] | None
522+
523+ g: list[Any] | dict[Any, Any] = f3(1 )
524+ # TODO : Better constraint solver.
525+ reveal_type(g) # revealed: list[Literal[1]] | dict[Literal[1], Literal[1]]
526+ ```
527+
528+ ## Narrow generic unions
529+
530+ ``` toml
531+ [environment ]
532+ python-version = " 3.12"
533+ ```
534+
535+ ``` py
536+ from typing import reveal_type, TypedDict
537+
538+ def id [T](x: T) -> T:
539+ return x
540+
541+ def _ (narrow : dict[str , str ], target : list[str ] | dict[str , str ] | None ):
542+ target = id (narrow)
543+ reveal_type(target) # revealed: dict[str, str]
544+
545+ def _ (narrow : list[str ], target : list[str ] | dict[str , str ] | None ):
546+ target = id (narrow)
547+ reveal_type(target) # revealed: list[str]
548+
549+ def _ (narrow : list[str ] | dict[str , str ], target : list[str ] | dict[str , str ] | None ):
550+ target = id (narrow)
551+ reveal_type(target) # revealed: list[str] | dict[str, str]
552+
553+ class TD (TypedDict ):
554+ x: int
555+
556+ def _ (target : list[TD ] | dict[str , TD ] | None ):
557+ target = id ([{" x" : 1 }])
558+ reveal_type(target) # revealed: list[TD]
559+
560+ def _ (target : list[TD ] | dict[str , TD ] | None ):
561+ target = id ({" x" : {" x" : 1 }})
562+ reveal_type(target) # revealed: dict[str, TD]
563+ ```
564+
565+ ## Prefer the inferred type of non-generic classes
566+
567+ ``` toml
568+ [environment ]
569+ python-version = " 3.12"
570+ ```
459571
460572``` py
461573def id [T](x: T) -> T:
@@ -476,10 +588,8 @@ def _(i: int):
476588 b: list[int | None ] | None = id ([i])
477589 c: list[int | None ] | int | None = id ([i])
478590 reveal_type(a) # revealed: list[int | None]
479- # TODO : these should reveal `list[int | None]`
480- # we currently do not use the call expression annotation as type context for argument inference
481- reveal_type(b) # revealed: list[Unknown | int]
482- reveal_type(c) # revealed: list[Unknown | int]
591+ reveal_type(b) # revealed: list[int | None]
592+ reveal_type(c) # revealed: list[int | None]
483593
484594 a: list[int | None ] | None = [i]
485595 b: list[int | None ] | None = lst(i)
@@ -494,4 +604,23 @@ def _(i: int):
494604 reveal_type(a) # revealed: list[Unknown]
495605 reveal_type(b) # revealed: list[Unknown]
496606 reveal_type(c) # revealed: list[Unknown]
607+
608+ def f[T](x: list[T]) -> T:
609+ return x[0 ]
610+
611+ def _ (a : int , b : int | str ):
612+ x1: int = f(lst(a))
613+ reveal_type(x1) # revealed: int
614+
615+ x2: int | str = f(lst(a))
616+ reveal_type(x2) # revealed: int
617+
618+ x3: int | None = f(lst(a))
619+ reveal_type(x3) # revealed: int
620+
621+ x4: int | str = f(lst(b))
622+ reveal_type(x4) # revealed: int | str
623+
624+ x5: int | str | None = f(lst(b))
625+ reveal_type(x5) # revealed: int | str
497626```
0 commit comments