File tree Expand file tree Collapse file tree 3 files changed +31
-2
lines changed
Expand file tree Collapse file tree 3 files changed +31
-2
lines changed Original file line number Diff line number Diff line change @@ -13,6 +13,7 @@ use crate::class::ClassType;
1313use crate :: literal:: Lit ;
1414use crate :: stdlib:: Stdlib ;
1515use crate :: tuple:: Tuple ;
16+ use crate :: typed_dict:: TypedDict ;
1617use crate :: types:: Type ;
1718use crate :: types:: Union ;
1819
@@ -74,6 +75,7 @@ fn unions_internal(
7475 let mut res = flatten_and_dedup ( xs) ;
7576 if let Some ( stdlib) = stdlib {
7677 collapse_literals ( & mut res, stdlib, enum_members. unwrap_or ( & |_| None ) ) ;
78+ promote_anonymous_typed_dicts ( & mut res, stdlib) ;
7779 }
7880 collapse_tuple_unions_with_empty ( & mut res) ;
7981 // `res` is collapsible again if `flatten_and_dedup` drops `xs` to 0 or 1 elements
@@ -254,6 +256,17 @@ fn collapse_literals(
254256 }
255257}
256258
259+ /// Promote anonymous typed dicts to `dict[str, value_type]`
260+ fn promote_anonymous_typed_dicts ( types : & mut [ Type ] , stdlib : & Stdlib ) {
261+ for ty in types. iter_mut ( ) {
262+ if let Type :: TypedDict ( TypedDict :: Anonymous ( inner) ) = ty {
263+ * ty = stdlib
264+ . dict ( stdlib. str ( ) . clone ( ) . to_type ( ) , inner. value_type . clone ( ) )
265+ . to_type ( ) ;
266+ }
267+ }
268+ }
269+
257270fn collapse_tuple_unions_with_empty ( types : & mut Vec < Type > ) {
258271 let Some ( empty_idx) = types. iter ( ) . position ( |t| match t {
259272 Type :: Tuple ( Tuple :: Concrete ( elts) ) => elts. is_empty ( ) ,
Original file line number Diff line number Diff line change @@ -2284,7 +2284,8 @@ class A:
22842284 self.y = {"x": 0} if check else 42
22852285def f(a: A):
22862286 x: TD = a.x
2287- y: TD | int = a.y
2287+ # anoynmous typed dicts are promoted away when unioned
2288+ y: dict[str, int] | int = a.y
22882289 "# ,
22892290) ;
22902291
Original file line number Diff line number Diff line change @@ -14,6 +14,21 @@ dict(x = 1, y = "test")
1414 "# ,
1515) ;
1616
17+ testcase ! (
18+ test_anonymous_typed_dict_union_promotion,
19+ r#"
20+ from typing import assert_type
21+
22+ def test(cond: bool):
23+ x = {"a": 1, "b": "2"}
24+ y = {"a": 1, "b": "2", "c": 3}
25+ # we promote anonymous typed dicts when unioning
26+ z = x if cond else y
27+ assert_type(z["a"], int | str)
28+ assert_type(z, dict[str, int | str])
29+ "# ,
30+ ) ;
31+
1732testcase ! (
1833 test_unpack_empty,
1934 r#"
@@ -48,6 +63,6 @@ def bar(yes: bool) -> None:
4863 else:
4964 kwargs = {"goodbye": 1}
5065
51- foo(**kwargs)
66+ foo(**kwargs)
5267"# ,
5368) ;
You can’t perform that action at this time.
0 commit comments