-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
I found this while creating the type Literal[1, 2, 3] & ~Literal[1] & ~Literal[2]. I was expecting to get Literal[3] after all simplifications were applied, but I got ~Literal[2] | Literal[3] instead. This is clearly not optimal.
The reason for this behavior is the following (using 1 instead of Literal[1] etc): When adding the first negation, we get the following in the union-of-intersections representation:
(1 | 2 | 3) & ~1
= (1 & ~1 | 2 & ~1 | 3 & ~1)
In the second and third component, the simplification creates 2 & ~1 = 2 and 3 & ~1 = 3, as expected. In the first component, the current implementation of simplification removes all positive (1) and negative (~1) components from the intersection, leaving an empty intersection:
= (empty-intersection | 2 | 3)
The idea was that the empty-intersection would represent Never (similar to how IntersectionBuilder::build() returns Never for the empty-empty case). But an empty intersection should actually represent the type object. To represent Never, we would need to explicitly add Never to the positive side. Since we don't do that, we end up creating
(empty-intersection | 2 | 3) & ~2
= (~2 | 2 & ~2 | 3 & ~2)
= ~2 | Never | 3
= ~2 | 3
in the second step.