Skip to content

Commit a423d67

Browse files
authored
Fix overload handling with union types in signatures (#3300)
Previously `None` was not considered as more precise than `Optional[x]`, which was obviously incorrect. Fixed the implementation of type precision checking to match the description, now that proper subtype checking is implemented. Fixes the original example in #3295.
1 parent d23c892 commit a423d67

File tree

3 files changed

+23
-14
lines changed

3 files changed

+23
-14
lines changed

mypy/subtypes.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -945,19 +945,14 @@ def visit_type_type(self, left: TypeType) -> bool:
945945
return False
946946

947947

948-
def is_more_precise(t: Type, s: Type) -> bool:
949-
"""Check if t is a more precise type than s.
948+
def is_more_precise(left: Type, right: Type) -> bool:
949+
"""Check if left is a more precise type than right.
950950
951-
A t is a proper subtype of s, t is also more precise than s. Also, if
952-
s is Any, t is more precise than s for any t. Finally, if t is the same
953-
type as s, t is more precise than s.
951+
A left is a proper subtype of right, left is also more precise than
952+
right. Also, if right is Any, left is more precise than right, for
953+
any left.
954954
"""
955955
# TODO Should List[int] be more precise than List[Any]?
956-
if isinstance(s, AnyType):
956+
if isinstance(right, AnyType):
957957
return True
958-
if isinstance(s, Instance):
959-
if isinstance(t, CallableType):
960-
# Fall back to subclass check and ignore other properties of the callable.
961-
return is_proper_subtype(t.fallback, s)
962-
return is_proper_subtype(t, s)
963-
return sametypes.is_same_type(t, s)
958+
return is_proper_subtype(left, right)

mypy/test/testtypes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,11 @@ def test_is_more_precise(self) -> None:
176176
assert_true(is_more_precise(fx.b, fx.anyt))
177177
assert_true(is_more_precise(self.tuple(fx.b, fx.a),
178178
self.tuple(fx.b, fx.a)))
179+
assert_true(is_more_precise(self.tuple(fx.b, fx.b),
180+
self.tuple(fx.b, fx.a)))
179181

180182
assert_false(is_more_precise(fx.a, fx.b))
181183
assert_false(is_more_precise(fx.anyt, fx.b))
182-
assert_false(is_more_precise(self.tuple(fx.b, fx.b),
183-
self.tuple(fx.b, fx.a)))
184184

185185
# is_proper_subtype
186186

test-data/unit/check-optional.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,20 @@ reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str, builtins
620620
y: Optional[Union[int, None]]
621621
reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.None]'
622622

623+
[case testOverloadWithNoneAndOptional]
624+
from typing import overload, Optional
625+
626+
@overload
627+
def f(x: int) -> str: ...
628+
@overload
629+
def f(x: Optional[int]) -> Optional[str]: ...
630+
def f(x): return x
631+
632+
reveal_type(f(1)) # E: Revealed type is 'builtins.str'
633+
reveal_type(f(None)) # E: Revealed type is 'Union[builtins.str, builtins.None]'
634+
x: Optional[int]
635+
reveal_type(f(x)) # E: Revealed type is 'Union[builtins.str, builtins.None]'
636+
623637
[case testUnionTruthinessTracking]
624638
from typing import Optional, Any
625639
def test_or_shortcut(value: Optional[Any]) -> None:

0 commit comments

Comments
 (0)