Merge 3.5 (Issue #24400)
diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst
index dc2704e..563c1bc 100644
--- a/Doc/library/collections.abc.rst
+++ b/Doc/library/collections.abc.rst
@@ -162,10 +162,11 @@
    :class:`~collections.abc.Coroutine` ABC are all instances of this ABC.
 
    .. note::
-      In CPython, generator-based coroutines are *awaitables*, even though
-      they do not have an :meth:`__await__` method.  This ABC
-      implements an :meth:`~class.__instancecheck__` method to make them
-      instances of itself.
+      In CPython, generator-based coroutines (generators decorated with
+      :func:`types.coroutine` or :func:`asyncio.coroutine`) are
+      *awaitables*, even though they do not have an :meth:`__await__` method.
+      Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``.
+      Use :func:`inspect.isawaitable` to detect them.
 
    .. versionadded:: 3.5
 
@@ -179,10 +180,11 @@
    :class:`Awaitable`.  See also the definition of :term:`coroutine`.
 
    .. note::
-      In CPython, generator-based coroutines are *awaitables* and *coroutines*,
-      even though they do not have an :meth:`__await__` method.  This ABC
-      implements an :meth:`~class.__instancecheck__` method to make them
-      instances of itself.
+      In CPython, generator-based coroutines (generators decorated with
+      :func:`types.coroutine` or :func:`asyncio.coroutine`) are
+      *awaitables*, even though they do not have an :meth:`__await__` method.
+      Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``.
+      Use :func:`inspect.isawaitable` to detect them.
 
    .. versionadded:: 3.5
 
diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index d21672f..66b9238 100644
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -310,6 +310,25 @@
    .. versionadded:: 3.5
 
 
+.. function:: isawaitable(object)
+
+   Return true if the object can be used in :keyword:`await` expression.
+
+   Can also be used to distinguish generator-based coroutines from regular
+   generators::
+
+      def gen():
+          yield
+      @types.coroutine
+      def gen_coro():
+          yield
+
+      assert not isawaitable(gen())
+      assert isawaitable(gen_coro())
+
+   .. versionadded:: 3.5
+
+
 .. function:: istraceback(object)
 
    Return true if the object is a traceback.
diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst
index 3239ce5..9713a98 100644
--- a/Doc/whatsnew/3.5.rst
+++ b/Doc/whatsnew/3.5.rst
@@ -532,8 +532,9 @@
 * New argument ``follow_wrapped`` for :func:`inspect.signature`.
   (Contributed by Yury Selivanov in :issue:`20691`.)
 
-* New :func:`~inspect.iscoroutine` and :func:`~inspect.iscoroutinefunction`
-  functions.  (Contributed by Yury Selivanov in :issue:`24017`.)
+* New :func:`~inspect.iscoroutine`, :func:`~inspect.iscoroutinefunction`
+  and :func:`~inspect.isawaitable` functions.  (Contributed by
+  Yury Selivanov in :issue:`24017`.)
 
 * New :func:`~inspect.getcoroutinelocals` and :func:`~inspect.getcoroutinestate`
   functions.  (Contributed by Yury Selivanov in :issue:`24400`.)
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index ba6a9b8..f89bb6f 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -81,22 +81,7 @@
         return NotImplemented
 
 
-class _AwaitableMeta(ABCMeta):
-
-    def __instancecheck__(cls, instance):
-        # This hook is needed because we can't add
-        # '__await__' method to generator objects, and
-        # we can't register GeneratorType on Awaitable.
-        # NB: 0x100 = CO_ITERABLE_COROUTINE
-        # (We don't want to import 'inspect' module, as
-        # a dependency for 'collections.abc')
-        if (instance.__class__ is generator and
-            instance.gi_code.co_flags & 0x100):
-            return True
-        return super().__instancecheck__(instance)
-
-
-class Awaitable(metaclass=_AwaitableMeta):
+class Awaitable(metaclass=ABCMeta):
 
     __slots__ = ()
 
diff --git a/Lib/inspect.py b/Lib/inspect.py
index f48769e..45679cf 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -207,6 +207,13 @@
     """Return true if the object is a coroutine."""
     return isinstance(object, types.CoroutineType)
 
+def isawaitable(object):
+    """Return true is object can be passed to an ``await`` expression."""
+    return (isinstance(object, types.CoroutineType) or
+            isinstance(object, types.GeneratorType) and
+                object.gi_code.co_flags & CO_ITERABLE_COROUTINE or
+            isinstance(object, collections.abc.Awaitable))
+
 def istraceback(object):
     """Return true if the object is a traceback.
 
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 698805d..07420c6 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -511,8 +511,10 @@
             self.assertTrue(issubclass(type(x), Awaitable))
 
         c = coro()
-        self.assertIsInstance(c, Awaitable)
-        c.close() # awoid RuntimeWarning that coro() was not awaited
+        # Iterable coroutines (generators with CO_ITERABLE_COROUTINE
+        # flag don't have '__await__' method, hence can't be instances
+        # of Awaitable. Use inspect.isawaitable to detect them.
+        self.assertNotIsInstance(c, Awaitable)
 
         c = new_coro()
         self.assertIsInstance(c, Awaitable)
@@ -559,8 +561,10 @@
             self.assertTrue(issubclass(type(x), Awaitable))
 
         c = coro()
-        self.assertIsInstance(c, Coroutine)
-        c.close() # awoid RuntimeWarning that coro() was not awaited
+        # Iterable coroutines (generators with CO_ITERABLE_COROUTINE
+        # flag don't have '__await__' method, hence can't be instances
+        # of Coroutine. Use inspect.isawaitable to detect them.
+        self.assertNotIsInstance(c, Coroutine)
 
         c = new_coro()
         self.assertIsInstance(c, Coroutine)
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index ab22c7d..a02f2e1 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -151,6 +151,29 @@
 
         coro.close(); gen_coro.close() # silence warnings
 
+    def test_isawaitable(self):
+        def gen(): yield
+        self.assertFalse(inspect.isawaitable(gen()))
+
+        coro = coroutine_function_example(1)
+        gen_coro = gen_coroutine_function_example(1)
+
+        self.assertTrue(inspect.isawaitable(coro))
+        self.assertTrue(inspect.isawaitable(gen_coro))
+
+        class Future:
+            def __await__():
+                pass
+        self.assertTrue(inspect.isawaitable(Future()))
+        self.assertFalse(inspect.isawaitable(Future))
+
+        class NotFuture: pass
+        not_fut = NotFuture()
+        not_fut.__await__ = lambda: None
+        self.assertFalse(inspect.isawaitable(not_fut))
+
+        coro.close(); gen_coro.close() # silence warnings
+
     def test_isroutine(self):
         self.assertTrue(inspect.isroutine(mod.spam))
         self.assertTrue(inspect.isroutine([].count))
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index ba8a1b9..738588e 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -1447,6 +1447,19 @@
         with self.assertRaisesRegex(Exception, 'ham'):
             wrapper.throw(Exception, Exception('ham'))
 
+    def test_returning_itercoro(self):
+        @types.coroutine
+        def gen():
+            yield
+
+        gencoro = gen()
+
+        @types.coroutine
+        def foo():
+            return gencoro
+
+        self.assertIs(foo(), gencoro)
+
     def test_genfunc(self):
         def gen(): yield
         self.assertIs(types.coroutine(gen), gen)
@@ -1457,9 +1470,6 @@
         g = gen()
         self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE)
         self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE)
-        self.assertIsInstance(g, collections.abc.Coroutine)
-        self.assertIsInstance(g, collections.abc.Awaitable)
-        g.close() # silence warning
 
         self.assertIs(types.coroutine(gen), gen)
 
diff --git a/Lib/types.py b/Lib/types.py
index 8c5fc65..48891cd 100644
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -241,12 +241,12 @@
     @_functools.wraps(func)
     def wrapped(*args, **kwargs):
         coro = func(*args, **kwargs)
-        if coro.__class__ is CoroutineType:
-            # 'coro' is a native coroutine object.
+        if (coro.__class__ is CoroutineType or
+            coro.__class__ is GeneratorType and coro.gi_code.co_flags & 0x100):
+            # 'coro' is a native coroutine object or an iterable coroutine
             return coro
-        if (coro.__class__ is GeneratorType or
-                (isinstance(coro, _collections_abc.Generator) and
-                 not isinstance(coro, _collections_abc.Coroutine))):
+        if (isinstance(coro, _collections_abc.Generator) and
+            not isinstance(coro, _collections_abc.Coroutine)):
             # 'coro' is either a pure Python generator iterator, or it
             # implements collections.abc.Generator (and does not implement
             # collections.abc.Coroutine).
diff --git a/Misc/NEWS b/Misc/NEWS
index 37d988c..e0e1693 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -41,7 +41,9 @@
   uses collections.abc.Coroutine, it's intended to test for pure 'async def'
   coroutines only; add new opcode: GET_YIELD_FROM_ITER; fix generators wrapper
   used in types.coroutine to be instance of collections.abc.Generator;
-  inspect.isawaitable was removed (use collections.abc.Awaitable).
+  collections.abc.Awaitable and collections.abc.Coroutine can no longer
+  be used to detect generator-based coroutines--use inspect.isawaitable
+  instead.
 
 - Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines.
   Contributed by Benno Leslie and Yury Selivanov.