Skip to content

Commit e242b5e

Browse files
committed
Narrow isinstance checks to Never
1 parent c62093e commit e242b5e

18 files changed

+109
-141
lines changed

mypy/checker.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8000,9 +8000,7 @@ def conditional_types_to_typemaps(
80008000
maps: list[TypeMap] = []
80018001
for typ in (yes_type, no_type):
80028002
proper_type = get_proper_type(typ)
8003-
if isinstance(proper_type, UninhabitedType):
8004-
maps.append(None)
8005-
elif proper_type is None:
8003+
if proper_type is None:
80068004
maps.append({})
80078005
else:
80088006
assert typ is not None

mypy/checkexpr.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3548,9 +3548,7 @@ def visit_op_expr(self, e: OpExpr) -> Type:
35483548
allow_reverse=False,
35493549
)
35503550
else:
3551-
# TODO: fix this bug with enum narrowing
3552-
# somehow the `use_reverse is UseReverse.ALWAYS` doesn't narrow.
3553-
assert_never(use_reverse) # type: ignore[arg-type]
3551+
assert_never(use_reverse)
35543552
e.method_type = method_type
35553553
return result
35563554
else:

test-data/unit/check-enum.test

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -888,9 +888,8 @@ elif x is Foo.B:
888888
elif x is Foo.C:
889889
reveal_type(x) # N: Revealed type is "Literal[__main__.Foo.C]"
890890
else:
891-
# TODO: this should narrow to Never
892-
reveal_type(x) # E: Statement is unreachable \
893-
# N: Revealed type is "Literal[__main__.Foo.C]"
891+
reveal_type(x) # N: Revealed type is "Never"
892+
_ = "unreachable" # E: Statement is unreachable
894893
reveal_type(x) # N: Revealed type is "Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B], Literal[__main__.Foo.C]]"
895894

896895
if Foo.A is x:
@@ -900,8 +899,8 @@ elif Foo.B is x:
900899
elif Foo.C is x:
901900
reveal_type(x) # N: Revealed type is "Literal[__main__.Foo.C]"
902901
else:
903-
reveal_type(x) # E: Statement is unreachable \
904-
# N: Revealed type is "Literal[__main__.Foo.C]"
902+
reveal_type(x) # N: Revealed type is "Never"
903+
_ = "unreachable" # E: Statement is unreachable
905904
reveal_type(x) # N: Revealed type is "Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B], Literal[__main__.Foo.C]]"
906905

907906
y: Foo
@@ -912,8 +911,7 @@ elif y is Foo.B:
912911
elif y is Foo.C:
913912
reveal_type(y) # N: Revealed type is "Literal[__main__.Foo.C]"
914913
else:
915-
reveal_type(y) # E: Statement is unreachable \
916-
# N: Revealed type is "Literal[__main__.Foo.C]"
914+
reveal_type(y) # N: Revealed type is "Never"
917915
reveal_type(y) # N: Revealed type is "__main__.Foo"
918916

919917
if Foo.A is y:
@@ -923,8 +921,8 @@ elif Foo.B is y:
923921
elif Foo.C is y:
924922
reveal_type(y) # N: Revealed type is "Literal[__main__.Foo.C]"
925923
else:
926-
reveal_type(y) # E: Statement is unreachable \
927-
# N: Revealed type is "Literal[__main__.Foo.C]"
924+
reveal_type(y) # N: Revealed type is "Never"
925+
_ = "unreachable" # E: Statement is unreachable
928926
reveal_type(y) # N: Revealed type is "__main__.Foo"
929927
[builtins fixtures/bool.pyi]
930928

@@ -946,8 +944,7 @@ if x is Foo.A:
946944
elif x is Foo.B:
947945
reveal_type(x) # N: Revealed type is "Literal[__main__.Foo.B]"
948946
else:
949-
reveal_type(x) # E: Statement is unreachable \
950-
# N: Revealed type is "Literal[__main__.Foo.B]"
947+
reveal_type(x) # N: Revealed type is "Never"
951948

