Add Never and assert_never (#1060)

Backport of python/cpython#30842, with additional tests from @sobolevn's python/cpython#31222.
diff --git a/typing_extensions/CHANGELOG b/typing_extensions/CHANGELOG
index c96bd34..092e04a 100644
--- a/typing_extensions/CHANGELOG
+++ b/typing_extensions/CHANGELOG
@@ -1,5 +1,6 @@
 # Release 4.x.x
 
+- Add `Never` and `assert_never`. Backport from bpo-46475.
 - `ParamSpec` args and kwargs are now equal to themselves. Backport from
   bpo-46676. Patch by Gregory Beauregard (@GBeauregard).
 - Add `reveal_type`. Backport from bpo-46414.
diff --git a/typing_extensions/README.rst b/typing_extensions/README.rst
index 961bdf9..a83ed3c 100644
--- a/typing_extensions/README.rst
+++ b/typing_extensions/README.rst
@@ -43,6 +43,8 @@
 
 - In ``typing`` since Python 3.11
 
+  - ``assert_never``
+  - ``Never``
   - ``reveal_type``
   - ``Self`` (see PEP 673)
 
diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py
index 4e1d95f..9111688 100644
--- a/typing_extensions/src/test_typing_extensions.py
+++ b/typing_extensions/src/test_typing_extensions.py
@@ -12,7 +12,7 @@
 from unittest import TestCase, main, skipUnless, skipIf
 from test import ann_module, ann_module2, ann_module3
 import typing
-from typing import TypeVar, Optional, Union
+from typing import TypeVar, Optional, Union, Any
 from typing import T, KT, VT  # Not in __all__.
 from typing import Tuple, List, Dict, Iterable, Iterator, Callable
 from typing import Generic, NamedTuple
@@ -22,7 +22,7 @@
 from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard
 from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired
 from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload, final, is_typeddict
-from typing_extensions import dataclass_transform, reveal_type
+from typing_extensions import dataclass_transform, reveal_type, Never, assert_never
 try:
     from typing_extensions import get_type_hints
 except ImportError:
@@ -70,19 +70,50 @@
     pass
 
 
-class NoReturnTests(BaseTestCase):
+class BottomTypeTestsMixin:
+    bottom_type: ClassVar[Any]
 
-    def test_noreturn_instance_type_error(self):
-        with self.assertRaises(TypeError):
-            isinstance(42, NoReturn)
+    def test_equality(self):
+        self.assertEqual(self.bottom_type, self.bottom_type)
+        self.assertIs(self.bottom_type, self.bottom_type)
+        self.assertNotEqual(self.bottom_type, None)
 
-    def test_noreturn_subclass_type_error_1(self):
-        with self.assertRaises(TypeError):
-            issubclass(Employee, NoReturn)
+    @skipUnless(PEP_560, "Python 3.7+ required")
+    def test_get_origin(self):
+        from typing_extensions import get_origin
+        self.assertIs(get_origin(self.bottom_type), None)
 
-    def test_noreturn_subclass_type_error_2(self):
+    def test_instance_type_error(self):
         with self.assertRaises(TypeError):
-            issubclass(NoReturn, Employee)
+            isinstance(42, self.bottom_type)
+
+    def test_subclass_type_error(self):
+        with self.assertRaises(TypeError):
+            issubclass(Employee, self.bottom_type)
+        with self.assertRaises(TypeError):
+            issubclass(NoReturn, self.bottom_type)
+
+    def test_not_generic(self):
+        with self.assertRaises(TypeError):
+            self.bottom_type[int]
+
+    def test_cannot_subclass(self):
+        with self.assertRaises(TypeError):
+            class A(self.bottom_type):
+                pass
+        with self.assertRaises(TypeError):
+            class A(type(self.bottom_type)):
+                pass
+
+    def test_cannot_instantiate(self):
+        with self.assertRaises(TypeError):
+            self.bottom_type()
+        with self.assertRaises(TypeError):
+            type(self.bottom_type)()
+
+
+class NoReturnTests(BottomTypeTestsMixin, BaseTestCase):
+    bottom_type = NoReturn
 
     def test_repr(self):
         if hasattr(typing, 'NoReturn'):
@@ -90,23 +121,43 @@
         else:
             self.assertEqual(repr(NoReturn), 'typing_extensions.NoReturn')
 
-    def test_not_generic(self):
-        with self.assertRaises(TypeError):
-            NoReturn[int]
+    def test_get_type_hints(self):
+        def some(arg: NoReturn) -> NoReturn: ...
+        def some_str(arg: 'NoReturn') -> 'typing.NoReturn': ...
 
-    def test_cannot_subclass(self):
-        with self.assertRaises(TypeError):
-            class A(NoReturn):
-                pass
-        with self.assertRaises(TypeError):
-            class A(type(NoReturn)):
-                pass
+        expected = {'arg': NoReturn, 'return': NoReturn}
+        for target in [some, some_str]:
+            with self.subTest(target=target):
+                self.assertEqual(gth(target), expected)
 
-    def test_cannot_instantiate(self):
-        with self.assertRaises(TypeError):
-            NoReturn()
-        with self.assertRaises(TypeError):
-            type(NoReturn)()
+    def test_not_equality(self):
+        self.assertNotEqual(NoReturn, Never)
+        self.assertNotEqual(Never, NoReturn)
+
+
+class NeverTests(BottomTypeTestsMixin, BaseTestCase):
+    bottom_type = Never
+
+    def test_repr(self):
+        if hasattr(typing, 'Never'):
+            self.assertEqual(repr(Never), 'typing.Never')
+        else:
+            self.assertEqual(repr(Never), 'typing_extensions.Never')
+
+    def test_get_type_hints(self):
+        def some(arg: Never) -> Never: ...
+        def some_str(arg: 'Never') -> 'typing_extensions.Never': ...
+
+        expected = {'arg': Never, 'return': Never}
+        for target in [some, some_str]:
+            with self.subTest(target=target):
+                self.assertEqual(gth(target), expected)
+
+
+class AssertNeverTests(BaseTestCase):
+    def test_exception(self):
+        with self.assertRaises(AssertionError):
+            assert_never(None)
 
 
 class ClassVarTests(BaseTestCase):
diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py
index 27eaff0..b67efd0 100644
--- a/typing_extensions/src/typing_extensions.py
+++ b/typing_extensions/src/typing_extensions.py
@@ -70,6 +70,7 @@
 
     # One-off things.
     'Annotated',
+    'assert_never',
     'dataclass_transform',
     'final',
     'IntVar',
@@ -85,6 +86,7 @@
     'TypeAlias',
     'TypeGuard',
     'TYPE_CHECKING',
+    'Never',
     'NoReturn',
     'Required',
     'NotRequired',
@@ -2107,9 +2109,8 @@
 
     TypeGuard = _TypeGuard(_root=True)
 
-if hasattr(typing, "Self"):
-    Self = typing.Self
-elif sys.version_info[:2] >= (3, 7):
+
+if sys.version_info[:2] >= (3, 7):
     # Vendored from cpython typing._SpecialFrom
     class _SpecialForm(typing._Final, _root=True):
         __slots__ = ('_name', '__doc__', '_getitem')
@@ -2153,6 +2154,10 @@
         def __getitem__(self, parameters):
             return self._getitem(self, parameters)
 
+
+if hasattr(typing, "Self"):
+    Self = typing.Self
+elif sys.version_info[:2] >= (3, 7):
     @_SpecialForm
     def Self(self, params):
         """Used to spell the type of "self" in classes.
@@ -2195,6 +2200,69 @@
     Self = _Self(_root=True)
 
 
+if hasattr(typing, "Never"):
+    Never = typing.Never
+elif sys.version_info[:2] >= (3, 7):
+    @_SpecialForm
+    def Never(self, params):
+        """The bottom type, a type that has no members.
+
+        This can be used to define a function that should never be
+        called, or a function that never returns::
+
+            from typing_extensions import Never
+
+            def never_call_me(arg: Never) -> None:
+                pass
+
+            def int_or_str(arg: int | str) -> None:
+                never_call_me(arg)  # type checker error
+                match arg:
+                    case int():
+                        print("It's an int")
+                    case str():
+                        print("It's a str")
+                    case _:
+                        never_call_me(arg)  # ok, arg is of type Never
+
+        """
+
+        raise TypeError(f"{self} is not subscriptable")
+else:
+    class _Never(typing._FinalTypingBase, _root=True):
+        """The bottom type, a type that has no members.
+
+        This can be used to define a function that should never be
+        called, or a function that never returns::
+
+            from typing_extensions import Never
+
+            def never_call_me(arg: Never) -> None:
+                pass
+
+            def int_or_str(arg: int | str) -> None:
+                never_call_me(arg)  # type checker error
+                match arg:
+                    case int():
+                        print("It's an int")
+                    case str():
+                        print("It's a str")
+                    case _:
+                        never_call_me(arg)  # ok, arg is of type Never
+
+        """
+
+        __slots__ = ()
+
+        def __instancecheck__(self, obj):
+            raise TypeError(f"{self} cannot be used with isinstance().")
+
+        def __subclasscheck__(self, cls):
+            raise TypeError(f"{self} cannot be used with issubclass().")
+
+    Never = _Never(_root=True)
+
+
 if hasattr(typing, 'Required'):
     Required = typing.Required
     NotRequired = typing.NotRequired
@@ -2377,6 +2445,32 @@
         return __obj
 
 
+if hasattr(typing, "assert_never"):
+    assert_never = typing.assert_never
+else:
+    def assert_never(__arg: Never) -> Never:
+        """Assert to the type checker that a line of code is unreachable.
+
+        Example::
+
+            def int_or_str(arg: int | str) -> None:
+                match arg:
+                    case int():
+                        print("It's an int")
+                    case str():
+                        print("It's a str")
+                    case _:
+                        assert_never(arg)
+
+        If a type checker finds that a call to assert_never() is
+        reachable, it will emit an error.
+
+        At runtime, this throws an exception when called.
+
+        """
+        raise AssertionError("Expected code to be unreachable")
+
+
 if hasattr(typing, 'dataclass_transform'):
     dataclass_transform = typing.dataclass_transform
 else: