{-# LANGUAGE ConstraintKinds      #-}
{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE PolyKinds            #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE TypeOperators        #-}
{-# LANGUAGE UndecidableInstances #-}
module Servant.API.TypeErrors (
  PartialApplication,
  NoInstanceFor,
  NoInstanceForSub,
  ErrorIfNoGeneric,
) where
import Data.Kind (Type, Constraint)
import GHC.Generics (Generic(..))
import GHC.TypeLits
type NoInstanceForSub (tycls :: k) (expr :: k') =
  Text "There is no instance for " :<>: ShowType tycls
  :<>: Text " (" :<>: ShowType expr :<>: Text " :> ...)"
type NoInstanceFor (expr :: k) =
  Text "There is no instance for " :<>: ShowType expr
type PartialApplication (tycls :: k) (expr :: k') =
  NoInstanceForSub tycls expr
  :$$: ShowType expr :<>: Text " expects " :<>: ShowType (Arity expr) :<>: Text " more arguments"
type Arity (ty :: k) = Arity' k
type family Arity' (ty :: k) :: Nat where
  Arity' (_ -> ty) = 1 + Arity' ty
  Arity' _ = 0
type ErrorIfNoGeneric routes = Break (NoGeneric routes :: Type) (Rep (routes ()))
data T1 a
type family Break err a :: Constraint where
  Break _ T1 = ((), ())
  Break _ a  = ()
type family NoGeneric (routes :: Type -> Type) where
  NoGeneric routes = TypeError
    ( 'Text "Named routes require a "
      ':<>: 'ShowType Generic ':<>: 'Text " instance for "
      ':<>: 'ShowType routes
    )