Skip to content

Commit 65e3a89

Browse files
authored
Add narrowing Union w/ bool Literal via identity check (#8821)
Fixes #8810
1 parent aaf9828 commit 65e3a89

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

mypy/typeops.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,10 +604,12 @@ def is_singleton_type(typ: Type) -> bool:
604604
constructing two distinct instances of 100001.
605605
"""
606606
typ = get_proper_type(typ)
607-
# TODO: Also make this return True if the type is a bool LiteralType.
607+
# TODO:
608608
# Also make this return True if the type corresponds to ... (ellipsis) or NotImplemented?
609609
return (
610-
isinstance(typ, NoneType) or (isinstance(typ, LiteralType) and typ.is_enum_literal())
610+
isinstance(typ, NoneType)
611+
or (isinstance(typ, LiteralType)
612+
and (typ.is_enum_literal() or isinstance(typ.value, bool)))
611613
or (isinstance(typ, Instance) and typ.type.is_enum and len(get_enum_values(typ)) == 1)
612614
)
613615

test-data/unit/check-narrowing.test

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,3 +984,45 @@ if true_or_false:
984984
else:
985985
reveal_type(true_or_false) # N: Revealed type is 'Literal[False]'
986986
[builtins fixtures/primitives.pyi]
987+
988+
[case testNarrowingLiteralIdentityCheck]
989+
from typing import Union
990+
from typing_extensions import Literal
991+
992+
str_or_false: Union[Literal[False], str]
993+
994+
if str_or_false is not False:
995+
reveal_type(str_or_false) # N: Revealed type is 'builtins.str'
996+
else:
997+
reveal_type(str_or_false) # N: Revealed type is 'Literal[False]'
998+
999+
if str_or_false is False:
1000+
reveal_type(str_or_false) # N: Revealed type is 'Literal[False]'
1001+
else:
1002+
reveal_type(str_or_false) # N: Revealed type is 'builtins.str'
1003+
1004+
str_or_true: Union[Literal[True], str]
1005+
1006+
if str_or_true is True:
1007+
reveal_type(str_or_true) # N: Revealed type is 'Literal[True]'
1008+
else:
1009+
reveal_type(str_or_true) # N: Revealed type is 'builtins.str'
1010+
1011+
if str_or_true is not True:
1012+
reveal_type(str_or_true) # N: Revealed type is 'builtins.str'
1013+
else:
1014+
reveal_type(str_or_true) # N: Revealed type is 'Literal[True]'
1015+
1016+
str_or_bool_literal: Union[Literal[False], Literal[True], str]
1017+
1018+
if str_or_bool_literal is not True:
1019+
reveal_type(str_or_bool_literal) # N: Revealed type is 'Union[Literal[False], builtins.str]'
1020+
else:
1021+
reveal_type(str_or_bool_literal) # N: Revealed type is 'Literal[True]'
1022+
1023+
if str_or_bool_literal is not True and str_or_bool_literal is not False:
1024+
reveal_type(str_or_bool_literal) # N: Revealed type is 'builtins.str'
1025+
else:
1026+
reveal_type(str_or_bool_literal) # N: Revealed type is 'Union[Literal[False], Literal[True]]'
1027+
1028+
[builtins fixtures/primitives.pyi]

0 commit comments

Comments
 (0)