Pep 593 py3 (#639)

This covers python 3.53 and above. I added a fair amount of tests.
diff --git a/typing_extensions/src_py3/test_typing_extensions.py b/typing_extensions/src_py3/test_typing_extensions.py
index e209a3f..57d77e6 100644
--- a/typing_extensions/src_py3/test_typing_extensions.py
+++ b/typing_extensions/src_py3/test_typing_extensions.py
@@ -11,13 +11,21 @@
 from typing import T, KT, VT  # Not in __all__.
 from typing import Tuple, List, Dict
 from typing import Generic
-from typing import get_type_hints
 from typing import no_type_check
 from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict
 try:
     from typing_extensions import Protocol, runtime
 except ImportError:
     pass
+try:
+    from typing_extensions import Annotated
+except ImportError:
+    pass
+try:
+    from typing_extensions import get_type_hints
+except ImportError:
+    from typing import get_type_hints
+
 import typing
 import typing_extensions
 import collections.abc as collections_abc
@@ -65,9 +73,6 @@
 # Protocols are hard to backport to the original version of typing 3.5.0
 HAVE_PROTOCOLS = sys.version_info[:3] != (3, 5, 0)
 
-# Not backported to older versions yet
-HAVE_ANNOTATED = PEP_560
-
 class BaseTestCase(TestCase):
     def assertIsSubclass(self, cls, class_or_tuple, msg=None):
         if not issubclass(cls, class_or_tuple):
@@ -1474,179 +1479,243 @@
             self.assertEqual(Options.__total__, False)
 
 
-if HAVE_ANNOTATED:
-    from typing_extensions import Annotated, get_type_hints
+@skipUnless(TYPING_3_5_3, "Python >= 3.5.3 required")
+class AnnotatedTests(BaseTestCase):
 
-    class AnnotatedTests(BaseTestCase):
+    def test_repr(self):
+        self.assertEqual(
+            repr(Annotated[int, 4, 5]),
+            "typing_extensions.Annotated[int, 4, 5]"
+        )
+        self.assertEqual(
+            repr(Annotated[List[int], 4, 5]),
+            "typing_extensions.Annotated[typing.List[int], 4, 5]"
+        )
 
-        def test_repr(self):
-            self.assertEqual(
-                repr(Annotated[int, 4, 5]),
-                "typing_extensions.Annotated[int, 4, 5]"
-            )
-
-        def test_flatten(self):
-            A = Annotated[Annotated[int, 4], 5]
-            self.assertEqual(A, Annotated[int, 4, 5])
-            self.assertEqual(A.__metadata__, (4, 5))
+    def test_flatten(self):
+        A = Annotated[Annotated[int, 4], 5]
+        self.assertEqual(A, Annotated[int, 4, 5])
+        self.assertEqual(A.__metadata__, (4, 5))
+        if PEP_560:
             self.assertEqual(A.__origin__, int)
 
-        def test_hash_eq(self):
-            self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
-            self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
-            self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5])
-            self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4])
-            self.assertEqual(
-                {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]},
-                {Annotated[int, 4, 5], Annotated[T, 4, 5]}
-            )
+    def test_specialize(self):
+        L = Annotated[List[T], "my decoration"]
+        LI = Annotated[List[int], "my decoration"]
+        self.assertEqual(L[int], Annotated[List[int], "my decoration"])
+        self.assertEqual(L[int].__metadata__, ("my decoration",))
+        if PEP_560:
+            self.assertEqual(L[int].__origin__, List[int])
+        with self.assertRaises(TypeError):
+            LI[int]
+        with self.assertRaises(TypeError):
+            L[int, float]
 
-        def test_instantiate(self):
-            class C:
-                classvar = 4
+    def test_hash_eq(self):
+        self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
+        self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
+        self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5])
+        self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4])
+        self.assertEqual(
+            {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]},
+            {Annotated[int, 4, 5], Annotated[T, 4, 5]}
+        )
 
-                def __init__(self, x):
-                    self.x = x
+    def test_instantiate(self):
+        class C:
+            classvar = 4
 
-                def __eq__(self, other):
-                    if not isinstance(other, C):
-                        return NotImplemented
-                    return other.x == self.x
+            def __init__(self, x):
+                self.x = x
 