952949
class Bar(Enum):
953950
__order__ = "A B"
@@ -962,26 +959,23 @@ if y is Bar.A:
962959
elif y is Bar.B:
963960
reveal_type(y) # N: Revealed type is "Literal[__main__.Bar.B]"
964961
else:
965-
reveal_type(y) # E: Statement is unreachable \
966-
# N: Revealed type is "Literal[__main__.Bar.B]"
962+
reveal_type(y) # N: Revealed type is "Never"
967963

968964
x2: Foo
969965
if x2 is Foo.A:
970966
reveal_type(x2) # N: Revealed type is "Literal[__main__.Foo.A]"
971967
elif x2 is Foo.B:
972968
reveal_type(x2) # N: Revealed type is "Literal[__main__.Foo.B]"
973969
else:
974-
reveal_type(x2) # E: Statement is unreachable \
975-
# N: Revealed type is "Literal[__main__.Foo.B]"
970+
reveal_type(x2) # N: Revealed type is "Never"
976971

977972
y2: Bar
978973
if y2 is Bar.A:
979974
reveal_type(y2) # N: Revealed type is "Literal[__main__.Bar.A]"
980975
elif y2 is Bar.B:
981976
reveal_type(y2) # N: Revealed type is "Literal[__main__.Bar.B]"
982977
else:
983-
reveal_type(y2) # E: Statement is unreachable \
984-
# N: Revealed type is "Literal[__main__.Bar.B]"
978+
reveal_type(y2) # N: Revealed type is "Never"
985979
[builtins fixtures/tuple.pyi]
986980

987981
[case testEnumReachabilityChecksIndirect]
@@ -1039,17 +1033,17 @@ if y is z:
10391033
reveal_type(z) # N: Revealed type is "Literal[__main__.Foo.A]?"
10401034
accepts_foo_a(z)
10411035
else:
1042-
reveal_type(y) # E: Statement is unreachable \
1043-
# N: Revealed type is "Literal[__main__.Foo.A]"
1044-
reveal_type(z) # N: Revealed type is "Literal[__main__.Foo.A]?"
1036+
reveal_type(y) # N: Revealed type is "Never"
1037+
reveal_type(z) # E: Statement is unreachable \
1038+
# N: Revealed type is "Literal[__main__.Foo.A]?"
10451039
if z is y:
10461040
reveal_type(y) # N: Revealed type is "Literal[__main__.Foo.A]"
10471041
reveal_type(z) # N: Revealed type is "Literal[__main__.Foo.A]?"
10481042
accepts_foo_a(z)
10491043
else:
1050-
reveal_type(y) # E: Statement is unreachable \
1044+
reveal_type(y) # E: Statement is unreachable \
10511045
# N: Revealed type is "Literal[__main__.Foo.A]"
1052-
reveal_type(z) # N: Revealed type is "Literal[__main__.Foo.A]?"
1046+
reveal_type(z) # N: Revealed type is "Never"
10531047
[builtins fixtures/bool.pyi]
10541048

10551049
[case testEnumReachabilityNoNarrowingForUnionMessiness]
@@ -2305,8 +2299,7 @@ if e == MyEnum.A:
23052299
elif e == MyEnum.B:
23062300
reveal_type(e) # N: Revealed type is "Literal[__main__.MyEnum.B]"
23072301
else:
2308-
reveal_type(e) # E: Statement is unreachable \
2309-
# N: Revealed type is "Literal[__main__.MyEnum.B]"
2302+
reveal_type(e) # N: Revealed type is "Never"
23102303
[builtins fixtures/dict.pyi]
23112304

23122305

