content: {-# LANGUAGE UndecidableInstances #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE KindSignatures #-}
  {-# LANGUAGE PolyKinds #-}
  {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE KindSignatures #-}
  
  -------------------------------------------------------------------------------
  ---- |
  ---- Module      :  Data.Generics.Internal.Errors
  ---- Copyright   :  (C) 2020 Csongor Kiss
  ---- License     :  BSD3
  ---- Maintainer  :  Csongor Kiss <kiss.csongor.kiss@gmail.com>
  ---- Stability   :  experimental
  ---- Portability :  non-portable
  ----
  ---- Provide more legible type errors as described in
  ---- (https://kcsongor.github.io/report-stuck-families/)[this blog post].
  -------------------------------------------------------------------------------
  
  module Data.Generics.Internal.Errors
   ( NoGeneric
   , Defined
   , Defined_list
  
   , QuoteType
   , PrettyError
   ) where
  
  import GHC.Generics
  import GHC.TypeLits
  import Data.Kind
  
  type family NoGeneric (a :: Type) (ctxt :: [ErrorMessage]) :: Constraint where
    NoGeneric a ctxt = PrettyError ('Text "No instance for " ':<>: QuoteType (Generic a)
                                     ': ctxt)
  type family PrettyError (ctxt :: [ErrorMessage]) :: k where
    PrettyError '[] = TypeError ('Text "")
    PrettyError (c ': cs) = TypeError ('Text "| " ':<>: c ':$$: PrettyLines cs)
  
  type family PrettyLines (ctxt :: [ErrorMessage]) :: ErrorMessage where
    PrettyLines '[] = 'Text ""
    PrettyLines (c ': cs) = 'Text "|   " ':<>: c ':$$: PrettyLines cs
  
  type family Defined (break :: Type -> Type) (err :: Constraint) (a :: k) :: k where
    Defined Void1 _ _ = Any
    Defined _ _     k = k
  
  type family Defined_list (break :: [*]) (err :: Constraint) (a :: k) :: k where
    Defined_list '[Void] _ _ = Any
    Defined_list _ _        k = k
  
  data Void1 a
  data Void
  type family Any :: k
  
  type family QuoteType (typ :: k) :: ErrorMessage where
    QuoteType typ = 'Text "‘" ':<>: 'ShowType typ ':<>: 'Text "’"
  