Skip to content

Commit 2e65c1c

Browse files
committed
Simplify union types when determining type sameness
Fixes #1135.
1 parent 2662e4e commit 2e65c1c

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

mypy/sametypes.py

+16
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,25 @@ def is_same_type(left: Type, right: Type) -> bool:
1414
# generated spurious error messages.
1515
return True
1616
else:
17+
# Simplify types to canonical forms.
18+
#
19+
# There are multiple possible union types that represent the same type,
20+
# such as Union[int, bool, str] and Union[int, str]. Also, some union
21+
# types can be simplified to non-union types such as Union[int, bool]
22+
# -> int. It would be nice if we always had simplified union types but
23+
# this is currently not the case, though it often is.
24+
left = simplify_union(left)
25+
right = simplify_union(right)
26+
1727
return left.accept(SameTypeVisitor(right))
1828

1929

30+
def simplify_union(t: Type) -> Type:
31+
if isinstance(t, UnionType):
32+
return UnionType.make_simplified_union(t.items)
33+
return t
34+
35+
2036
def is_same_types(a1: Sequence[Type], a2: Sequence[Type]) -> bool:
2137
if len(a1) != len(a2):
2238
return False

mypy/test/data/check-isinstance.test

+20
Original file line numberDiff line numberDiff line change
@@ -773,3 +773,23 @@ def foo(): pass
773773
[builtins fixtures/isinstancelist.py]
774774
[out]
775775
main: note: In function "f":
776+
777+
[case testIsinstanceWithOverlappingUnionType]
778+
from typing import Union
779+
def f(x: Union[float, int]) -> None:
780+
if isinstance(x, float):
781+
pass
782+
if not isinstance(x, int):
783+
f(x)
784+
[builtins fixtures/isinstance.py]
785+
786+
[case testIsinstanceWithOverlappingUnionType2]
787+
from typing import Union
788+
class A: pass
789+
class B(A): pass
790+
def f(x: Union[A, B]) -> None:
791+
if isinstance(x, A):
792+
pass
793+
if not isinstance(x, B):
794+
f(x)
795+
[builtins fixtures/isinstance.py]

mypy/test/data/fixtures/isinstance.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
from typing import builtinclass
22

3-
@builtinclass
43
class object:
54
def __init__(self) -> None: pass
65

7-
@builtinclass
86
class type:
97
def __init__(self, x) -> None: pass
108

@@ -13,9 +11,7 @@ class function: pass
1311

1412
def isinstance(x: object, t: type) -> bool: pass
1513

16-
@builtinclass
1714
class int: pass
18-
@builtinclass
15+
class float: pass
1916
class bool(int): pass
20-
@builtinclass
2117
class str: pass

0 commit comments

Comments
 (0)