-            A = Annotated[C, "a decoration"]
-            a = A(5)
-            c = C(5)
-            self.assertEqual(a, c)
-            self.assertEqual(a.x, c.x)
-            self.assertEqual(A.classvar, C.classvar)
+            def __eq__(self, other):
+                if not isinstance(other, C):
+                    return NotImplemented
+                return other.x == self.x
 
-            MyCount = Annotated[typing_extensions.Counter[T], "my decoration"]
-            self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1})
-            self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1})
+        A = Annotated[C, "a decoration"]
+        a = A(5)
+        c = C(5)
+        self.assertEqual(a, c)
+        self.assertEqual(a.x, c.x)
+        self.assertEqual(a.classvar, c.classvar)
+
+    def test_instantiate_generic(self):
+        MyCount = Annotated[typing_extensions.Counter[T], "my decoration"]
+        self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1})
+        self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1})
+
+    def test_cannot_instantiate_forward(self):
+        A = Annotated["int", (5, 6)]
+        with self.assertRaises(TypeError):
+            A(5)
+
+    def test_cannot_instantiate_type_var(self):
+        A = Annotated[T, (5, 6)]
+        with self.assertRaises(TypeError):
+            A(5)
+
+    def test_cannot_getattr_typevar(self):
+        with self.assertRaises(AttributeError):
+            Annotated[T, (5, 7)].x
+
+    def test_attr_passthrough(self):
+        class C:
+            classvar = 4
+
+        A = Annotated[C, "a decoration"]
+        self.assertEqual(A.classvar, 4)
+        A.x = 5
+        self.assertEqual(C.x, 5)
+
+    def test_hash_eq(self):
+        self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
+        self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
+        self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5])
+        self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4])
+        self.assertEqual(
+            {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]},
+            {Annotated[int, 4, 5], Annotated[T, 4, 5]}
+        )
+
+    def test_cannot_subclass(self):
+        with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"):
+           class C(Annotated):
+               pass
+
+    def test_cannot_check_instance(self):
+        with self.assertRaises(TypeError):
+            isinstance(5, Annotated[int, "positive"])
+
+    def test_cannot_check_subclass(self):
+        with self.assertRaises(TypeError):
+            issubclass(int, Annotated[int, "positive"])
 
 
-        def test_cannot_subclass(self):
-            with self.assertRaises(TypeError):
-                class C(Annotated):
-                    pass
+    @skipUnless(PEP_560, "pickle support was added with PEP 560")
+    def test_pickle(self):
+        samples = [typing.Any, typing.Union[int, str],
+                   typing.Optional[str], Tuple[int, ...],
+                   typing.Callable[[str], bytes]]
 
-        def test_pickle(self):
-            samples = [typing.Any, typing.Union[int, str],
-                       typing.Optional[str], Tuple[int, ...],
-                       typing.Callable[[str], bytes]]
+        for t in samples:
+            x = Annotated[t, "a"]
 
-            for t in samples:
-                x = Annotated[t, "a"]
+            for prot in range(pickle.HIGHEST_PROTOCOL + 1):
+                with self.subTest(protocol=prot, type=t):
+                    pickled = pickle.dumps(x, prot)
+                    restored = pickle.loads(pickled)
+                    self.assertEqual(x, restored)
 
-                for prot in range(pickle.HIGHEST_PROTOCOL + 1):
-                    with self.subTest(protocol=prot, type=t):
-                        pickled = pickle.dumps(x, prot)
-                        restored = pickle.loads(pickled)
-                        self.assertEqual(x, restored)
+        global _Annotated_test_G
 
-            global _Annotated_test_G
+        class _Annotated_test_G(Generic[T]):
+            x = 1
 
-            class _Annotated_test_G(Generic[T]):
-                x = 1
+        G = Annotated[_Annotated_test_G[int], "A decoration"]
+        G.foo = 42
+        G.bar = 'abc'
 
-            G = Annotated[_Annotated_test_G[int], "A decoration"]
-            G.foo = 42
-            G.bar = 'abc'
+        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+            z = pickle.dumps(G, proto)
+            x = pickle.loads(z)
+            self.assertEqual(x.foo, 42)
+            self.assertEqual(x.bar, 'abc')
+            self.assertEqual(x.x, 1)
 
-            for proto in range(pickle.HIGHEST_PROTOCOL + 1):
-                z = pickle.dumps(G, proto)
-                x = pickle.loads(z)
-                self.assertEqual(x.foo, 42)
-                self.assertEqual(x.bar, 'abc')
-                self.assertEqual(x.x, 1)
+    def test_subst(self):
+        dec = "a decoration"
+        dec2 = "another decoration"
 
