Skip to content

Commit abb1cc7

Browse files
authored
Uninhabited should have all attributes (#19300)
Although this can hide some mypy bugs, TBH this always bothered me as something conceptually wrong. The work on `checkmember` stuff inspired me to actually try it.
1 parent 23e6072 commit abb1cc7

File tree

3 files changed

+25
-0
lines changed

3 files changed

+25
-0
lines changed

mypy/checkexpr.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,10 @@ def check_call(
16711671
object_type,
16721672
original_type=callee,
16731673
)
1674+
elif isinstance(callee, UninhabitedType):
1675+
ret = UninhabitedType()
1676+
ret.ambiguous = callee.ambiguous
1677+
return callee, ret
16741678
else:
16751679
return self.msg.not_callable(callee, context), AnyType(TypeOfAny.from_error)
16761680

mypy/checkmember.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
TypeVarLikeType,
7070
TypeVarTupleType,
7171
TypeVarType,
72+
UninhabitedType,
7273
UnionType,
7374
get_proper_type,
7475
)
@@ -268,6 +269,10 @@ def _analyze_member_access(
268269
if not mx.suppress_errors:
269270
mx.msg.deleted_as_rvalue(typ, mx.context)
270271
return AnyType(TypeOfAny.from_error)
272+
elif isinstance(typ, UninhabitedType):
273+
attr_type = UninhabitedType()
274+
attr_type.ambiguous = typ.ambiguous
275+
return attr_type
271276
return report_missing_attribute(mx.original_type, typ, name, mx)
272277

273278

test-data/unit/check-unreachable-code.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,3 +1587,19 @@ x = 0 # not unreachable
15871587

15881588
f2: Callable[[], NoReturn] = lambda: foo()
15891589
x = 0 # not unreachable
1590+
1591+
[case testAttributeNoReturn]
1592+
# flags: --warn-unreachable
1593+
from typing import Optional, NoReturn, TypeVar
1594+
1595+
def foo() -> NoReturn:
1596+
raise
1597+
1598+
T = TypeVar("T")
1599+
def bar(x: Optional[list[T]] = None) -> T:
1600+
...
1601+
1602+
reveal_type(bar().attr) # N: Revealed type is "Never"
1603+
1 # not unreachable
1604+
reveal_type(foo().attr) # N: Revealed type is "Never"
1605+
1 # E: Statement is unreachable

0 commit comments

Comments
 (0)