Skip to content

Commit 6ff8091

Browse files
Add support for Never (#12153)
1 parent 234344b commit 6ff8091

File tree

6 files changed

+35
-9
lines changed

6 files changed

+35
-9
lines changed

mypy/semanal.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
from mypy.errorcodes import ErrorCode
9595
from mypy import message_registry, errorcodes as codes
9696
from mypy.types import (
97-
FunctionLike, UnboundType, TypeVarType, TupleType, UnionType, StarType,
97+
NEVER_NAMES, FunctionLike, UnboundType, TypeVarType, TupleType, UnionType, StarType,
9898
CallableType, Overloaded, Instance, Type, AnyType, LiteralType, LiteralValue,
9999
TypeTranslator, TypeOfAny, TypeType, NoneType, PlaceholderType, TPDICT_NAMES, ProperType,
100100
get_proper_type, get_proper_types, TypeAliasType, TypeVarLikeType,
@@ -2227,11 +2227,7 @@ def is_type_ref(self, rv: Expression, bare: bool = False) -> bool:
22272227
# Assignment color = Color['RED'] defines a variable, not an alias.
22282228
return not rv.node.is_enum
22292229
if isinstance(rv.node, Var):
2230-
return rv.node.fullname in (
2231-
'typing.NoReturn',
2232-
'typing_extensions.NoReturn',
2233-
'mypy_extensions.NoReturn',
2234-
)
2230+
return rv.node.fullname in NEVER_NAMES
22352231

22362232
if isinstance(rv, NameExpr):
22372233
n = self.lookup(rv.name, rv)

mypy/typeanal.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from mypy.messages import MessageBuilder, quote_type_string, format_type_bare
1313
from mypy.options import Options
1414
from mypy.types import (
15-
Type, UnboundType, TupleType, TypedDictType, UnionType, Instance, AnyType,
15+
NEVER_NAMES, Type, UnboundType, TupleType, TypedDictType, UnionType, Instance, AnyType,
1616
CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarType, SyntheticTypeVisitor,
1717
StarType, PartialType, EllipsisType, UninhabitedType, TypeType, CallableArgument,
1818
TypeQuery, union_items, TypeOfAny, LiteralType, RawExpressionType,
@@ -348,7 +348,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt
348348
self.fail('ClassVar[...] must have at most one type argument', t)
349349
return AnyType(TypeOfAny.from_error)
350350
return self.anal_type(t.args[0])
351-
elif fullname in ('mypy_extensions.NoReturn', 'typing.NoReturn'):
351+
elif fullname in NEVER_NAMES:
352352
return UninhabitedType(is_noreturn=True)
353353
elif fullname in LITERAL_TYPE_NAMES:
354354
return self.analyze_literal_type(t)

mypy/types.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@
132132
'typing_extensions.reveal_type',
133133
)
134134

135+
NEVER_NAMES: Final = (
136+
'typing.NoReturn',
137+
'typing_extensions.NoReturn',
138+
'mypy_extensions.NoReturn',
139+
'typing.Never',
140+
'typing_extensions.Never',
141+
)
142+
135143
# A placeholder used for Bogus[...] parameters
136144
_dummy: Final[Any] = object()
137145

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,26 @@ if False:
936936
reveal_type(x)
937937
[builtins fixtures/exception.pyi]
938938

939+
[case testNeverVariants]
940+
from typing import Never
941+
from typing_extensions import Never as TENever
942+
from typing import NoReturn
943+
from typing_extensions import NoReturn as TENoReturn
944+
from mypy_extensions import NoReturn as MENoReturn
945+
946+
bottom1: Never
947+
reveal_type(bottom1) # N: Revealed type is "<nothing>"
948+
bottom2: TENever
949+
reveal_type(bottom2) # N: Revealed type is "<nothing>"
950+
bottom3: NoReturn
951+
reveal_type(bottom3) # N: Revealed type is "<nothing>"
952+
bottom4: TENoReturn
953+
reveal_type(bottom4) # N: Revealed type is "<nothing>"
954+
bottom5: MENoReturn
955+
reveal_type(bottom5) # N: Revealed type is "<nothing>"
956+
957+
[builtins fixtures/tuple.pyi]
958+
939959
[case testUnreachableFlagExpressions]
940960
# flags: --warn-unreachable
941961
def foo() -> bool: ...

test-data/unit/lib-stub/typing.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Type = 0
2323
ClassVar = 0
2424
Final = 0
2525
NoReturn = 0
26+
Never = 0
2627
NewType = 0
2728
ParamSpec = 0
2829

test-data/unit/lib-stub/typing_extensions.pyi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import TypeVar, Any, Mapping, Iterator, NoReturn, Dict, Type
1+
from typing import TypeVar, Any, Mapping, Iterator, NoReturn as NoReturn, Dict, Type
22
from typing import TYPE_CHECKING as TYPE_CHECKING
33
from typing import NewType as NewType
44

@@ -27,6 +27,7 @@ Concatenate: _SpecialForm
2727
TypeAlias: _SpecialForm
2828

2929
TypeGuard: _SpecialForm
30+
Never: _SpecialForm
3031

3132
# Fallback type for all typed dicts (does not exist at runtime).
3233
class _TypedDict(Mapping[str, object]):

0 commit comments

Comments
 (0)