-        def test_subst(self):
-            dec = "a decoration"
+        S = Annotated[T, dec2]
+        self.assertEqual(S[int], Annotated[int, dec2])
 
-            S = Annotated[T, dec]
-            self.assertEqual(S[int], Annotated[int, dec])
+        self.assertEqual(S[Annotated[int, dec]], Annotated[int, dec, dec2])
+        L = Annotated[List[T], dec]
 
-            L = Annotated[List[T], dec]
-            self.assertEqual(L[int], Annotated[List[int], dec])
-            with self.assertRaises(TypeError):
-                L[int, int]
+        self.assertEqual(L[int], Annotated[List[int], dec])
+        with self.assertRaises(TypeError):
+            L[int, int]
 
-            D = Annotated[Dict[KT, VT], dec]
-            self.assertEqual(D[str, int], Annotated[Dict[str, int], dec])
-            with self.assertRaises(TypeError):
-                D[int]
+        self.assertEqual(S[L[int]], Annotated[List[int], dec, dec2])
 
-            I = Annotated[int, dec]
-            with self.assertRaises(TypeError):
-                I[None]
+        D = Annotated[Dict[KT, VT], dec]
+        self.assertEqual(D[str, int], Annotated[Dict[str, int], dec])
+        with self.assertRaises(TypeError):
+            D[int]
 
-            LI = L[int]
-            with self.assertRaises(TypeError):
-                LI[None]
+        I = Annotated[int, dec]
+        with self.assertRaises(TypeError):
+            I[None]
 
-        def test_annotated_in_other_types(self):
-            X = List[Annotated[T, 5]]
-            self.assertEqual(X[int], List[Annotated[int, 5]])
+        LI = L[int]
+        with self.assertRaises(TypeError):
+            LI[None]
+
+    def test_annotated_in_other_types(self):
+        X = List[Annotated[T, 5]]
+        self.assertEqual(X[int], List[Annotated[int, 5]])
 
 
-    class GetTypeHintsTests(BaseTestCase):
-        def test_get_type_hints(self):
-            def foobar(x: List['X']): ...
-            X = Annotated[int, (1, 10)]
-            self.assertEqual(
-                get_type_hints(foobar, globals(), locals()),
-                {'x': List[int]}
-            )
-            self.assertEqual(
-                get_type_hints(foobar, globals(), locals(), include_extras=True),
-                {'x': List[Annotated[int, (1, 10)]]}
-            )
-            BA = Tuple[Annotated[T, (1, 0)], ...]
-            def barfoo(x: BA): ...
-            self.assertEqual(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...])
-            self.assertIs(
-                get_type_hints(barfoo, globals(), locals(), include_extras=True)['x'],
-                BA
-            )
-            def barfoo2(x: typing.Callable[..., Annotated[List[T], "const"]],
-                        y: typing.Union[int, Annotated[T, "mutable"]]): ...
-            self.assertEqual(
-                get_type_hints(barfoo2, globals(), locals()),
-                {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]}
-            )
-            BA2 = typing.Callable[..., List[T]]
-            def barfoo3(x: BA2): ...
-            self.assertIs(
-                get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"],
-                BA2
-            )
+@skipUnless(PEP_560, "Python 3.7 required")
+class GetTypeHintsTests(BaseTestCase):
+    def test_get_type_hints(self):
+        def foobar(x: List['X']): ...
+        X = Annotated[int, (1, 10)]
+        self.assertEqual(
+            get_type_hints(foobar, globals(), locals()),
+            {'x': List[int]}
+        )
+        self.assertEqual(
+            get_type_hints(foobar, globals(), locals(), include_extras=True),
+            {'x': List[Annotated[int, (1, 10)]]}
+        )
+        BA = Tuple[Annotated[T, (1, 0)], ...]
+        def barfoo(x: BA): ...
+        self.assertEqual(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...])
+        self.assertIs(
+            get_type_hints(barfoo, globals(), locals(), include_extras=True)['x'],
+            BA
+        )
+        def barfoo2(x: typing.Callable[..., Annotated[List[T], "const"]],
+                    y: typing.Union[int, Annotated[T, "mutable"]]): ...
+        self.assertEqual(
+            get_type_hints(barfoo2, globals(), locals()),
+            {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]}
+        )
+        BA2 = typing.Callable[..., List[T]]
+        def barfoo3(x: BA2): ...
+        self.assertIs(
+            get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"],
+            BA2
+        )
 
