Make a start with a prototype for the "typing.py" module.

(This is actually copied from the "better" subdirectory of the
"prototyping" branch. See there for history. But I'm abandoning that
branch now. My git-fu is lacking to do this using git commands.)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..04bb595
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+__pycache__
+@*
+*~
+*.pyc
+*.pyo
+htmlcov
+.coverage
diff --git a/prototyping/test_typing.py b/prototyping/test_typing.py
new file mode 100644
index 0000000..3915b99
--- /dev/null
+++ b/prototyping/test_typing.py
@@ -0,0 +1,607 @@
+from unittest import TestCase, mock
+
+from typing import Any
+from typing import Var, T, KT, VT, AnyStr
+from typing import Union, Optional
+from typing import Tuple
+from typing import Callable
+from typing import Generic
+
+
+class Employee:
+    pass
+
+
+class Manager(Employee):
+    pass
+
+
+class Founder(Employee):
+    pass
+
+
+class ManagingFounder(Manager, Founder):
+    pass
+
+
+class AnyTests(TestCase):
+
+    def test_any_instance(self):
+        self.assertIsInstance(Employee(), Any)
+        self.assertIsInstance(42, Any)
+        self.assertIsInstance(None, Any)
+        self.assertIsInstance(object(), Any)
+
+    def test_any_subclass(self):
+        self.assertTrue(issubclass(Employee, Any))
+        self.assertTrue(issubclass(int, Any))
+        self.assertTrue(issubclass(type(None), Any))
+        self.assertTrue(issubclass(object, Any))
+
+    def test_others_any(self):
+        self.assertFalse(issubclass(Any, Employee))
+        self.assertFalse(issubclass(Any, int))
+        self.assertFalse(issubclass(Any, type(None)))
+        # However, Any is a subclass of object (this can't be helped).
+        self.assertTrue(issubclass(Any, object))
+
+    def test_repr(self):
+        self.assertEqual(repr(Any), 'typing.Any')
+
+    def test_errors(self):
+        with self.assertRaises(TypeError):
+            issubclass(42, Any)
+        with self.assertRaises(TypeError):
+            Any[int]  # Any is not a generic type.
+
+    def test_cannot_subclass(self):
+        with self.assertRaises(TypeError):
+            class A(Any):
+                pass
+
+    def test_cannot_instantiate(self):
+        with self.assertRaises(TypeError):
+            Any()
+
+    def test_cannot_subscript(self):
+        with self.assertRaises(TypeError):
+            Any[int]
+
+
+class VarTests(TestCase):
+
+    def test_isinstance(self):
+        self.assertNotIsInstance(42, T)
+        self.assertIsInstance(b'b', AnyStr)
+        self.assertIsInstance('s', AnyStr)
+        self.assertNotIsInstance(42, AnyStr)
+
+    def test_issubclass(self):
+        self.assertTrue(issubclass(T, Any))
+        self.assertFalse(issubclass(int, T))
+        self.assertTrue(issubclass(bytes, AnyStr))
+        self.assertTrue(issubclass(str, AnyStr))
+        self.assertTrue(issubclass(T, T))
+        self.assertTrue(issubclass(AnyStr, AnyStr))
+
+    def test_repr(self):
+        self.assertEqual(repr(T), '~T')
+        self.assertEqual(repr(KT), '~KT')
+        self.assertEqual(repr(VT), '~VT')
+        self.assertEqual(repr(AnyStr), '~AnyStr')
+
+    def test_no_redefinition(self):
+        self.assertNotEqual(Var('T'), Var('T'))
+        self.assertNotEqual(Var('T', int, str), Var('T', int, str))
+
+    def test_subclass_as_unions(self):
+        self.assertTrue(issubclass(Var('T', int, str), Var('T', int, str)))
+        self.assertTrue(issubclass(Var('T', int), Var('T', int, str)))
+        self.assertTrue(issubclass(Var('T', int, str), Var('T', str, int)))
+        A = Var('A', int, str)
+        B = Var('B', int, str, float)
+        self.assertTrue(issubclass(A, B))
+        self.assertFalse(issubclass(B, A))
+
+    def test_cannot_subclass_vars(self):
+        with self.assertRaises(TypeError):
+            class V(Var('T')):
+                pass
+
+    def test_cannot_subclass_var_itself(self):
+        with self.assertRaises(TypeError):
+            class V(Var):
+                pass
+
+    def test_cannot_instantiate_vars(self):
+        with self.assertRaises(TypeError):
+            Var('A')()
+
+    def test_bind(self):
+        self.assertNotIsInstance(42, T)  # Baseline.
+        with T.bind(int):
+            self.assertIsInstance(42, T)
+            self.assertNotIsInstance(3.14, T)
+            self.assertTrue(issubclass(int, T))
+            self.assertFalse(issubclass(T, int))
+            self.assertFalse(issubclass(float, T))
+        self.assertNotIsInstance(42, T)  # Baseline restored.
+
+    def test_bind_reuse(self):
+        self.assertNotIsInstance(42, T)  # Baseline.
+        bv = T.bind(int)
+        with bv:
+            self.assertIsInstance(42, T)  # Bound.
+            self.assertNotIsInstance(3.14, T)
+        self.assertNotIsInstance(42, T)  # Baseline restored.
+        # Reusing bv will work.
+        with bv:
+            self.assertIsInstance(42, T)  # Bound.
+            self.assertNotIsInstance(3.14, T)
+            # Reusing bv recursively won't work.
+            with self.assertRaises(TypeError):
+                with bv:
+                    self.assertFalse("Should not get here")
+            # Rebinding T explicitly will work.
+            with T.bind(float):
+                self.assertIsInstance(3.14, T)
+                self.assertNotIsInstance(42, T)
+            # Now the previous binding should be restored.
+            self.assertIsInstance(42, T)
+            self.assertNotIsInstance(3.14, T)
+        self.assertNotIsInstance(42, T)  # Baseline restored.
+
+    def test_bind_fail(self):
+        # This essentially tests what happens when __enter__() raises
+        # an exception.  __exit__() won't be called, but the
+        # VarBinding and the Var are still in consistent states.
+        bv = T.bind(int)
+        with mock.patch('typing.Var._bind', side_effect=RuntimeError):
+            with self.assertRaises(RuntimeError):
+                with bv:
+                    self.assertFalse("Should not get here")
+        self.assertNotIsInstance(42, T)
+        with bv:
+            self.assertIsInstance(42, T)
+        self.assertNotIsInstance(42, T)
+
+
+class UnionTests(TestCase):
+
+    def test_basics(self):
+        u = Union[int, float]
+        self.assertNotEqual(u, Union)
+        self.assertIsInstance(42, u)
+        self.assertIsInstance(3.14, u)
+        self.assertTrue(issubclass(int, u))
+        self.assertTrue(issubclass(float, u))
+
+    def test_union_any(self):
+        u = Union[Any]
+        self.assertEqual(u, Any)
+        u = Union[int, Any]
+        self.assertEqual(u, Any)
+        u = Union[Any, int]
+        self.assertEqual(u, Any)
+
+    def test_union_object(self):
+        u = Union[object]
+        self.assertEqual(u, object)
+        u = Union[int, object]
+        self.assertEqual(u, object)
+        u = Union[object, int]
+        self.assertEqual(u, object)
+
+    def test_union_any_object(self):
+        u = Union[object, Any]
+        self.assertEqual(u, Any)
+        u = Union[Any, object]
+        self.assertEqual(u, Any)
+
+    def test_unordered(self):
+        u1 = Union[int, float]
+        u2 = Union[float, int]
+        self.assertEqual(u1, u2)
+
+    def test_subclass(self):
+        u = Union[int, Employee]
+        self.assertIsInstance(Manager(), u)
+        self.assertTrue(issubclass(Manager, u))
+
+    def test_self_subclass(self):
+        self.assertTrue(issubclass(Union[KT, VT], Union))
+        self.assertFalse(issubclass(Union, Union[KT, VT]))
+
+    def test_multiple_inheritance(self):
+        u = Union[int, Employee]
+        self.assertIsInstance(ManagingFounder(), u)
+        self.assertTrue(issubclass(ManagingFounder, u))
+
+    def test_single_class_disappears(self):
+        t = Union[Employee]
+        self.assertIs(t, Employee)
+
+    def test_base_class_disappears(self):
+        u = Union[Employee, Manager, int]
+        self.assertEqual(u, Union[int, Employee])
+        u = Union[Manager, int, Employee]
+        self.assertEqual(u, Union[int, Employee])
+        u = Union[Employee, Manager]
+        self.assertIs(u, Employee)
+
+    def test_weird_subclasses(self):
+        u = Union[Employee, int, float]
+        v = Union[int, float]
+        self.assertTrue(issubclass(v, u))
+        w = Union[int, Manager]
+        self.assertTrue(issubclass(w, u))
+
+    def test_union_union(self):
+        u = Union[int, float]
+        v = Union[u, Employee]
+        self.assertEqual(v, Union[int, float, Employee])
+
+    def test_repr(self):
+        self.assertEqual(repr(Union), 'typing.Union')
+        u = Union[Employee, int]
+        self.assertEqual(repr(u), 'typing.Union[test_typing.Employee, int]')
+        u = Union[int, Employee]
+        self.assertEqual(repr(u), 'typing.Union[int, test_typing.Employee]')
+
+    def test_cannot_subclass(self):
+        with self.assertRaises(TypeError):
+            class C(Union):
+                pass
+        with self.assertRaises(TypeError):
+            class C(Union[int, str]):
+                pass
+
+    def test_cannot_instantiate(self):
+        with self.assertRaises(TypeError):
+            Union()
+        u = Union[int, float]
+        with self.assertRaises(TypeError):
+            u()
+
+    def test_optional(self):
+        o = Optional[int]
+        u = Union[int, None]
+        self.assertEqual(o, u)
+        self.assertIsInstance(42, o)
+        self.assertIsInstance(None, o)
+        self.assertNotIsInstance(3.14, o)
+
+    def test_empty(self):
+        with self.assertRaises(TypeError):
+            Union[()]
+
+
+class VarUnionTests(TestCase):
+
+    def test_simpler(self):
+        A = Var('A', int, str, float)
+        B = Var('B', int, str)
+        assert issubclass(A, A)
+        assert issubclass(B, B)
+        assert issubclass(B, A)
+        assert issubclass(A, Union[int, str, float])
+        assert issubclass(Union[int, str, float], A)
+        assert issubclass(Union[int, str], B)
+        assert issubclass(B, Union[int, str])
+        assert not issubclass(A, B)
+        assert not issubclass(Union[int, str, float], B)
+        assert not issubclass(A, Union[int, str])
+
+    def test_var_union_subclass(self):
+        self.assertTrue(issubclass(T, Union[int, T]))
+        self.assertTrue(issubclass(KT, Union[KT, VT]))
+
+    def test_var_union(self):
+        TU = Var('TU', Union[int, float])
+        self.assertIsInstance(42, TU)
+        self.assertIsInstance(3.14, TU)
+        self.assertNotIsInstance('', TU)
+        with TU.bind(int):
+            # The effective binding is the union.
+            self.assertIsInstance(42, TU)
+            self.assertIsInstance(3.14, TU)
+            self.assertNotIsInstance('', TU)
+        with self.assertRaises(TypeError):
+            with TU.bind(str):
+                self.assertFalse("Should not get here")
+
+    def test_var_union_and_more_precise(self):
+        TU = Var('TU', Union[int, float], int)
+        with TU.bind(int):
+            # The binding is ambiguous, but the second alternative
+            # is strictly more precise.  Choose the more precise match.
+            # The effective binding is int.
+            self.assertIsInstance(42, TU)
+            self.assertNotIsInstance(3.14, TU)
+            self.assertNotIsInstance('', TU)
+        with TU.bind(float):
+            # The effective binding is the union.
+            self.assertIsInstance(42, TU)
+            self.assertIsInstance(3.14, TU)
+            self.assertNotIsInstance('', TU)
+
+    def test_var_union_overlapping(self):
+        TU = Var('TU', Union[int, float], Union[float, str])
+        with TU.bind(int):
+            # The effective binding is the first union.
+            self.assertIsInstance(42, TU)
+            self.assertIsInstance(3.14, TU)
+            self.assertNotIsInstance('', TU)
+        with TU.bind(float):
+            # The binding is ambiguous, but neither constraint is a
+            # subclass of the other.  Choose the first match.
+            # The effective binding is the first union.
+            self.assertIsInstance(42, TU)
+            self.assertIsInstance(3.14, TU)
+            self.assertNotIsInstance('', TU)
+        with TU.bind(str):
+            # The effective binding is the second union.
+            self.assertNotIsInstance(42, TU)
+            self.assertIsInstance(3.14, TU)
+            self.assertIsInstance('', TU)
+
+
+class TupleTests(TestCase):
+
+    def test_basics(self):
+        self.assertIsInstance((42, 3.14, ''), Tuple)
+        self.assertIsInstance((42, 3.14, ''), Tuple[int, float, str])
+        self.assertIsInstance((42,), Tuple[int])
+        self.assertNotIsInstance((3.14,), Tuple[int])
+        self.assertNotIsInstance((42, 3.14), Tuple[int, float, str])
+        self.assertNotIsInstance((42, 3.14, 100), Tuple[int, float, str])
+        self.assertNotIsInstance((42, 3.14, 100), Tuple[int, float])
+        self.assertTrue(issubclass(Tuple[int, str], Tuple))
+        self.assertTrue(issubclass(Tuple[int, str], Tuple[int, str]))
+        self.assertFalse(issubclass(int, Tuple))
+        self.assertFalse(issubclass(Tuple[float, str], Tuple[int, str]))
+        self.assertFalse(issubclass(Tuple[int, str, int], Tuple[int, str]))
+        self.assertFalse(issubclass(Tuple[int, str], Tuple[int, str, int]))
+        self.assertTrue(issubclass(tuple, Tuple))
+        self.assertFalse(issubclass(Tuple, tuple))  # Can't have it both ways.
+
+    def test_tuple_subclass(self):
+        class MyTuple(tuple):
+            pass
+        self.assertTrue(issubclass(MyTuple, Tuple))
+
+    def test_repr(self):
+        self.assertEqual(repr(Tuple), 'typing.Tuple')
+        self.assertEqual(repr(Tuple[()]), 'typing.Tuple[]')
+        self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]')
+
+    def test_errors(self):
+        with self.assertRaises(TypeError):
+            issubclass(42, Tuple)
+        with self.assertRaises(TypeError):
+            issubclass(42, Tuple[int])
+
+
+class CallableTests(TestCase):
+
+    def test_basics(self):
+        c = Callable[[int, float], str]
+
+        def flub(a: int, b: float) -> str:
+            return str(a*b)
+
+        def flob(a: int, b: int) -> str:
+            return str(a*b)
+
+        self.assertIsInstance(flub, c)
+        self.assertNotIsInstance(flob, c)
+
+    def test_self_subclass(self):
+        self.assertTrue(issubclass(Callable[[int], int], Callable))
+        self.assertFalse(issubclass(Callable, Callable[[int], int]))
+        self.assertTrue(issubclass(Callable[[int], int], Callable[[int], int]))
+        self.assertFalse(issubclass(Callable[[Employee], int],
+                                    Callable[[Manager], int]))
+        self.assertFalse(issubclass(Callable[[Manager], int],
+                                    Callable[[Employee], int]))
+        self.assertFalse(issubclass(Callable[[int], Employee],
+                                    Callable[[int], Manager]))
+        self.assertFalse(issubclass(Callable[[int], Manager],
+                                    Callable[[int], Employee]))
+
+    def test_eq_hash(self):
+        self.assertEqual(Callable[[int], int], Callable[[int], int])
+        self.assertEqual(len({Callable[[int], int], Callable[[int], int]}), 1)
+        self.assertNotEqual(Callable[[int], int], Callable[[int], str])
+        self.assertNotEqual(Callable[[int], int], Callable[[str], int])
+        self.assertNotEqual(Callable[[int], int], Callable[[int, int], int])
+        self.assertNotEqual(Callable[[int], int], Callable[[], int])
+        self.assertNotEqual(Callable[[int], int], Callable)
+
+    def test_with_none(self):
+        c = Callable[[None], None]
+
+        def flub(self: None) -> None:
+            pass
+
+        def flab(self: Any) -> None:
+            pass
+
+        def flob(self: None) -> Any:
+            pass
+
+        self.assertIsInstance(flub, c)
+        self.assertIsInstance(flab, c)
+        self.assertNotIsInstance(flob, c)  # Test contravariance.
+
+    def test_with_subclasses(self):
+        c = Callable[[Employee, Manager], Employee]
+
+        def flub(a: Employee, b: Employee) -> Manager:
+            return Manager()
+
+        def flob(a: Manager, b: Manager) -> Employee:
+            return Employee()
+
+        self.assertIsInstance(flub, c)
+        self.assertNotIsInstance(flob, c)
+
+    def test_with_default_args(self):
+        c = Callable[[int], int]
+
+        def flub(a: int, b: float = 3.14) -> int:
+            return a
+
+        def flab(a: int, *, b: float = 3.14) -> int:
+            return a
+
+        def flob(a: int = 42) -> int:
+            return a
+
+        self.assertIsInstance(flub, c)
+        self.assertIsInstance(flab, c)
+        self.assertIsInstance(flob, c)
+
+    def test_with_varargs(self):
+        c = Callable[[int], int]
+
+        def flub(*args) -> int:
+            return 42
+
+        def flab(*args: int) -> int:
+            return 42
+
+        def flob(*args: float) -> int:
+            return 42
+
+        self.assertIsInstance(flub, c)
+        self.assertIsInstance(flab, c)
+        self.assertNotIsInstance(flob, c)
+
+    def test_with_method(self):
+
+        class C:
+
+            def imethod(self, arg: int) -> int:
+                self.last_arg = arg
+                return arg + 1
+
+            @classmethod
+            def cmethod(cls, arg: int) -> int:
+                cls.last_cls_arg = arg
+                return arg + 1
+
+            @staticmethod
+            def smethod(arg: int) -> int:
+                return arg + 1
+
+        ct = Callable[[int], int]
+        self.assertIsInstance(C().imethod, ct)
+        self.assertIsInstance(C().cmethod, ct)
+        self.assertIsInstance(C.cmethod, ct)
+        self.assertIsInstance(C().smethod, ct)
+        self.assertIsInstance(C.smethod, ct)
+        self.assertIsInstance(C.imethod, Callable[[Any, int], int])
+
+    def test_cannot_subclass(self):
+        with self.assertRaises(TypeError):
+
+            class C(Callable):
+                pass
+
+        with self.assertRaises(TypeError):
+
+            class C(Callable[[int], int]):
+                pass
+
+    def test_cannot_instantiate(self):
+        with self.assertRaises(TypeError):
+            Callable()
+        c = Callable[[int], str]
+        with self.assertRaises(TypeError):
+            c()
+
+
+XK = Var('XK', str, bytes)
+XV = Var('XV')
+
+
+class SimpleMapping(Generic[XK, XV]):
+
+    def __getitem__(self, key: XK) -> XV:
+        ...
+
+    def __setitem__(self, key: XK, value: XV):
+        ...
+
+    def get(self, key: XK, default: XV = None) -> XV:
+        ...
+
+
+class MySimpleMapping(SimpleMapping):
+
+    def __init__(self):
+        self.store = {}
+
+    def __getitem__(self, key: str):
+        return self.store[key]
+
+    def __setitem__(self, key: str, value):
+        self.store[key] = value
+
+    def get(self, key: str, default=None):
+        try:
+            return self.store[key]
+        except KeyError:
+            return default
+
+
+class GenericTests(TestCase):
+
+    def test_basics(self):
+        X = SimpleMapping[str, Any]
+        Y = SimpleMapping[AnyStr, str]
+        X[str, str]
+        Y[str, str]
+        with self.assertRaises(TypeError):
+            X[int, str]
+        with self.assertRaises(TypeError):
+            Y[str, bytes]
+
+    def test_repr(self):
+        self.assertEqual(repr(SimpleMapping),
+                         __name__ + '.' + 'SimpleMapping[~XK, ~XV]')
+        self.assertEqual(repr(MySimpleMapping),
+                         __name__ + '.' + 'MySimpleMapping[~XK, ~XV]')
+        A = Var('A', str)  # Must be a subclass of XK.
+        B = Var('B')
+
+        class X(SimpleMapping[A, B]):
+            pass
+
+        self.assertEqual(repr(X).split('.')[-1], 'X[~A, ~B]')
+
+    def test_errors(self):
+        with self.assertRaises(TypeError):
+            class C(SimpleMapping[XK, Any]):
+                pass
+
+    def test_repr_2(self):
+
+        class C(Generic[T]):
+            pass
+
+        assert C.__module__ == __name__
+        assert C.__qualname__ == 'GenericTests.test_repr_2.<locals>.C'
+        assert repr(C).split('.')[-1] == 'C[~T]'
+        X = C[int]
+        assert X.__module__ == __name__
+        assert X.__qualname__ == 'C'
+        assert repr(X).split('.')[-1] == 'C[int]'
+
+        class Y(C[int]):
+            pass
+
+        assert Y.__module__ == __name__
+        assert Y.__qualname__ == 'GenericTests.test_repr_2.<locals>.Y'
+        assert repr(Y).split('.')[-1] == 'Y[int]'
diff --git a/prototyping/typing.py b/prototyping/typing.py
new file mode 100644
index 0000000..0edae04
--- /dev/null
+++ b/prototyping/typing.py
@@ -0,0 +1,758 @@
+# TODO:
+# [done] Any
+# [done] Var (type variables)
+# [done] T, KT, VT, AnyStr
+# [done] Union, Optional
+# [done] Tuple
+# [done] Callable
+# [done] Generic
+# Protocol (similar to Generic, but for structural matching)
+# All the collections ABCs (with Set renamed to AbstractSet):
+#   Hashable, Iterable, Iterator,
+#   Sized, Container, *Abstract*Set, MutableSet, Mapping, MutableMapping,
+#   MappingView, KeysView, ItemsView, ValuesView,
+#   Sequence, MutableSequence
+#   ByteString
+# List, Dict, Set; FrozenSet?
+# Other things from mypy's typing.py:
+# - Undefined
+# - IO, BinaryIO, TextIO (?)
+# - Match (?)
+# - Pattern (?)
+# - cast
+# - forwardref
+# - overload
+# - [done] typevar (alias for Var)
+# Even more things from mypy's typing.py (that aren't in its __all__)
+
+# TODO nits:
+# Get rid of asserts that are the caller's fault.
+# Docstrings.
+# Make it pep8-clean.
+
+import abc
+import collections.abc
+import inspect
+import types
+
+
+class TypingMeta(type):
+    """Base class for every type defined below.
+
+    This overrides __new__() to require an extra keyword parameter
+    '_root', which serves as a guard against naive subclassing of the
+    typing classes.  Any legitimate class defined using a metaclass
+    derived from TypingMeta (including internal subclasses created by
+    e.g.  Union[X, Y]) must pass _root=True.
+
+    This also defines a dummy constructor (all the work is done in
+    __new__) and a nicer repr().
+    """
+
+    def __new__(cls, name, bases, namespace, *, _root=False):
+        if not _root:
+            raise TypeError("Cannot subclass %s" %
+                            (', '.join(map(_type_repr, bases))))
+        return super().__new__(cls, name, bases, namespace)
+
+    def __init__(self, *args, **kwds):
+        pass
+
+    def __repr__(self):
+        return '%s.%s' % (self.__module__, self.__qualname__)
+
+
+class Final:
+    """Mix-in class to prevent instantiation."""
+
+    def __new__(self, *args, **kwds):
+        raise TypeError("Cannot instantiate %r" % self.__class__)
+
+
+def _type_check(arg, msg):
+    """Check that the argument is a type, and return it.
+
+    As a special case, accept None and return type(None) instead.
+    The msg argument is a human-readable error message, e.g.
+
+        "Union[arg, ...]: arg should be a type."
+
+    We append the repr() of the actual value (truncated to 100 chars).
+    """
+    if arg is None:
+        return type(None)
+    if not isinstance(arg, type):
+        raise TypeError(msg + " Got %.100r." % (arg,))
+    return arg
+
+
+def _type_repr(obj):
+    """Return the repr() of an object, special-casing types.
+
+    If obj is a type, we return a shorter version than the default
+    type.__repr__, based on the module and qualified name, which is
+    typically enough to uniquely identify a type.  For everything
+    else, we fall back on repr(obj).
+    """
+    if isinstance(obj, type) and not isinstance(obj, TypingMeta):
+        # The ~ is to have some indication the string was produced here.
+        if obj.__module__ == 'builtins':
+            return obj.__qualname__
+        else:
+            return '%s.%s' % (obj.__module__, obj.__qualname__)
+    else:
+        return repr(obj)
+
+
+class AnyMeta(TypingMeta):
+    """Metaclass for Any."""
+
+    def __new__(cls, name, bases, namespace, _root=False):
+        self = super().__new__(cls, name, bases, namespace, _root=_root)
+        return self
+
+    def __instancecheck__(self, instance):
+        return True
+
+    def __subclasscheck__(self, cls):
+        if not isinstance(cls, type):
+            return super().__subclasscheck__(cls)  # To TypeError.
+        return True
+
+
+class Any(Final, metaclass=AnyMeta, _root=True):
+    """Special type indicating an unconstrained type.
+
+    - Any object is an instance of Any.
+    - Any class is a subclass of Any.
+    - As a special case, Any and object are subclasses of each other.
+    """
+
+
+class Var(TypingMeta, metaclass=TypingMeta, _root=True):
+    """Type variable.
+
+    Usage::
+
+      T1 = Var('T1')  # Unconstrained
+      T2 = Var('T2', t1, t2, ...)  # Constrained to any of (t1, t2, ...)
+
+    For an unconstrained type variable T, isinstance(x, T) is false
+    for all x, and similar for issubclass(cls, T).  Example::
+
+      T = Var('T')
+      assert not isinstance(42, T)
+      assert not issubclass(int, T)
+
+    For a constrained type variable T, isinstance(x, T) is true for
+    any x that is an instance of at least one of T's constraints,
+    and similar for issubclass(cls, T).  Example::
+
+      AnyStr = Var('AnyStr', str, bytes)
+      # AnyStr behaves similar to Union[str, bytes] (but not exactly!)
+      assert not isinstance(42, AnyStr)
+      assert isinstance('', AnyStr)
+      assert isinstance(b'', AnyStr)
+      assert not issubclass(int, AnyStr)
+      assert issubclass(str, AnyStr)
+      assert issubclass(bytes, AnyStr)
+
+    Type variables that are distinct objects are never equal (even if
+    created with the same parameters).
+
+    You can temporarily *bind* a type variable to a specific type by
+    calling its bind() method and using the result as a context
+    manager (i.e., in a with-statement).  Example::
+
+      with T.bind(int):
+          # In this block, T is nearly an alias for int.
+          assert isinstance(42, T)
+          assert issubclass(int, T)
+
+    There is still a difference between T and int; issubclass(T, int)
+    is False.  However, issubclass(int, T) is true.
+
+    Binding a constrained type variable will replace the binding type
+    with the most derived of its constraints that matches.  Example::
+
+      class MyStr(str):
+          pass
+
+      with AnyStr.bind(MyStr):
+          # In this block, AnyStr is an alias for str, not for MyStr.
+          assert isinstance('', AnyStr)
+          assert issubclass(str, AnyStr)
+          assert not isinstance(b'', AnyStr)
+          assert not issubclass(bytes, AnyStr)
+
+    """
+
+    def __new__(cls, name, *constraints):
+        self = super().__new__(cls, name, (Final,), {}, _root=True)
+        msg = "Var(name, constraint, ...): constraints must be types."
+        self.__constraints__ = tuple(_type_check(t, msg) for t in constraints)
+        self.__binding__ = None
+        return self
+
+    def __repr__(self):
+        return '~' + self.__name__
+
+    def __instancecheck__(self, instance):
+        if self.__binding__ is not None:
+            return isinstance(instance, self.__binding__)
+        elif not self.__constraints__:
+            return False
+        else:
+            return isinstance(instance, Union[self.__constraints__])
+
+    def __subclasscheck__(self, cls):
+        if cls is self:
+            return True
+        elif self.__binding__ is not None:
+            return issubclass(cls, self.__binding__)
+        elif not self.__constraints__:
+            return False
+        else:
+            return issubclass(cls, Union[self.__constraints__])
+
+    def bind(self, binding):
+        binding = _type_check(binding, "Var.bind(t): t must be a type.")
+        if self.__constraints__:
+            best = None
+            for t in self.__constraints__:
+                if (issubclass(binding, t) and
+                    (best is None or issubclass(t, best))):
+                    best = t
+            if best is None:
+                raise TypeError(
+                    "Var.bind(t): t must match one of the constraints.")
+            binding = best
+        return VarBinding(self, binding)
+
+    def _bind(self, binding):
+        old_binding = self.__binding__
+        self.__binding__ = binding
+        return old_binding
+
+    def _unbind(self, binding, old_binding):
+        assert self.__binding__ is binding, (self.__binding__,
+                                             binding, old_binding)
+        self.__binding__ = old_binding
+
+
+# Compatibility for for mypy's typevar().
+def typevar(name, values=()):
+    return Var(name, *values)
+
+
+class VarBinding:
+    """Variable binding returned by Var.bind()."""
+
+    # TODO: This is not thread-safe.  We could solve this in one of
+    # two ways: by using a lock or by using thread-local state.  But
+    # either of these feels overly heavy, and still doesn't work
+    # e.g. in an asyncio Task.
+
+    def __init__(self, var, binding):
+        assert isinstance(var, Var), (var, binding)
+        assert isinstance(binding, type), (var, binding)
+        self._var = var
+        self._binding = binding
+        self._old_binding = None
+        self._entered = False
+
+    def __enter__(self):
+        if self._entered:
+            # This checks for the following scenario:
+            # bv = T.bind(<some_type>)
+            # with bv:
+            #     with bv:  # Will raise here.
+            #         ...
+            # However, the following scenario is OK (if somewhat odd):
+            # bv = T.bind(<some_type>)
+            # with bv:
+            #     ...
+            # with bv:
+            #     ...
+            # The following scenario is also fine:
+            # with T.bind(<some_type>):
+            #     with T.bind(<some_other_type>):
+            #         ...
+            raise TypeError("Cannot reuse variable binding recursively.")
+        self._old_binding = self._var._bind(self._binding)
+        self._entered = True
+
+    def __exit__(self, *args):
+        try:
+            self._var._unbind(self._binding, self._old_binding)
+        finally:
+            self._entered = False
+            self._old_binding = None
+
+
+# Some unconstrained type variables.  These are used by the container types.
+T = Var('T')  # Any type.
+KT = Var('KT')  # Key type.
+VT = Var('VT')  # Value type.
+
+# A useful type variable with constraints.  This represents string types.
+# TODO: What about bytearray, memoryview?
+AnyStr = Var('AnyStr', bytes, str)
+
+
+class UnionMeta(TypingMeta):
+    """Metaclass for Union."""
+
+    def __new__(cls, name, bases, namespace, parameters=None, _root=False):
+        if parameters is None:
+            return super().__new__(cls, name, bases, namespace, _root=_root)
+        if not isinstance(parameters, tuple):
+            raise TypeError("Expected parameters=<tuple>")
+        # Flatten out Union[Union[...], ...] and type-check non-Union args.
+        params = []
+        msg = "Union[arg, ...]: each arg must be a type."
+        for p in parameters:
+            if isinstance(p, UnionMeta):
+                params.extend(p.__union_params__)
+            else:
+                params.append(_type_check(p, msg))
+        # Weed out strict duplicates, preserving the first of each occurrence.
+        all_params = set(params)
+        if len(all_params) < len(params):
+            new_params = []
+            for t in params:
+                if t in all_params:
+                    new_params.append(t)
+                    all_params.remove(t)
+            params = new_params
+            assert not all_params, all_params
+        # Weed out subclasses.
+        # E.g. Union[int, Employee, Manager] == Union[int, Employee].
+        # If Any or object is present it will be the sole survivor.
+        # If both Any and object are present, Any wins.
+        all_params = set(params)
+        for t1 in params:
+            if t1 is Any:
+                return Any
+            if any(issubclass(t1, t2) for t2 in all_params - {t1}):
+                all_params.remove(t1)
+        # It's not a union if there's only one type left.
+        if len(all_params) == 1:
+            return all_params.pop()
+        # Create a new class with these params.
+        self = super().__new__(cls, name, bases, namespace, _root=True)
+        self.__union_params__ = tuple(t for t in params if t in all_params)
+        self.__union_set_params__ = frozenset(self.__union_params__)
+        return self
+
+    def __repr__(self):
+        r = super().__repr__()
+        if self.__union_params__:
+            r += '[%s]' % (', '.join(_type_repr(t)
+                                     for t in self.__union_params__))
+        return r
+
+    def __getitem__(self, parameters):
+        if self.__union_params__ is not None:
+            raise TypeError(
+                "Cannot subscript an existing Union. Use Union[u, t] instead.")
+        if parameters == ():
+            raise TypeError("Cannot take a Union of no types.")
+        if not isinstance(parameters, tuple):
+            parameters = (parameters,)
+        return self.__class__(self.__name__, self.__bases__,
+                              dict(self.__dict__), parameters, _root=True)
+
+    def __eq__(self, other):
+        if not isinstance(other, UnionMeta):
+            return NotImplemented
+        return self.__union_set_params__ == other.__union_set_params__
+
+    def __hash__(self):
+        return hash(self.__union_set_params__)
+
+    def __instancecheck__(self, instance):
+        return any(isinstance(instance, t) for t in self.__union_params__)
+
+    def __subclasscheck__(self, cls):
+        if self.__union_params__ is None:
+            return isinstance(cls, UnionMeta)
+        elif isinstance(cls, UnionMeta):
+            if cls.__union_params__ is None:
+                return False
+            return all(issubclass(c, self) for c in (cls.__union_params__))
+        elif isinstance(cls, Var):
+            if cls in self.__union_params__:
+                return True
+            if cls.__constraints__:
+                return issubclass(Union[cls.__constraints__], self)
+            return False
+        else:
+            return any(issubclass(cls, t) for t in self.__union_params__)
+
+
+class Union(Final, metaclass=UnionMeta, _root=True):
+    """Union type; Union[X, Y] means either X or Y.
+
+    To define a union, use e.g. Union[int, str].  Details:
+
+    - The arguments must be types and there must be at least one.
+
+    - None as an argument is a special case and is replaced by
+      type(None).
+
+    - Unions of unions are flattened, e.g.::
+
+        Union[Union[int, str], float] == Union[int, str, float]
+
+    - Unions of a single argument vanish, e.g.::
+
+        Union[int] == int  # The constructore actually returns int
+
+    - Redundant arguments are skipped, e.g.::
+
+        Union[int, str, int] == Union[int, str]
+
+    - When comparing unions, the argument order is ignored, e.g.::
+
+        Union[int, str] == Union[str, int]
+
+    - When two arguments have a subclass relationship, the least
+      derived argument is kept, e.g.::
+
+        class Employee: pass
+        class Manager(Employee): pass
+        Union[int, Employee, Manager] == Union[int, Employee]
+        Union[Manager, int, Employee] == Union[int, Employee]
+        Union[Employee, Manager] == Employee
+
+    - Corollary: if Any is present it is the sole survivor, e.g.::
+
+        Union[int, Any] == Any
+
+    - Similar for object::
+
+        Union[int, object] == object
+
+    - To cut a tie: Union[object, Any] == Union[Any, object] == Any.
+
+    - You cannot subclass or instantiate a union.
+
+    - You cannot write Union[X][Y] (what would it mean?).
+
+    - You can use Optional[X] as a shorthand for Union[X, None].
+    """
+
+    # Unsubscripted Union type has params set to None.
+    __union_params__ = None
+    __union_set_params__ = None
+
+
+class OptionalMeta(TypingMeta):
+    """Metaclass for Optional."""
+
+    def __new__(cls, name, bases, namespace, _root=False):
+        return super().__new__(cls, name, bases, namespace, _root=_root)
+
+    def __getitem__(self, arg):
+        if not isinstance(arg, type):
+            raise TypeError("Optional[t] requires a single type.")
+        return Union[arg, type(None)]
+
+
+class Optional(Final, metaclass=OptionalMeta, _root=True):
+    """Optional type.
+
+    Optional[X] is equivalent to Union[X, type(None)].
+    """
+
+
+class TupleMeta(TypingMeta):
+    """Metaclass for Tuple."""
+
+    def __new__(cls, name, bases, namespace, parameters=None, _root=False):
+        self = super().__new__(cls, name, bases, namespace, _root=_root)
+        self.__tuple_params__ = parameters
+        return self
+
+    def __repr__(self):
+        r = super().__repr__()
+        if self.__tuple_params__ is not None:
+            r += '[%s]' % (
+                ', '.join(_type_repr(p) for p in self.__tuple_params__))
+        return r
+
+    def __getitem__(self, parameters):
+        if self.__tuple_params__ is not None:
+            raise TypeError("Cannot re-parameterize %r" % (self,))
+        if not isinstance(parameters, tuple):
+            parameters = (parameters,)
+        msg = "Class[arg, ...]: each arg must be a type."
+        parameters = tuple(_type_check(p, msg) for p in parameters)
+        return self.__class__(self.__name__, self.__bases__,
+                              dict(self.__dict__), parameters, _root=True)
+
+    def __instancecheck__(self, t):
+        if not isinstance(t, tuple):
+            return False
+        if self.__tuple_params__ is None:
+            return True
+        return (len(t) == len(self.__tuple_params__) and
+                all(isinstance(x, p)
+                    for x, p in zip(t, self.__tuple_params__)))
+
+    def __subclasscheck__(self, cls):
+        if not isinstance(cls, type):
+            return super().__subclasscheck__(cls)  # To TypeError.
+        if issubclass(cls, tuple):
+            return True  # Special case.
+        if not isinstance(cls, TupleMeta):
+            return super().__subclasscheck__(cls)  # False.
+        if self.__tuple_params__ is None:
+            return True
+        if cls.__tuple_params__ is None:
+            return False  # ???
+        # Covariance.
+        return (len(self.__tuple_params__) == len(cls.__tuple_params__) and
+                all(issubclass(x, p)
+                    for x, p in zip(cls.__tuple_params__,
+                                    self.__tuple_params__)))
+
+
+class Tuple(Final, metaclass=TupleMeta, _root=True):
+    """Tuple type; Tuple[X, Y] is the cross-product type of X and Y.
+
+    Example: Tuple[T1, T2] is a tuple of two elements corresponding
+    to type variables T1 and T2.  Tuple[int, float, str] is a tuple
+    of an int, a float and a string.
+
+    To specify a variable-length tuple of homogeneous type, use Sequence[T].
+    """
+
+
+class CallableMeta(TypingMeta):
+    """Metaclass for Callable."""
+
+    def __new__(cls, name, bases, namespace, _root=False,
+                args=None, result=None):
+        if args is None and result is None:
+            pass  # Must be 'class Callable'.
+        else:
+            if not isinstance(args, list):
+                TypeError("Callable[args, result]: args must be a list." +
+                          " Got %.100r." % (args,))
+            msg = "Callable[[arg, ...], result]: each arg must be a type."
+            args = tuple(_type_check(arg, msg) for arg in args)
+            msg = "Callable[args, result]: result must be a type."
+            result = _type_check(result, msg)
+        self = super().__new__(cls, name, bases, namespace, _root=_root)
+        self.__args__ = args
+        self.__result__ = result
+        return self
+
+    def __repr__(self):
+        r = super().__repr__()
+        if self.__args__ is not None or self.__result__ is not None:
+            r += '%s[[%s], %s]' % (self.__qualname__,
+                                   ', '.join(_type_repr(t)
+                                             for t in self.__args__),
+                                   _type_repr(self.__result__))
+        return r
+
+    def __getitem__(self, parameters):
+        if self.__args__ is not None or self.__result__ is not None:
+            raise TypeError("This Callable type is already parameterized.")
+        if not isinstance(parameters, tuple) or len(parameters) != 2:
+            raise TypeError(
+                "Callable must be used as Callable[[arg, ...], result].")
+        args, result = parameters
+        return self.__class__(self.__name__, self.__bases__,
+                              dict(self.__dict__), _root=True,
+                              args=args, result=result)
+
+    def __eq__(self, other):
+        if not isinstance(other, CallableMeta):
+            return NotImplemented
+        return (self.__args__ == other.__args__ and
+                self.__result__ == other.__result__)
+
+    def __hash__(self):
+        return hash(self.__args__) ^ hash(self.__result__)
+
+    def __instancecheck__(self, instance):
+        if not callable(instance):
+            return False
+        if self.__args__ is None and self.__result__ is None:
+            return True
+        assert self.__args__ is not None
+        assert self.__result__ is not None
+        my_args, my_result = self.__args__, self.__result__
+        # Would it be better to use Signature objects?
+        try:
+            (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults,
+             annotations) = inspect.getfullargspec(instance)
+        except TypeError:
+            return False  # We can't find the signature.  Give up.
+        if kwonlyargs and (not kwonlydefaults or
+                           len(kwonlydefaults) < len(kwonlyargs)):
+            return False
+        if isinstance(instance, types.MethodType):
+            # For methods, getfullargspec() includes self/cls,
+            # but it's not part of the call signature, so drop it.
+            del args[0]
+        min_call_args = len(args)
+        if defaults:
+            min_call_args -= len(defaults)
+        if varargs:
+            max_call_args = 999999999
+            if len(args) < len(my_args):
+                args += [varargs] * (len(my_args) - len(args))
+        else:
+            max_call_args = len(args)
+        if not min_call_args <= len(my_args) <= max_call_args:
+            return False
+        msg = ("When testing isinstance(<callable>, Callable[...], " +
+               "<calleble>'s annotations must be types.")
+        for my_arg_type, name in zip(my_args, args):
+            if name in annotations:
+                annot_type = _type_check(annotations[name], msg)
+            else:
+                annot_type = Any
+            if not issubclass(my_arg_type, annot_type):
+                return False
+            # TODO: If mutable type, check invariance?
+        if 'return' in annotations:
+            annot_return_type = _type_check(annotations['return'], msg)
+            # Note contravariance here!
+            if not issubclass(annot_return_type, my_result):
+                return False
+        # Can't find anything wrong...
+        return True
+
+    def __subclasscheck__(self, cls):
+        # Compute issubclass(cls, self).
+        if not isinstance(cls, CallableMeta):
+            return super().__subclasscheck__(cls)
+        if self.__args__ is None and self.__result__ is None:
+            return True
+        # We're not doing covariance or contravariance -- this is *invariance*.
+        return self == cls
+
+
+class Callable(Final, metaclass=CallableMeta, _root=True):
+    """Callable type; Callable[[int], str] is a function of (int) -> str.
+
+    The subscription syntax must always be used with exactly two
+    values: the argument list and the return type.  The argument list
+    must be a list of types; the return type must be a single type.
+
+    There is no syntax to indicate optional or keyword arguments,
+    such function types are rarely used as callback types.
+    """
+
+
+class GenericMeta(TypingMeta, abc.ABCMeta):
+    """Metaclass for generic types."""
+
+    # TODO: Constrain more how Generic is used; only a few
+    # standard patterns should be allowed.
+
+    # TODO: Somehow repr() of a subclass parameterized comes out with
+    # module=typing.
+
+    def __new__(cls, name, bases, namespace, parameters=None):
+        if parameters is None:
+            # Extract parameters from direct base classes.  Only
+            # direct bases are considered and only those that are
+            # themselves generic, and parameterized with type
+            # variables.  Don't use bases like Any, Union, Tuple,
+            # Callable or type variables.
+            params = None
+            for base in bases:
+                if isinstance(base, TypingMeta):
+                    if not isinstance(base, GenericMeta):
+                        raise TypeError(
+                            "You cannot inherit from magic class %s" %
+                            repr(base))
+                    if base.__parameters__ is None:
+                        continue
+                    if params is None:
+                        params = []
+                    for bp in base.__parameters__:
+                        if isinstance(bp, TypingMeta):
+                            if not isinstance(bp, Var):
+                                raise TypeError(
+                                    "Cannot inherit from a generic class "
+                                    "parameterized with a "
+                                    "non-type-variable %s" % bp)
+                        if bp not in params:
+                            params.append(bp)
+            if params is not None:
+                parameters = tuple(params)
+        self = super().__new__(cls, name, bases, namespace, _root=True)
+        self.__parameters__ = parameters
+        return self
+
+    def __repr__(self):
+        r = super().__repr__()
+        if self.__parameters__ is not None:
+            r += '[%s]' % (
+                ', '.join(_type_repr(p) for p in self.__parameters__))
+        return r
+
+    def __getitem__(self, params):
+        if not isinstance(params, tuple):
+            params = (params,)
+        if not params:
+            raise TypeError("Cannot have empty parameter list")
+        msg = "Parameters to generic types must be types."
+        params = tuple(_type_check(p, msg) for p in params)
+        if self.__parameters__ is None:
+            for p in params:
+                if not isinstance(p, Var):
+                    raise TypeError("Initial parameters must be "
+                                    "type variables; got %s" % p)
+        else:
+            if len(params) != len(self.__parameters__):
+                raise TypeError("Cannot change parameter count from %d to %d" %
+                                (len(self.__parameters__), len(params)))
+            for new, old in zip(params, self.__parameters__):
+                if isinstance(old, Var) and not old.__constraints__:
+                    # Substituting for an unconstrained Var is always OK.
+                    continue
+                if not issubclass(new, old):
+                    raise TypeError(
+                        "Cannot substitute %s for %s in %s" %
+                        (_type_repr(new), _type_repr(old), self))
+        return self.__class__(self.__name__, self.__bases__,
+                              dict(self.__dict__),
+                              parameters=params)
+
+
+class Generic(metaclass=GenericMeta):
+    """Abstract base class for generic types.
+
+    A generic type is typically declared by inheriting from an
+    instantiation of this class with one or more type variables.
+    For example, a generic mapping type might be defined as::
+
+      class Mapping(Generic[KT, VT]):
+          def __getitem__(self, key: KT) -> VT:
+              ...
+          # Etc.
+
+    This class can then be used as follows::
+
+      def lookup_name(mapping: Mapping, key: KT, default: VT) -> VT:
+          try:
+              return mapping[key]
+          except KeyError:
+              return default
+
+    For clarity the type variables may be redefined, e.g.::
+
+      X = Var('X')
+      Y = Var('Y')
+      def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y:
+          # Same body as above.
+    """