    {-# LANGUAGE DataKinds, FlexibleInstances, FlexibleContexts, UndecidableInstances,
         KindSignatures, TypeFamilies, CPP #-}

    #if !defined(TESTING)
    {-# LANGUAGE Safe #-}
    #endif

    -- | Unsatisfiable constraints for functions being removed.

    module Utils.Containers.Internal.TypeError where
    import GHC.TypeLits

    -- | The constraint @Whoops s@ is unsatisfiable for every 'Symbol' @s@.  Trying
    -- to use a function with a @Whoops s@ constraint will lead to a pretty type
    -- error explaining how to fix the problem.
    --
    -- ==== Example
    --
    -- @
    -- oldFunction :: Whoops "oldFunction is gone now. Use newFunction."
    --             => Int -> IntMap a -> IntMap a
    -- @
    class Whoops (a :: Symbol)

    instance TypeError ('Text a) => Whoops a

    -- Why don't we just use
    --
    -- type Whoops a = TypeError ('Text a) ?
    --
    -- When GHC sees the type signature of oldFunction, it will see that it
    -- has an unsatisfiable constraint and reject it out of hand.
    --
    -- It seems possible to hack around that with a type family:
    --
    -- type family Whoops a where
    --   Whoops a = TypeError ('Text a)
    --
    -- but I don't really trust that to work reliably. What we actually
    -- do is pretty much guaranteed to work. Despite the fact that there
    -- is a totally polymorphic instance in scope, GHC will refrain from
    -- reducing the constraint because it knows someone could (theoretically)
    -- define an overlapping instance of Whoops. It doesn't commit to
    -- the polymorphic one until it has to, at the call site.