-        def test_get_type_hints_refs(self):
+    def test_get_type_hints_refs(self):
 
-            Const = Annotated[T, "Const"]
+        Const = Annotated[T, "Const"]
 
-            class MySet(Generic[T]):
+        class MySet(Generic[T]):
 
-                def __ior__(self, other: "Const[MySet[T]]") -> "MySet[T]":
-                    ...
+            def __ior__(self, other: "Const[MySet[T]]") -> "MySet[T]":
+                ...
 
-                def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]":
-                    ...
+            def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]":
+                ...
 
-            self.assertEqual(
-                get_type_hints(MySet.__iand__, globals(), locals()),
-                {'other': MySet[T], 'return': MySet[T]}
-            )
+        self.assertEqual(
+            get_type_hints(MySet.__iand__, globals(), locals()),
+            {'other': MySet[T], 'return': MySet[T]}
+        )
 
-            self.assertEqual(
-                get_type_hints(MySet.__iand__, globals(), locals(), include_extras=True),
-                {'other': Const[MySet[T]], 'return': MySet[T]}
-            )
+        self.assertEqual(
+            get_type_hints(MySet.__iand__, globals(), locals(), include_extras=True),
+            {'other': Const[MySet[T]], 'return': MySet[T]}
+        )
 
-            self.assertEqual(
-                get_type_hints(MySet.__ior__, globals(), locals()),
-                {'other': MySet[T], 'return': MySet[T]}
-            )
+        self.assertEqual(
+            get_type_hints(MySet.__ior__, globals(), locals()),
+            {'other': MySet[T], 'return': MySet[T]}
+        )
 
 
 
@@ -1665,6 +1734,10 @@
         self.assertIn('overload', a)
         self.assertIn('Text', a)
         self.assertIn('TYPE_CHECKING', a)
+        if TYPING_3_5_3:
+            self.assertIn('Annotated', a)
+        if PEP_560:
+            self.assertIn('get_type_hints', a)
 
         if ASYNCIO:
             self.assertIn('Awaitable', a)
@@ -1680,9 +1753,6 @@
             self.assertIn('Protocol', a)
             self.assertIn('runtime', a)
 
-        if HAVE_ANNOTATED:
-            self.assertIn('Annotated', a)
-            self.assertIn('get_type_hints', a)
 
     def test_typing_extensions_defers_when_possible(self):
         exclude = {'overload', 'Text', 'TYPE_CHECKING', 'Final', 'get_type_hints'}
diff --git a/typing_extensions/src_py3/typing_extensions.py b/typing_extensions/src_py3/typing_extensions.py
index 81f60ac..dc5d2db 100644
--- a/typing_extensions/src_py3/typing_extensions.py
+++ b/typing_extensions/src_py3/typing_extensions.py
@@ -25,6 +25,11 @@
 except ImportError:
     OLD_GENERICS = True
 try:
+    from typing import _subs_tree
+    SUBS_TREE = True
+except ImportError:
+    SUBS_TREE = False
+try:
     from typing import _tp_cache
 except ImportError:
     _tp_cache = lambda x: x
@@ -135,19 +140,22 @@
     'TYPE_CHECKING',
 ]
 
+# Annotated relies on substitution trees of pep 560. It will not work for
+# versions of typing older than 3.5.3
+HAVE_ANNOTATED = PEP_560 or SUBS_TREE
+
+if PEP_560:
+    __all__.append("get_type_hints")
+
+if HAVE_ANNOTATED:
+    __all__.append("Annotated")
+
 # Protocols are hard to backport to the original version of typing 3.5.0
 HAVE_PROTOCOLS = sys.version_info[:3] != (3, 5, 0)
 
 if HAVE_PROTOCOLS:
     __all__.extend(['Protocol', 'runtime'])
 
-# Annotations were implemented under tight time constraints; this keeps the
-# implementation simple for now
-HAVE_ANNOTATED = PEP_560
-
-if HAVE_ANNOTATED:
-    __all__.extend(['Annotated', 'get_type_hints'])
-
 
 # TODO
 if hasattr(typing, 'NoReturn'):
@@ -1611,8 +1619,8 @@
     """
 
 
-if HAVE_ANNOTATED:
-    class _Annotated(typing._GenericAlias, _root=True):
+if PEP_560:
+    class _AnnotatedAlias(typing._GenericAlias, _root=True):
         """Runtime representation of an annotated type.
 
         At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't'
