Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions conformance/results/mypy/specialtypes_never.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ specialtypes_never.py:85: error: Incompatible types in assignment (expression ha
specialtypes_never.py:85: note: "list" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
specialtypes_never.py:85: note: Consider using "Sequence" instead, which is covariant
specialtypes_never.py:104: error: Incompatible return value type (got "ClassC[Never]", expected "ClassC[U]") [return-value]
specialtypes_never.py:121: error: Return statement in function which does not return [misc]
specialtypes_never.py:145: error: Incompatible return value type (got "list[Never]", expected "list[int]") [return-value]
specialtypes_never.py:145: note: "list" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
specialtypes_never.py:145: note: Consider using "Sequence" instead, which is covariant
"""
conformance_automated = "Pass"
errors_diff = """
Expand Down
2 changes: 2 additions & 0 deletions conformance/results/pyrefly/specialtypes_never.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ output = """
ERROR specialtypes_never.py:19:22-30: Function declared to return `NoReturn` but is missing an explicit `return` [bad-return]
ERROR specialtypes_never.py:85:21-22: `list[Never]` is not assignable to `list[int]` [bad-assignment]
ERROR specialtypes_never.py:104:12-27: Returned type `ClassC[Never]` is not assignable to declared return type `ClassC[U]` [bad-return]
ERROR specialtypes_never.py:121:12-13: Returned type `object` is not assignable to declared return type `Never` [bad-return]
ERROR specialtypes_never.py:145:12-13: Returned type `list[Never]` is not assignable to declared return type `list[int]` [bad-return]
"""
5 changes: 5 additions & 0 deletions conformance/results/pyright/specialtypes_never.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ specialtypes_never.py:85:21 - error: Type "list[Never]" is not assignable to dec
specialtypes_never.py:104:12 - error: Type "ClassC[Never]" is not assignable to return type "ClassC[U@func10]"
  "ClassC[Never]" is not assignable to "ClassC[U@func10]"
    Type parameter "T@ClassC" is invariant, but "Never" is not the same as "U@func10" (reportReturnType)
specialtypes_never.py:121:5 - error: Function with declared return type "NoReturn" cannot include a return statement (reportGeneralTypeIssues)
specialtypes_never.py:145:12 - error: Type "list[Never]" is not assignable to return type "list[int]"
  "list[Never]" is not assignable to "list[int]"
    Type parameter "_T@list" is invariant, but "Never" is not the same as "int"
    Consider switching from "list" to "Sequence" which is covariant (reportReturnType)
"""
conformance_automated = "Pass"
errors_diff = """
Expand Down
9 changes: 8 additions & 1 deletion conformance/results/ty/specialtypes_never.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
conformance_automated = "Pass"
conformant = "Partial"
notes = """
Does not flag `return <object>` in a function declared `-> Never` (line 121).
Does not flag `return list[Never]` where `list[int]` is expected (line 145).
"""
conformance_automated = "Partial"
errors_diff = """
Line 121: Expected 1 errors
Line 145: Expected 1 errors
"""
output = """
specialtypes_never.py:19:22: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Never`
Expand Down
4 changes: 4 additions & 0 deletions conformance/results/zuban/specialtypes_never.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ specialtypes_never.py:85: error: Incompatible types in assignment (expression ha
specialtypes_never.py:85: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
specialtypes_never.py:85: note: Consider using "Sequence" instead, which is covariant
specialtypes_never.py:104: error: Incompatible return value type (got "ClassC[Never]", expected "ClassC[U]") [return-value]
specialtypes_never.py:121: error: Return statement in function which does not return [misc]
specialtypes_never.py:145: error: Incompatible return value type (got "list[Never]", expected "list[int]") [return-value]
specialtypes_never.py:145: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
specialtypes_never.py:145: note: Consider using "Sequence" instead, which is covariant
"""
41 changes: 41 additions & 0 deletions conformance/tests/specialtypes_never.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,44 @@ class ClassC(Generic[T]):
def func10(x: U) -> ClassC[U]:
# Never is not compatible in an invariant context.
return ClassC[Never]() # E


# Never | T is equivalent to T — the union collapses.

type Alias1 = Never | int # Equivalent to int
type Alias2 = int | Never # Equivalent to int


def func11(x: Alias1) -> int:
return x # OK — Alias1 is int


# No type other than Never (and Any) is assignable to Never.


def func12(x: object) -> Never:
return x # E


def func13() -> Never:
raise RuntimeError("never") # OK


# type[Never] is valid and represents an uninhabitable class object.


def func14(cls: type[Never]) -> None:
pass


# Empty containers typed as list[Never] are assignable to list[T]
# only when T is used covariantly; list itself is invariant, so
# list[Never] is not assignable to list[int].


def func15() -> list[Never]:
return [] # OK


def func16(x: list[Never]) -> list[int]:
return x # E — list is invariant
67 changes: 65 additions & 2 deletions docs/spec/special-types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,77 @@ is unreachable and will behave accordingly::
---------

Since Python 3.11, the ``typing`` module contains a :term:`special form`
``Never``. It represents the bottom type, a type that represents the empty set
of Python objects.
``Never``. It represents the **bottom type**: the type that denotes the empty
set of Python objects. No Python object can be a runtime instance of
``Never``.

The ``Never`` type is equivalent to ``NoReturn``, which is discussed above.
The ``NoReturn`` type is conventionally used in return annotations of
functions, and ``Never`` is typically used in other locations, but the two
types are completely interchangeable.

Subtyping rules for ``Never``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Because ``Never`` is the bottom type, it is a :term:`subtype` of every fully
static type. This means that a value of type ``Never`` is :term:`assignable`
to a variable of any type ``T``::

from typing import Never

def f(x: Never) -> None:
v1: int = x # OK — Never is a subtype of int
v2: str = x # OK — Never is a subtype of str

No type other than ``Never`` itself (and :ref:`Any <any>`) is a subtype of
Comment thread
ashishpatel26 marked this conversation as resolved.
Outdated
Comment thread
ashishpatel26 marked this conversation as resolved.
Outdated
``Never``. In particular, ``object`` is *not* a subtype of ``Never``::

def g(x: object) -> Never:
return x # Error — object is not assignable to Never
Comment thread
ashishpatel26 marked this conversation as resolved.
Outdated

Because ``Never`` is a subtype of every type ``T``, the union ``Never | T`` is
Comment thread
ashishpatel26 marked this conversation as resolved.
Outdated
equivalent to ``T``::

from typing import Never, Union

type Alias = Never | int # Equivalent to int

Code following a call to a function that returns ``Never`` is unreachable.
Type checkers may suppress errors in unreachable blocks.

Using ``Never`` as a type argument
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``Never`` may appear as a type argument. When used with a covariant
type parameter, ``Container[Never]`` is a subtype of ``Container[T]`` for
every type ``T``, because ``Never`` is a subtype of every type. This is
useful to type an empty container whose element type is not yet known::

from typing import Never

def empty_list() -> list[Never]:
return []
Comment thread
ashishpatel26 marked this conversation as resolved.

When used with an invariant type parameter, the normal invariance rules
apply: ``Container[Never]`` is only assignable to ``Container[Never]``::

from typing import Generic, Never, TypeVar

T = TypeVar("T")

class Box(Generic[T]):
pass

def f() -> Box[int]:
return Box[Never]() # Error — Box is invariant in T

``type[Never]``
^^^^^^^^^^^^^^^^^

``type[Never]`` represents the class object for a type that has no instances.
Comment thread
ashishpatel26 marked this conversation as resolved.
Outdated
In practice this type is rarely useful directly, but it is the correct result
of narrowing a ``type[T]`` variable to an impossible branch.

.. _`numeric-promotions`:

Special cases for ``float`` and ``complex``
Expand Down