REF: make dependency structure more DAG-like
There are a handful of places where the dependency structure is _almost_ DAG-like.  If these can be smoothed out, reasoning about the code can be made easier.  I'll update this list as I encounter these places.

For reference, I'm treating as the "default" dependency structure that enforced by isort:

- `_libs`, 'errors', `compat`, and `util._*` are considered "upstream" of everything else.
   - Within `_libs`, `tslibs` is considered upstream of the rest of `_libs`
- Within `core`, `core.dtypes` is considered upstream of the rest of `core`.
- `plotting` is considered downstream of core
- `io` is a hodge-podge
- `tseries` is mostly destined to be refactored into `tslibs`

Some places where this can be made more coherent:

- [ ] `compat.pickle_compat` imports `pandas`, so really isn't upstream of anything.
- [ ] `compat.numpy.function` imports from `util._validators`.  AFAICT the imported `util._validators` functions aren't used anywhere else, so these could be made self-contained.  Both of these modules import from core.dtypes.common, though these imports could come directly from `_libs.lib`.
- [ ] `core.dtypes` is a mix.  `base`, `generic`, `inference` have no non-upstream imports.  But `common` has a couple, `cast` and `concat` have a bunch, with `dtypes` and `missing` in between.  It may be worth splitting this directory into two pieces, one of which is strictly upstream from the rest of core and one which is not.
- [ ] Important parts of `io` could be made independent/upstream of `core` if `config` was made further upstream.
- [ ] `util` is split between modules like `_decorators` that are low-dependency and `testing` which is depends-on-everything.