@@ -1621,7 +1629,7 @@
         it to types is also the same.
         """
         def __init__(self, origin, metadata):
-            if isinstance(origin, _Annotated):
+            if isinstance(origin, _AnnotatedAlias):
                 metadata = origin.__metadata__ + metadata
                 origin = origin.__origin__
             super().__init__(origin, origin)
@@ -1630,7 +1638,7 @@
         def copy_with(self, params):
             assert len(params) == 1
             new_type = params[0]
-            return _Annotated(new_type, self.__metadata__)
+            return _AnnotatedAlias(new_type, self.__metadata__)
 
         def __repr__(self):
             return "typing_extensions.Annotated[{}, {}]".format(
@@ -1644,7 +1652,7 @@
             )
 
         def __eq__(self, other):
-            if not isinstance(other, _Annotated):
+            if not isinstance(other, _AnnotatedAlias):
                 return NotImplemented
             if self.__origin__ != other.__origin__:
                 return False
@@ -1653,7 +1661,6 @@
         def __hash__(self):
             return hash((self.__origin__, self.__metadata__))
 
-
     class Annotated:
         """Add context specific metadata to a type.
 
@@ -1680,11 +1687,11 @@
 
         - Annotated can be used as a generic type alias::
 
-            Optimized = Annotated[T, runtime.Optimize]
-            Optimized[int] == Annotated[int, runtime.Optimize]
+            Optimized = Annotated[T, runtime.Optimize()]
+            Optimized[int] == Annotated[int, runtime.Optimize()]
 