test-data/unit/check-errorcodes.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ g = 3 if True else 4 # E: If condition is always true [redu
805805
h = 3 if False else 4 # E: If condition is always false [redundant-expr]
806806
i = [x for x in lst if True] # E: If condition in comprehension is always true [redundant-expr]
807807
j = [x for x in lst if False] # E: If condition in comprehension is always false [redundant-expr]
808-
k = [x for x in lst if isinstance(x, int) or foo()] # E: If condition in comprehension is always true [redundant-expr]
808+
k = [x for x in lst if isinstance(x, int) or foo()]
809809
[builtins fixtures/isinstancelist.pyi]
810810

811811
[case testRedundantExprTruthiness]

test-data/unit/check-expressions.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,7 @@ z = x.append(y) if bool() else x.append(y) # E: "append" of "list" does not retu
15061506
from typing import TypeVar
15071507
T = TypeVar("T", int, str)
15081508
def foo(x: T) -> T:
1509-
return x + 1 if isinstance(x, int) else x + "a"
1509+
return x + 1 if isinstance(x, int) else x + "a" # E: Unsupported left operand type for + ("Never")
15101510
[builtins fixtures/isinstancelist.pyi]
15111511

15121512
-- Special cases

test-data/unit/check-incremental.test

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5415,7 +5415,9 @@ reveal_type(z)
54155415
[out]
54165416
tmp/c.py:2: note: Revealed type is "a.<subclass of "a.A" and "a.B">"
54175417
[out2]
5418-
tmp/c.py:2: note: Revealed type is "a.A"
5418+
tmp/a.py:7: error: Need type annotation for "y"
5419+
tmp/b.py:2: error: Need type annotation for "z"
5420+
tmp/c.py:2: note: Revealed type is "Never"
54195421

54205422
[case testIsInstanceAdHocIntersectionIncrementalUnreachableToIntersection]
54215423
import c
@@ -5446,7 +5448,9 @@ from b import z
54465448
reveal_type(z)
54475449
[builtins fixtures/isinstance.pyi]
54485450
[out]
5449-
tmp/c.py:2: note: Revealed type is "a.A"
5451+
tmp/a.py:7: error: Need type annotation for "y"
5452+
tmp/b.py:2: error: Need type annotation for "z"
5453+
tmp/c.py:2: note: Revealed type is "Never"
54505454
[out2]
54515455
tmp/c.py:2: note: Revealed type is "a.<subclass of "a.A" and "a.B">"
54525456

test-data/unit/check-isinstance.test

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -734,11 +734,9 @@ while bool():
734734
x + 1
735735
break
736736
# TODO: only report unreachability once
737-
# TODO: narrow x to Never
738-
elif isinstance(x, str): # E: Statement is unreachable \
739-
# E: Subclass of "int" and "str" cannot exist: would have incompatible method signatures
737+
elif isinstance(x, str): # E: Statement is unreachable
740738
_ = "unreachable" # E: Statement is unreachable
741-
x + 'a' # E: Unsupported operand types for + ("int" and "str")
739+
x + 'a' # E: Unsupported left operand type for + ("Never")
742740
break
743741
_ = "unreachable" # E: Statement is unreachable
744742
x + [1] # E: Unsupported operand types for + ("int" and "List[int]") \
@@ -1275,7 +1273,8 @@ if isinstance(y, int) and isinstance(x, B): # E: Subclass of "A" and "int" cann
12751273
# E: Right operand of "and" is never evaluated
12761274
_ = "unreachable" # E: Statement is unreachable
12771275
if isinstance(y, int) and y > 42: # E: Subclass of "A" and "int" cannot exist: would have incompatible method signatures \
1278-
# E: Right operand of "and" is never evaluated
1276+
# E: Right operand of "and" is never evaluated \
1277+
# E: Unsupported left operand type for > ("Never")
12791278
_ = "unreachable" # E: Statement is unreachable
12801279
[builtins fixtures/isinstancelist.pyi]
12811280

