Skip to content

Commit c4c95ef

Browse files
committed
EXPERIMENT: skip simplifying Unions of TypedDicts
1 parent 6a96571 commit c4c95ef

File tree

3 files changed

+11
-9
lines changed

3 files changed

+11
-9
lines changed

crates/ty_python_semantic/resources/mdtest/typed_dict.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -841,10 +841,10 @@ def _(
841841

842842
reveal_type(being["name"]) # revealed: str
843843

844-
# TODO: A type of `int | None | Unknown` might be better here. `str` is because
845-
# `Person | Animal` reduces to `Animal`, and `Animal.__getitem__` can only return `str`.
844+
# TODO: A type of `int | None | Unknown` might be better here. The `str` is mixed in
845+
# because `Animal.__getitem__` can only return `str`.
846846
# error: [invalid-key] "Unknown key "age" for TypedDict `Animal`"
847-
reveal_type(being["age"]) # revealed: str
847+
reveal_type(being["age"]) # revealed: int | None | str
848848
```
849849

850850
### Writing
@@ -1115,7 +1115,8 @@ def combine(p: Person, e: Employee):
11151115
reveal_type(p | p) # revealed: Person
11161116
reveal_type(e | e) # revealed: Employee
11171117

1118-
reveal_type(p | e) # revealed: Person
1118+
# EXPERIMENT: Simplification of TypedDicts in Unions is disabled.
1119+
reveal_type(p | e) # revealed: Person | Employee
11191120
```
11201121

11211122
When inheriting from a `TypedDict` with a different `total` setting, inherited fields maintain their

crates/ty_python_semantic/src/types/builder.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -463,10 +463,11 @@ impl<'db> UnionBuilder<'db> {
463463
None
464464
};
465465

466-
// If an alias gets here, it means we aren't unpacking aliases, and we also
467-
// shouldn't try to simplify aliases out of the union, because that will require
468-
// unpacking them.
469-
let should_simplify_full = !matches!(ty, Type::TypeAlias(_));
466+
// If an alias gets here, it means we aren't unpacking aliases, and we also shouldn't try
467+
// to simplify aliases out of the union, because that will require unpacking them.
468+
// `TypedDict`s also run into trouble here when their fields refer to a recursive union, so
469+
// and we need to skip simplification to break cycles.
470+
let should_simplify_full = !matches!(ty, Type::TypeAlias(_) | Type::TypedDict(_));
470471

471472
let mut to_remove = SmallVec::<[usize; 2]>::new();
472473
let ty_negated = if should_simplify_full {

crates/ty_python_semantic/src/types/class.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ impl<'db> ClassType<'db> {
565565
TypeRelation::Assignability => ConstraintSet::from(!other.is_final(db)),
566566
},
567567

568-
// Protocol and Generic are not represented by a ClassType.
568+
// Protocol, Generic, and TypedDict are not represented by a ClassType.
569569
ClassBase::Protocol | ClassBase::Generic | ClassBase::TypedDict => {
570570
ConstraintSet::from(false)
571571
}

0 commit comments

Comments
 (0)