diff --git a/mypy/typeops.py b/mypy/typeops.py index 828791333f36..0833b15a0bee 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -604,10 +604,12 @@ def is_singleton_type(typ: Type) -> bool: constructing two distinct instances of 100001. """ typ = get_proper_type(typ) - # TODO: Also make this return True if the type is a bool LiteralType. + # TODO: # Also make this return True if the type corresponds to ... (ellipsis) or NotImplemented? return ( - isinstance(typ, NoneType) or (isinstance(typ, LiteralType) and typ.is_enum_literal()) + isinstance(typ, NoneType) + or (isinstance(typ, LiteralType) + and (typ.is_enum_literal() or isinstance(typ.value, bool))) or (isinstance(typ, Instance) and typ.type.is_enum and len(get_enum_values(typ)) == 1) ) diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 45d4a625f8c7..a1d9685cc43d 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -984,3 +984,45 @@ if true_or_false: else: reveal_type(true_or_false) # N: Revealed type is 'Literal[False]' [builtins fixtures/primitives.pyi] + +[case testNarrowingLiteralIdentityCheck] +from typing import Union +from typing_extensions import Literal + +str_or_false: Union[Literal[False], str] + +if str_or_false is not False: + reveal_type(str_or_false) # N: Revealed type is 'builtins.str' +else: + reveal_type(str_or_false) # N: Revealed type is 'Literal[False]' + +if str_or_false is False: + reveal_type(str_or_false) # N: Revealed type is 'Literal[False]' +else: + reveal_type(str_or_false) # N: Revealed type is 'builtins.str' + +str_or_true: Union[Literal[True], str] + +if str_or_true is True: + reveal_type(str_or_true) # N: Revealed type is 'Literal[True]' +else: + reveal_type(str_or_true) # N: Revealed type is 'builtins.str' + +if str_or_true is not True: + reveal_type(str_or_true) # N: Revealed type is 'builtins.str' +else: + reveal_type(str_or_true) # N: Revealed type is 'Literal[True]' + +str_or_bool_literal: Union[Literal[False], Literal[True], str] + +if str_or_bool_literal is not True: + reveal_type(str_or_bool_literal) # N: Revealed type is 'Union[Literal[False], builtins.str]' +else: + reveal_type(str_or_bool_literal) # N: Revealed type is 'Literal[True]' + +if str_or_bool_literal is not True and str_or_bool_literal is not False: + reveal_type(str_or_bool_literal) # N: Revealed type is 'builtins.str' +else: + reveal_type(str_or_bool_literal) # N: Revealed type is 'Union[Literal[False], Literal[True]]' + +[builtins fixtures/primitives.pyi]