bpo-34075: Deprecate non-ThreadPoolExecutor in loop.set_default_executor() (GH-8533)

Various asyncio internals expect that the default executor is a
`ThreadPoolExecutor`, so deprecate passing anything else to
`loop.set_default_executor()`.
diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
index 317f3fb..cf7b6d8 100644
--- a/Doc/library/asyncio-eventloop.rst
+++ b/Doc/library/asyncio-eventloop.rst
@@ -906,7 +906,14 @@
 
 .. method:: AbstractEventLoop.set_default_executor(executor)
 
-   Set the default executor used by :meth:`run_in_executor`.
+   Set *executor* as the default executor used by :meth:`run_in_executor`.
+   *executor* should be an instance of
+   :class:`~concurrent.futures.ThreadPoolExecutor`.
+
+   .. deprecated:: 3.8
+      Using an executor that is not an instance of
+      :class:`~concurrent.futures.ThreadPoolExecutor` is deprecated and
+      will trigger an error in Python 3.9.
 
 
 Error Handling API
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 3f51535..bab1e06 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -164,6 +164,12 @@
   They will be removed in Python 3.9.
   (Contributed by Serhiy Storchaka in :issue:`29209`.)
 
+* Passing an object that is not an instance of
+  :class:`concurrent.futures.ThreadPoolExecutor` to
+  :meth:`asyncio.AbstractEventLoop.set_default_executor()` is
+  deprecated and will be prohibited in Python 3.9.
+  (Contributed by Elvis Pranskevichus in :issue:`34075`.)
+
 
 Removed
 =======
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index dc0ca3f..75989a7 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -741,6 +741,12 @@
             executor.submit(func, *args), loop=self)
 
     def set_default_executor(self, executor):
+        if not isinstance(executor, concurrent.futures.ThreadPoolExecutor):
+            warnings.warn(
+                'Using the default executor that is not an instance of '
+                'ThreadPoolExecutor is deprecated and will be prohibited '
+                'in Python 3.9',
+                DeprecationWarning, 2)
         self._default_executor = executor
 
     def _getaddrinfo_debug(self, host, port, family, type, proto, flags):
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index bda8cc6..f3ae140 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -1,5 +1,6 @@
 """Tests for base_events.py"""
 
+import concurrent.futures
 import errno
 import logging
 import math
@@ -211,10 +212,21 @@
         self.assertFalse(self.loop._ready)
 
     def test_set_default_executor(self):
-        executor = mock.Mock()
+        class DummyExecutor(concurrent.futures.ThreadPoolExecutor):
+            def submit(self, fn, *args, **kwargs):
+                raise NotImplementedError(
+                    'cannot submit into a dummy executor')
+
+        executor = DummyExecutor()
         self.loop.set_default_executor(executor)
         self.assertIs(executor, self.loop._default_executor)
 
+    def test_set_default_executor_deprecation_warnings(self):
+        executor = mock.Mock()
+
+        with self.assertWarns(DeprecationWarning):
+            self.loop.set_default_executor(executor)
+
     def test_call_soon(self):
         def cb():
             pass
diff --git a/Misc/NEWS.d/next/Library/2018-07-28-11-49-21.bpo-34075.9u1bO-.rst b/Misc/NEWS.d/next/Library/2018-07-28-11-49-21.bpo-34075.9u1bO-.rst
new file mode 100644
index 0000000..799e68e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-07-28-11-49-21.bpo-34075.9u1bO-.rst
@@ -0,0 +1,2 @@
+Deprecate passing non-ThreadPoolExecutor instances to
+:meth:`AbstractEventLoop.set_default_executor`.