8000 Fixes type narrowing for overlaping runtime types (#11273) · python/mypy@f4a21a4 · GitHub
[go: up one dir, main page]

Skip to content

Commit f4a21a4

Browse files
authored
Fixes type narrowing for overlaping runtime types (#11273)
Closes #11272
1 parent 4ddc8fb commit f4a21a4

File tree

4 files changed

+37
-4
lines changed

4 files changed

+37
-4
lines changed

mypy/checker.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5395,9 +5395,11 @@ def conditional_type_map(expr: Expression,
53955395
return None, {}
53965396
else:
53975397
# we can only restrict when the type is precise, not bounded
5398-
proposed_precise_type = UnionType([type_range.item
5399-
for type_range in proposed_type_ranges
5400-
if not type_range.is_upper_bound])
5398+
proposed_precise_type = UnionType.make_union([
5399+
type_range.item
5400+
for type_range in proposed_type_ranges
5401+
if not type_range.is_upper_bound
5402+
])
54015403
remaining_type = restrict_subtype_away(current_type, proposed_precise_type)
54025404
return {expr: proposed_type}, {expr: remaining_type}
54035405
else:

mypy/subtypes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,8 @@ def restrict_subtype_away(t: Type, s: Type, *, ignore_promotions: bool = False)
11381138
if (isinstance(get_proper_type(item), AnyType) or
11391139
not covers_at_runtime(item, s, ignore_promotions))]
11401140
return UnionType.make_union(new_items)
1141+
elif covers_at_runtime(t, s, ignore_promotions):
1142+
return UninhabitedType()
11411143
else:
11421144
return t
11431145

test-data/unit/check-inference.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1975,7 +1975,7 @@ T = TypeVar('T')
19751975

19761976
class A:
19771977
def f(self) -> None:
1978-
self.g() # E: Too few arguments for "g" of "A"
1978+
self.g() # E: Too few arguments for "g" of "A"
19791979
self.g(1)
19801980
@dec
19811981
def g(self, x: str) -> None: pass

test-data/unit/check-narrowing.test

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,3 +1143,32 @@ else:
11431143
reveal_type(abc) # N: Revealed type is "TypedDict('__main__.B', {'tag': Literal['B'], 'b': builtins.int})"
11441144

11451145
[builtins fixtures/primitives.pyi]
1146+
1147+
1148+
[case testNarrowingRuntimeCover]
1149+
from typing import Dict, List, Union
1150+
1151+
def unreachable(x: Union[str, List[str]]) -> None:
1152+
if isinstance(x, str):
1153+
reveal_type(x) # N: Revealed type is "builtins.str"
1154+
elif isinstance(x, list):
1155+
reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]"
1156+
else:
1157+
reveal_type(x) # N: Revealed type is "<nothing>"
1158+
1159+
def all_parts_covered(x: Union[str, List[str], List[int], int]) -> None:
1160+
if isinstance(x, str):
1161+
reveal_type(x) # N: Revealed type is "builtins.str"
1162+
elif isinstance(x, list):
1163+
reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.list[builtins.int]]"
1164+
else:
1165+
reveal_type(x) # N: Revealed type is "builtins.int"
1166+
1167+
def two_type_vars(x: Union[str, Dict[str, int], Dict[bool, object], int]) -> None:
1168+
if isinstance(x, str):
1169+
reveal_type(x) # N: Revealed type is "builtins.str"
1170+
elif isinstance(x, dict):
1171+
reveal_type(x) # N: Revealed type is "Union[builtins.dict[builtins.str, builtins.int], builtins.dict[builtins.bool, builtins.object]]"
1172+
else:
1173+
reveal_type(x) # N: Revealed type is "builtins.int"
1174+
[builtins fixtures/dict.pyi]

0 commit comments

Comments
 (0)
0