{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Error messages.
--
-- === Warning
--
-- This is an internal module: it is not subject to any versioning policy,
-- breaking changes can happen at any time.
--
-- If something here seems useful, please report it or create a pull request to
-- export it from an external module.

module Generic.Data.Internal.Error where

import Data.Kind
import Data.Type.Bool
import GHC.Generics
import GHC.TypeLits

type family HasSum f where
  HasSum V1 = 'False
  HasSum U1 = 'False
  HasSum (K1 i c) = 'False
  HasSum (M1 i c f) = HasSum f
  HasSum (f :*: g) = HasSum f || HasSum g
  HasSum (f :+: g) = 'True

class Assert (pred :: Bool) (msg :: ErrorMessage)
instance Assert 'True msg
instance (TypeError msg ~ '()) => Assert 'False msg

-- |
-- >>> :set -XDeriveGeneric -XDerivingVia
-- >>> import Generic.Data (Generically(..))
-- >>> :{
--   data AB = A | B
--     deriving stock Generic
--     deriving Semigroup via Generically AB
-- :}
-- ...
--     • Cannot derive Semigroup instance for AB due to sum type
--     • When deriving the instance for (Semigroup AB)
type AssertNoSum (constraint :: * -> Constraint) a =
    Assert (Not (HasSum (Rep a)))
    ('Text "Cannot derive " ':<>: 'ShowType constraint ':<>:
        'Text " instance for " ':<>: 'ShowType a ':<>: 'Text " due to sum type")