{-# LANGUAGE CPP #-}
{-# LANGUAGE AllowAmbiguousTypes       #-}
{-# LANGUAGE DataKinds                 #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE PolyKinds                 #-}
{-# LANGUAGE Rank2Types                #-}
{-# LANGUAGE ScopedTypeVariables       #-}
{-# LANGUAGE TypeApplications          #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE TypeOperators             #-}
{-# LANGUAGE UndecidableInstances      #-}
module Data.Generics.Product.Subtype
  ( 
    
    
    Subtype (..)
  ) where
import Data.Generics.Internal.Families
import Data.Generics.Internal.VL.Lens as VL
import Data.Generics.Internal.Void
import Data.Generics.Product.Internal.Subtype
import GHC.Generics (Generic (Rep, to, from) )
import GHC.TypeLits (Symbol, TypeError, ErrorMessage (..))
import Data.Kind (Type, Constraint)
import Data.Generics.Internal.Profunctor.Lens hiding (set)
import Data.Generics.Internal.Errors
class Subtype sup sub where
  
  
  
  
  
  
  
  
  super  :: VL.Lens sub sub sup sup
  super
    = VL.lens upcast (uncurry smash . swap)
  
  
  
  
  
  
  
  
  
  
  
  upcast :: sub -> sup
  upcast s = s ^. super @sup
  
  
  
  
  smash  :: sup -> sub -> sub
  smash = VL.set (super @sup)
  {-# MINIMAL super | smash, upcast #-}
instance
  ( Generic a
  , Generic b
  , GSmash (Rep a) (Rep b)
  , GUpcast (Rep a) (Rep b)
  , CustomError a b
  ) => Subtype b a where
    smash p b = to $ gsmash (from p) (from b)
    upcast    = to . gupcast . from
type family CustomError a b :: Constraint where
  CustomError a b =
    ( ErrorUnless b a (CollectFieldsOrdered (Rep b) \\ CollectFieldsOrdered (Rep a))
    , Defined (Rep a)
      (NoGeneric a '[ 'Text "arising from a generic lens focusing on " ':<>: QuoteType b
                    , 'Text "as a supertype of " ':<>: QuoteType a
                    ])
      (() :: Constraint)
    , Defined (Rep b)
      (NoGeneric b '[ 'Text "arising from a generic lens focusing on " ':<>: QuoteType b
                    , 'Text "as a supertype of " ':<>: QuoteType a
                    ])
      (() :: Constraint)
    )
instance {-# OVERLAPPING #-} Subtype a a where
  super = id
#if __GLASGOW_HASKELL__ < 804
#else
#endif
instance {-# OVERLAPPING #-} Subtype a Void where
  super = undefined
#if __GLASGOW_HASKELL__ < 804
#else
#endif
instance {-# OVERLAPPING #-} Subtype Void a where
  super = undefined
type family ErrorUnless (sup :: Type) (sub :: Type) (diff :: [Symbol]) :: Constraint where
  ErrorUnless _ _ '[]
    = ()
  ErrorUnless sup sub fs
    = TypeError
        (     'Text "The type '"
        ':<>: 'ShowType sub
        ':<>: 'Text "' is not a subtype of '"
        ':<>: 'ShowType sup ':<>: 'Text "'."
        ':$$: 'Text "The following fields are missing from '"
        ':<>: 'ShowType sub ':<>: 'Text "':"
        ':$$: ShowSymbols fs
        )