Skip to content

Commit 3ac5a7f

Browse files
committed
Don't consider 'object' always truthy
There are two reasons I'm proposing this change. First, we know that many subclasses of 'object' can be falsy. Second, mypy sometimes simplifies `object | Any` into just `object`. The latter was considered always truthy, while the prior one wasn't. Now both of them are treated consistently. An alternative fix would be to not simplify unions like `object | Any`, but this seems a bit ad hoc. Fixes #14480. This doesn't just fix the regression but fixes a more general issue.
1 parent dcf910e commit 3ac5a7f

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

mypy/checker.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5151,6 +5151,7 @@ def _is_truthy_type(self, t: ProperType) -> bool:
51515151
and bool(t.type)
51525152
and not t.type.has_readable_member("__bool__")
51535153
and not t.type.has_readable_member("__len__")
5154+
and t.type.fullname != "builtins.object"
51545155
)
51555156
or isinstance(t, FunctionLike)
51565157
or (

test-data/unit/check-errorcodes.test

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -803,12 +803,15 @@ from typing_extensions import TypedDict
803803

804804
Foo = TypedDict("Bar", {}) # E: First argument "Bar" to TypedDict() does not match variable name "Foo" [name-match]
805805
[builtins fixtures/dict.pyi]
806+
806807
[case testTruthyBool]
807808
# flags: --enable-error-code truthy-bool
808-
from typing import List, Union
809+
from typing import List, Union, Any
809810

810811
class Foo:
811812
pass
813+
class Bar:
814+
pass
812815

813816
foo = Foo()
814817
if foo: # E: "__main__.foo" has type "Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool]
@@ -836,15 +839,30 @@ if good_union:
836839
if not good_union:
837840
pass
838841

839-
bad_union: Union[Foo, object] = Foo()
840-
if bad_union: # E: "__main__.bad_union" has type "Union[Foo, object]" of which no members implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool]
842+
bad_union: Union[Foo, Bar] = Foo()
843+
if bad_union: # E: "__main__.bad_union" has type "Union[Foo, Bar]" of which no members implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool]
844+
pass
845+
if not bad_union: # E: "__main__.bad_union" has type "Union[Foo, Bar]" of which no members implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool]
846+
pass
847+
848+
# 'object' is special and is treated as potentially falsy
849+
obj: object = Foo()
850+
if obj:
841851
pass
842-
if not bad_union: # E: "__main__.bad_union" has type "object" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool]
852+
if not obj:
843853
pass
844854

845855
lst: List[int] = []
846856
if lst:
847857
pass
858+
859+
a: Any
860+
if a:
861+
pass
862+
863+
any_or_object: Union[object, Any]
864+
if any_or_object:
865+
pass
848866
[builtins fixtures/list.pyi]
849867

850868
[case testTruthyFunctions]

0 commit comments

Comments
 (0)