diff --git a/mypy/checker.py b/mypy/checker.py index 4cd5c6c5580d..2c71c468ed46 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5325,9 +5325,11 @@ def conditional_type_map(expr: Expression, return None, {} else: # we can only restrict when the type is precise, not bounded - proposed_precise_type = UnionType([type_range.item - for type_range in proposed_type_ranges - if not type_range.is_upper_bound]) + proposed_precise_type = UnionType.make_union([ + 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) return {expr: proposed_type}, {expr: remaining_type} else: diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 52d03282494f..b1f6dba58cef 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1131,6 +1131,8 @@ def restrict_subtype_away(t: Type, s: Type, *, ignore_promotions: bool = False) if (isinstance(get_proper_type(item), AnyType) or not covers_at_runtime(item, s, ignore_promotions))] return UnionType.make_union(new_items) + elif covers_at_runtime(t, s, ignore_promotions): + return UninhabitedType() else: return t diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 80bc40b6ca98..652a26163858 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1975,7 +1975,7 @@ T = TypeVar('T') class A: def f(self) -> None: - self.g() # E: Too few arguments for "g" of "A" + self.g() # E: Too few arguments for "g" of "A" self.g(1) @dec def g(self, x: str) -> None: pass diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 8cf85536f3b9..6b030ae49a86 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1143,3 +1143,32 @@ else: reveal_type(abc) # N: Revealed type is "TypedDict('__main__.B', {'tag': Literal['B'], 'b': builtins.int})" [builtins fixtures/primitives.pyi] + + +[case testNarrowingRuntimeCover] +from typing import Dict, List, Union + +def unreachable(x: Union[str, List[str]]) -> None: + if isinstance(x, str): + reveal_type(x) # N: Revealed type is "builtins.str" + elif isinstance(x, list): + reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" + else: + reveal_type(x) # N: Revealed type is "" + +def all_parts_covered(x: Union[str, List[str], List[int], int]) -> None: + if isinstance(x, str): + reveal_type(x) # N: Revealed type is "builtins.str" + elif isinstance(x, list): + reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.list[builtins.int]]" + else: + reveal_type(x) # N: Revealed type is "builtins.int" + +def two_type_vars(x: Union[str, Dict[str, int], Dict[bool, object], int]) -> None: + if isinstance(x, str): + reveal_type(x) # N: Revealed type is "builtins.str" + elif isinstance(x, dict): + reveal_type(x) # N: Revealed type is "Union[builtins.dict[builtins.str, builtins.int], builtins.dict[builtins.bool, builtins.object]]" + else: + reveal_type(x) # N: Revealed type is "builtins.int" +[builtins fixtures/dict.pyi]