-            OptimizedList = Annotated[List[T], runtime.Optimize]
-            OptimizedList[int] == Annotated[List[int], runtime.Optimize]
+            OptimizedList = Annotated[List[T], runtime.Optimize()]
+            OptimizedList[int] == Annotated[List[int], runtime.Optimize()]
         """
 
         __slots__ = ()
@@ -1692,7 +1699,7 @@
         def __new__(cls, *args, **kwargs):
             raise TypeError("Type Annotated cannot be instantiated.")
 
-        @typing._tp_cache
+        @_tp_cache
         def __class_getitem__(cls, params):
             if not isinstance(params, tuple) or len(params) < 2:
                 raise TypeError("Annotated[...] should be used "
@@ -1701,15 +1708,17 @@
             msg = "Annotated[t, ...]: t must be a type."
             origin = typing._type_check(params[0], msg)
             metadata = tuple(params[1:])
-            return _Annotated(origin, metadata)
+            return _AnnotatedAlias(origin, metadata)
 
         def __init_subclass__(cls, *args, **kwargs):
-            raise TypeError("Cannot inherit from Annotated")
+            raise TypeError(
+                "Cannot subclass {}.Annotated".format(cls.__module__)
+            )
 
     def _strip_annotations(t):
         """Strips the annotations from a given type.
         """
-        if isinstance(t, _Annotated):
+        if isinstance(t, _AnnotatedAlias):
             return _strip_annotations(t.__origin__)
         if isinstance(t, typing._GenericAlias):
             stripped_args = tuple(_strip_annotations(a) for a in t.__args__)
@@ -1755,3 +1764,148 @@
         if include_extras:
             return hint
         return {k: _strip_annotations(t) for k, t in hint.items()}
+
+elif HAVE_ANNOTATED:
+
+    # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality
+    # checks, argument expansion etc. are done on the _subs_tre. As a result we
+    # can't provide a get_type_hints function that strips out annotations.
+
+    class AnnotatedMeta(typing.GenericMeta):
+        """Metaclass for Annotated"""
+
+        def __new__(cls, name, bases, namespace, **kwargs):
+            if any(b is not object for b in bases):
+                raise TypeError("Cannot subclass " + str(Annotated))
+            return super().__new__(cls, name, bases, namespace, **kwargs)
+
+        @property
+        def __metadata__(self):
+            return self._subs_tree()[2]
+
+        def _tree_repr(self, tree):
+            assert len(tree) == 3
+            # First argument is this class, second is __origin__, 3rd is __metadata__
+            tp_tree = tree[1]
+            if not isinstance(tp_tree, tuple):
+                tp_repr = typing._type_repr(tp_tree)
+            else:
+                tp_repr = tp_tree[0]._tree_repr(tp_tree)
+            metadata_reprs = ", ".join(repr(arg) for arg in tree[2])
+            return repr(tree[0]) + '[%s, %s]' % (tp_repr, metadata_reprs)
+
+        def _subs_tree(self, tvars=None, args=None):
+            if self is Annotated:
+                return Annotated
+            res = super()._subs_tree(tvars=tvars, args=args)
+            # Flatten nested Annotated
+            if isinstance(res[1], tuple) and res[1][0] is Annotated:
+                sub_tp = res[1][1]
+                sub_annot = res[1][2]
+                return (Annotated, sub_tp, sub_annot + res[2])
+            return res
+
+        def _get_cons(self):
+            """Return the class used to create instance of this type."""
+            if self.__origin__ is None:
+                raise TypeError("Cannot get the underlying type of a "
+                                "non-specialized Annotated type.")
+            tree = self._subs_tree()
+            while isinstance(tree, tuple) and tree[0] is Annotated:
+                tree = tree[1]
+            if isinstance(tree, tuple):
+                return tree[0]
+            else:
+                return tree
+
+        @_tp_cache
+        def __getitem__(self, params):
+            if not isinstance(params, tuple):
+                params = (params,)
+            if self.__origin__ is not None:  # specializing an instantiated type
+                return super().__getitem__(params)
+            elif not isinstance(params, tuple) or len(params) < 2:
+                raise TypeError("Annotated[...] should be instantiated "
+                                "with at least two arguments (a type and an "
+                                "annotation).")
+            else:
+                msg = "Annotated[t, ...]: t must be a type."
+                tp = typing._type_check(params[0], msg)
+                metadata = tuple(params[1:])
+            return self.__class__(
+                self.__name__,
+                self.__bases__,
+                _no_slots_copy(self.__dict__),
+                tvars=_type_vars((tp,)),
+                # Metadata is a tuple so it won't be touched by _replace_args et al.
+                args=(tp, metadata),
+                origin=self,
+            )
+
+        def __call__(self, *args, **kwargs):
+            cons = self._get_cons()
+            result = cons(*args, **kwargs)
+            try:
+                result.__orig_class__ = self
+            except AttributeError:
+                pass
+            return result
+
+        def __getattr__(self, attr):
+            # For simplicity we just don't relay all dunder names
+            if self.__origin__ is not None and not (
+                    attr.startswith('__') and attr.endswith('__')
+            ):
+                return getattr(self._get_cons(), attr)
+            raise AttributeError(attr)
+
+        def __setattr__(self, attr, value):
+            if (
+                attr.startswith('__') and attr.endswith('__')
+                or attr.startswith('_abc_')
+            ):
+                super().__setattr__(attr, value)
+            elif self.__origin__ is None:
+                raise AttributeError(attr)
+            else:
+                setattr(self._get_cons(), attr, value)
+
+        # We overload this because the super() error message is confusing:
+        # Parametrized generics cannot be used ...
+        def __instancecheck__(self, obj):
+            raise TypeError("Annotated cannot be used with isinstance().")
+
+        def __subclasscheck__(self, cls):
+            raise TypeError("Annotated cannot be used with issubclass().")
+
+    class Annotated(metaclass=AnnotatedMeta):
+        """Add context specific metadata to a type.
+
+        Example: Annotated[int, runtime_check.Unsigned] indicates to the
+        hypothetical runtime_check module that this type is an unsigned int.
+        Every other consumer of this type can ignore this metadata and treat
+        this type as int.
+
+        The first argument to Annotated must be a valid type, the remaining
+        arguments are kept as a tuple in the __metadata__ field.
+
+        Details:
+
+        - It's an error to call `Annotated` with less than two arguments.
+        - Nested Annotated are flattened::
+
+            Annotated[Annotated[int, Ann1, Ann2], Ann3] == Annotated[int, Ann1, Ann2, Ann3]
+
+        - Instantiating an annotated type is equivalent to instantiating the
+        underlying type::
+
+            Annotated[C, Ann1](5) == C(5)
+
+        - Annotated can be used as a generic type alias::
+
+            Optimized = Annotated[T, runtime.Optimize()]
+            Optimized[int] == Annotated[int, runtime.Optimize()]
+
+            OptimizedList = Annotated[List[T], runtime.Optimize()]
+            OptimizedList[int] == Annotated[List[int], runtime.Optimize()]
+        """