@@ -1370,9 +1369,9 @@ x = B()
13701369
if isinstance(x, A):
13711370
reveal_type(x) # N: Revealed type is "__main__.B"
13721371
if not isinstance(x, A):
1373-
reveal_type(x) # E: Statement is unreachable \
1374-
# N: Revealed type is "__main__.B"
1375-
x = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")
1372+
reveal_type(x) # N: Revealed type is "Never"
1373+
x = A() # E: Statement is unreachable \
1374+
# E: Incompatible types in assignment (expression has type "A", variable has type "B")
13761375
reveal_type(x) # N: Revealed type is "__main__.B"
13771376
[builtins fixtures/isinstance.pyi]
13781377

@@ -1537,8 +1536,7 @@ from typing import Type, Sequence, Union
15371536

15381537
x: Type[str]
15391538
if issubclass(x, int): # E: Subclass of "str" and "int" cannot exist: would have incompatible method signatures
1540-
reveal_type(x) # E: Statement is unreachable \
1541-
# N: Revealed type is "Type[builtins.str]"
1539+
reveal_type(x) # N: Revealed type is "Type[builtins.str]"
15421540

15431541
class X: pass
15441542
class Y(X): pass
@@ -1548,8 +1546,7 @@ a: Union[Type[Y], Type[Z]]
15481546
if issubclass(a, X):
15491547
reveal_type(a) # N: Revealed type is "Union[Type[__main__.Y], Type[__main__.Z]]"
15501548
else:
1551-
reveal_type(a) # E: Statement is unreachable \
1552-
# N: Revealed type is "Union[Type[__main__.Y], Type[__main__.Z]]"
1549+
reveal_type(a) # N: Revealed type is "Union[Type[__main__.Y], Type[__main__.Z]]"
15531550
[builtins fixtures/isinstancelist.pyi]
15541551

15551552
[case testIssubclasDestructuringUnions1]
@@ -1891,8 +1888,7 @@ def f(x: Type[int]) -> None:
18911888
if isinstance(x, type):
18921889
reveal_type(x) # N: Revealed type is "Type[builtins.int]"
18931890
else:
1894-
reveal_type(x) # E: Statement is unreachable \
1895-
# N: Revealed type is "Type[builtins.int]"
1891+
reveal_type(x) # N: Revealed type is "Never"
18961892
reveal_type(x) # N: Revealed type is "Type[builtins.int]"
18971893
[builtins fixtures/isinstance.pyi]
18981894

@@ -2392,17 +2388,15 @@ class C:
23922388
class Example(A, B): pass # E: Definition of "f" in base class "A" is incompatible with definition in base class "B"
23932389
x: A
23942390
if isinstance(x, B): # E: Subclass of "A" and "B" cannot exist: would have incompatible method signatures
2395-
reveal_type(x) # E: Statement is unreachable \
2396-
# N: Revealed type is "__main__.A"
2391+
reveal_type(x) # N: Revealed type is "Never"
23972392
else:
23982393
reveal_type(x) # N: Revealed type is "__main__.A"
23992394

24002395
y: C
24012396
if isinstance(y, B):
24022397
reveal_type(y) # N: Revealed type is "__main__.<subclass of "__main__.C" and "__main__.B">"
24032398
if isinstance(y, A): # E: Subclass of "C", "B", and "A" cannot exist: would have incompatible method signatures
2404-
reveal_type(y) # E: Statement is unreachable \
2405-
# N: Revealed type is "__main__.<subclass of "__main__.C" and "__main__.B">"
2399+
reveal_type(y) # N: Revealed type is "Never"
24062400
[builtins fixtures/isinstance.pyi]
24072401

24082402
[case testIsInstanceAdHocIntersectionReversed]
@@ -2431,7 +2425,7 @@ class B:
24312425
def t0(self) -> None:
24322426
if isinstance(self, A0): # E: Subclass of "B" and "A0" cannot exist: would have incompatible method signatures
24332427
x0: Literal[0] = self.f() # E: Statement is unreachable \
2434-
# E: Incompatible types in assignment (expression has type "Literal[1, 2]", variable has type "Literal[0]")
2428+
# E: "Never" has no attribute "f"
24352429

