Repository: python/mypy

Issue:
Else block of `isinstance` check with promotable types has <nothing> for type
This test case
```
from typing import Union
def asdf(val: Union[int, float]):
    if isinstance(val, float):
        reveal_type(val)
    else:
        reveal_type(val)
```
produces:
```
/home/msullivan/lol2.py:4: error: Revealed type is 'builtins.float'
/home/msullivan/lol2.py:6: error: Revealed type is '<nothing>'
```
But the type in the `else` branch ought to be `int`.

Prior to  #6114, it produced
```
/home/msullivan/lol2.py:4: error: Revealed type is 'Union[builtins.int, builtins.float]'
```
which is of course also wrong.
The prior version produced false positives in the then branch and false negatives in the else branch, while the new version produces false positives in the else branch and works correctly in the then branch.


Discussion:

Resolving patch:
diff --git a/mypy/checker.py b/mypy/checker.py
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -3764,7 +3764,8 @@ def conditional_type_map(expr: Expression,
                 proposed_precise_type = UnionType([type_range.item
                                           for type_range in proposed_type_ranges
                                           if not type_range.is_upper_bound])
-                remaining_type = restrict_subtype_away(current_type, proposed_precise_type)
+                remaining_type = restrict_subtype_away(current_type, proposed_precise_type,
+                                                       ignore_promotions=True)
                 return {expr: proposed_type}, {expr: remaining_type}
         else:
             return {expr: proposed_type}, {}
diff --git a/mypy/subtypes.py b/mypy/subtypes.py
--- a/mypy/subtypes.py
+++ b/mypy/subtypes.py
@@ -997,7 +997,7 @@ def unify_generic_callable(type: CallableType, target: CallableType,
     return applied
 
 
-def restrict_subtype_away(t: Type, s: Type) -> Type:
+def restrict_subtype_away(t: Type, s: Type, *, ignore_promotions: bool = False) -> Type:
     """Return t minus s.
 
     If we can't determine a precise result, return a supertype of the
@@ -1014,8 +1014,10 @@ def restrict_subtype_away(t: Type, s: Type) -> Type:
         # TODO: Implement more robust support for runtime isinstance() checks,
         # see issue #3827
         new_items = [item for item in t.relevant_items()
-                     if (not (is_proper_subtype(erase_type(item), erased_s) or
-                              is_proper_subtype(item, erased_s))
+                     if (not (is_proper_subtype(erase_type(item), erased_s,
+                                                ignore_promotions=ignore_promotions) or
+                              is_proper_subtype(item, erased_s,
+                                                ignore_promotions=ignore_promotions))
                          or isinstance(item, AnyType))]
         return UnionType.make_union(new_items)
     else:


Test patch:
diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test
--- a/test-data/unit/check-isinstance.test
+++ b/test-data/unit/check-isinstance.test
@@ -1323,6 +1323,8 @@ def f1(x: Union[float, int]) -> None:
     # We ignore promotions in isinstance checks
     if isinstance(x, float):
         reveal_type(x)  # E: Revealed type is 'builtins.float'
+    else:
+        reveal_type(x)  # E: Revealed type is 'builtins.int'
 
 def f2(x: Union[FloatLike, IntLike]) -> None:
     # ...but not regular subtyping relationships