Skip to content

Commit

Permalink
Make reachability code understand chained comparisons (v2) (python#8148)
Browse files Browse the repository at this point in the history
This pull request is v2 (well, more like v10...) of my attempts to
make our reachability code better understand chained comparisons.

Unlike python#7169, this diff focuses
exclusively on adding support for chained operation comparisons and
deliberately does not attempt to change any of the semantics of
how identity and equality operations are performed.

Specifically, mypy currently only examines the first two operands
within a comparison expression when refining types. That means
the following expressions all do not behave as expected:

```python
x: MyEnum
y: MyEnum
if x is y is MyEnum.A:
    # x and y are not narrowed at all

if x is MyEnum.A is y:
    # Only x is narrowed to Literal[MyEnum.A]
```

This pull request fixes this so we correctly infer the literal type
for x and y in both conditionals.

Some additional notes:

1. While analyzing our codebase, I found that while comparison
   expressions involving two or more `is` or `==` operators
   were somewhat common, there were almost no comparisons involving
   chains of `!=` or `is not` operators, and no comparisons
   involving "disjoint chains" -- e.g. expressions like
   `a == b < c == b` where there are multiple "disjoint"
   chains of equality comparisons.

   So, this diff is primarily designed to handle the case where
   a comparison expression has just one chain of `is` or `==`.
   For all other cases, I fall back to the more naive strategy
   of evaluating each comparison individually and and-ing the
   inferred types together without attempting to propagate
   any info.

2. I tested this code against one of our internal codebases. This
   ended up making mypy produce 3 or 4 new errors, but they all
   seemed legitimate, as far as I can tell.

3. I plan on submitting a follow-up diff that takes advantage of
   the work done in this diff to complete support for tagged unions
   using any Literal key, as previously promised.

   (I tried adding support for tagged unions in this diff, but
   attempting to simultaneously add support for chained comparisons
   while overhauling the semantics of `==` proved to be a little
   too overwhelming for me. So, baby steps.)
  • Loading branch information
Michael0x2a committed Dec 25, 2019
1 parent 5336f27 commit 9101707
Show file tree
Hide file tree
Showing 5 changed files with 956 additions and 65 deletions.

0 comments on commit 9101707

Please sign in to comment.