24362430
def t1(self) -> None:
24372431
if isinstance(self, A1):
@@ -2468,8 +2462,7 @@ class B:
24682462

24692463
x: A[int]
24702464
if isinstance(x, B): # E: Subclass of "A[int]" and "B" cannot exist: would have incompatible method signatures
2471-
reveal_type(x) # E: Statement is unreachable \
2472-
# N: Revealed type is "__main__.A[builtins.int]"
2465+
reveal_type(x) # N: Revealed type is "Never"
24732466
else:
24742467
reveal_type(x) # N: Revealed type is "__main__.A[builtins.int]"
24752468

@@ -2509,29 +2502,28 @@ def f1(x: T1) -> T1:
25092502
# N: Revealed type is "__main__.<subclass of "__main__.B" and "__main__.A">"
25102503
else:
25112504
reveal_type(x) # N: Revealed type is "__main__.A" \
2512-
# N: Revealed type is "__main__.<subclass of "__main__.B" and "__main__.A">"
2505+
# N: Revealed type is "Never"
25132506
else:
2514-
reveal_type(x) # N: Revealed type is "__main__.A" \
2507+
reveal_type(x) # N: Revealed type is "Never" \
25152508
# N: Revealed type is "__main__.B"
25162509
return x
25172510

25182511
T2 = TypeVar('T2', B, C)
25192512
def f2(x: T2) -> T2:
25202513
if isinstance(x, B):
25212514
reveal_type(x) # N: Revealed type is "__main__.B" \
2522-
# N: Revealed type is "__main__.C"
2515+
# N: Revealed type is "Never"
25232516
# Note: even though --warn-unreachable is set, we don't report
25242517
# errors for the below: we don't yet have a way of filtering out
25252518
# reachability errors that occur for only one variation of the
25262519
# TypeVar yet.
25272520
if isinstance(x, C):
2528-
reveal_type(x) # N: Revealed type is "__main__.B" \
2529-
# N: Revealed type is "__main__.C"
2521+
reveal_type(x) # N: Revealed type is "Never"
25302522
else:
25312523
reveal_type(x) # N: Revealed type is "__main__.B" \
2532-
# N: Revealed type is "__main__.C"
2524+
# N: Revealed type is "Never"
25332525
else:
2534-
reveal_type(x) # N: Revealed type is "__main__.B" \
2526+
reveal_type(x) # N: Revealed type is "Never" \
25352527
# N: Revealed type is "__main__.C"
25362528
return x
25372529

@@ -2648,8 +2640,7 @@ class B(Y, X): pass
26482640

26492641
foo: A
26502642
if isinstance(foo, B): # E: Subclass of "A" and "B" cannot exist: would have inconsistent method resolution order
2651-
reveal_type(foo) # E: Statement is unreachable \
2652-
# N: Revealed type is "__main__.A"
2643+
reveal_type(foo) # N: Revealed type is "Never"
26532644
[builtins fixtures/isinstance.pyi]
26542645

26552646
[case testIsInstanceAdHocIntersectionAmbiguousClass]
@@ -2683,8 +2674,7 @@ x: Type[A]
26832674
if issubclass(x, B):
26842675
reveal_type(x) # N: Revealed type is "Type[__main__.<subclass of "__main__.A" and "__main__.B">]"
26852676
if issubclass(x, C): # E: Subclass of "A", "B", and "C" cannot exist: would have incompatible method signatures
2686-
reveal_type(x) # E: Statement is unreachable \
2687-
# N: Revealed type is "Type[__main__.<subclass of "__main__.A" and "__main__.B">]"
2677+
reveal_type(x) # N: Revealed type is "Type[__main__.<subclass of "__main__.A" and "__main__.B">]"
26882678
else:
26892679
reveal_type(x) # N: Revealed type is "Type[__main__.<subclass of "__main__.A" and "__main__.B">]"
26902680
else:

0 commit comments

Comments
 (0)