diff --git a/stdlib/@tests/test_cases/builtins/check_bool.py b/stdlib/@tests/test_cases/builtins/check_bool.py new file mode 100644 index 000000000000..25f83c98e901 --- /dev/null +++ b/stdlib/@tests/test_cases/builtins/check_bool.py @@ -0,0 +1,20 @@ +from typing_extensions import Literal, assert_type + +assert_type(bool(), Literal[False]) +assert_type(bool(False), Literal[False]) +assert_type(bool(True), Literal[True]) +assert_type(bool(42), bool) + + +class Truthy: + def __bool__(self) -> Literal[True]: + return True + + +class Falsy: + def __bool__(self) -> Literal[False]: + return False + + +assert_type(bool(Truthy()), Literal[True]) +assert_type(bool(Falsy()), Literal[False]) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 416d793de61c..97d08dc2ce65 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -966,9 +966,24 @@ class memoryview(Sequence[_I]): if sys.version_info >= (3, 14): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... +class _Truthy(Protocol): + def __bool__(self) -> Literal[True]: ... + +class _Falsy(Protocol): + def __bool__(self) -> Literal[False]: ... + @final class bool(int): - def __new__(cls, o: object = False, /) -> Self: ... + @overload + def __new__(cls, o: _Truthy, /) -> Literal[True]: ... + @overload + def __new__(cls, o: _Falsy = False, /) -> Literal[False]: ... + @overload + def __new__(cls, o: object, /) -> Self: ... + @overload + def __bool__(self: Literal[True]) -> Literal[True]: ... + @overload + def __bool__(self: Literal[False]) -> Literal[False]: ... # The following overloads could be represented more elegantly with a TypeVar("_B", bool, int), # however mypy has a bug regarding TypeVar constraints (https://github.com/python/mypy/issues/11880). @overload