From 79f14b0ada3f214089fd42578a8b6c851f3c6f9f Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Fri, 4 Jan 2019 13:54:15 -0800 Subject: [PATCH] Disable promotions when restricting types in isinstance checks This fixes a bug left behind by #6114, where too much would get subtracted out of a union type after an isinstance. Fixes #6141. --- mypy/checker.py | 3 ++- mypy/subtypes.py | 8 +++++--- test-data/unit/check-isinstance.test | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index a4cb8d12cdb5..2638f0e768c7 100644 --- 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 index 227b3ba10d27..83ebd468b9b3 100644 --- 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: diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 9076ef9aea6b..4060832dd425 100644 --- 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