module Text.Show.Text.TH.Internal (
deriveShow
, deriveShow1
, deriveShow2
, mkShow
, mkShowLazy
, mkShowPrec
, mkShowPrecLazy
, mkShowList
, mkShowListLazy
, mkShowb
, mkShowbPrec
, mkShowbList
, mkPrint
, mkPrintLazy
, mkHPrint
, mkHPrintLazy
, mkShowbPrecWith
, mkShowbPrec1
, mkShowbPrecWith2
, mkShowbPrec2
) where
import Data.Function (on)
import Data.List.Compat (foldl', intersperse)
#if MIN_VERSION_template_haskell(2,7,0)
import Data.List.Compat (find)
#endif
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (NonEmpty(..), (<|))
import qualified Data.Map as Map (fromList, lookup)
import Data.Map (Map)
import Data.Maybe (fromMaybe)
import Data.Monoid.Compat ((<>))
import qualified Data.Set as Set
import Data.Set (Set)
import qualified Data.Text as TS ()
import qualified Data.Text.IO as TS (putStrLn, hPutStrLn)
import Data.Text.Lazy (toStrict)
import Data.Text.Lazy.Builder (Builder, fromString, singleton, toLazyText)
import qualified Data.Text.Lazy as TL ()
import qualified Data.Text.Lazy.IO as TL (putStrLn, hPutStrLn)
import GHC.Exts (Char(..), Double(..), Float(..), Int(..), Word(..))
import GHC.Prim (Char#, Double#, Float#, Int#, Word#)
import GHC.Show (appPrec, appPrec1)
import Language.Haskell.TH.Lib
import Language.Haskell.TH.Ppr hiding (appPrec)
import Language.Haskell.TH.Syntax
import Prelude ()
import Prelude.Compat hiding (Show)
import qualified Text.Show as S (Show(show))
import qualified Text.Show.Text.Classes as T
import Text.Show.Text.Classes (Show1(..), Show2(..), showbPrec,
showbListWith, showbParen, showbSpace)
import Text.Show.Text.Utils (isInfixTypeCon, isTupleString)
deriveShow :: Name -> Q [Dec]
deriveShow = deriveShowClass Show
deriveShow1 :: Name -> Q [Dec]
deriveShow1 = deriveShowClass Show1
deriveShow2 :: Name -> Q [Dec]
deriveShow2 = deriveShowClass Show2
mkShow :: Name -> Q Exp
mkShow name = [| toStrict . $(mkShowLazy name) |]
mkShowLazy :: Name -> Q Exp
mkShowLazy name = [| toLazyText . $(mkShowb name) |]
mkShowPrec :: Name -> Q Exp
mkShowPrec name = [| \p -> toStrict . $(mkShowPrecLazy name) p |]
mkShowPrecLazy :: Name -> Q Exp
mkShowPrecLazy name = [| \p -> toLazyText . $(mkShowbPrec name) p |]
mkShowList :: Name -> Q Exp
mkShowList name = [| toStrict . $(mkShowListLazy name) |]
mkShowListLazy :: Name -> Q Exp
mkShowListLazy name = [| toLazyText . $(mkShowbList name) |]
mkShowb :: Name -> Q Exp
mkShowb name = mkShowbPrec name `appE` [| zero |]
where
zero :: Int
zero = 0
mkShowbPrec :: Name -> Q Exp
mkShowbPrec = mkShowbPrecClass Show
mkShowbPrecWith :: Name -> Q Exp
mkShowbPrecWith = mkShowbPrecClass Show1
mkShowbPrec1 :: Name -> Q Exp
mkShowbPrec1 name = [| $(mkShowbPrecWith name) showbPrec |]
mkShowbPrecWith2 :: Name -> Q Exp
mkShowbPrecWith2 = mkShowbPrecClass Show2
mkShowbPrec2 :: Name -> Q Exp
mkShowbPrec2 name = [| $(mkShowbPrecWith2 name) showbPrec showbPrec |]
mkShowbList :: Name -> Q Exp
mkShowbList name = [| showbListWith $(mkShowb name) |]
mkPrint :: Name -> Q Exp
mkPrint name = [| TS.putStrLn . $(mkShow name) |]
mkPrintLazy :: Name -> Q Exp
mkPrintLazy name = [| TL.putStrLn . $(mkShowLazy name) |]
mkHPrint :: Name -> Q Exp
mkHPrint name = [| \h -> TS.hPutStrLn h . $(mkShow name) |]
mkHPrintLazy :: Name -> Q Exp
mkHPrintLazy name = [| \h -> TL.hPutStrLn h . $(mkShowLazy name) |]
deriveShowClass :: ShowClass -> Name -> Q [Dec]
deriveShowClass sClass tyConName = do
info <- reify tyConName
case info of
TyConI{} -> deriveShowPlainTy sClass tyConName
#if MIN_VERSION_template_haskell(2,7,0)
DataConI{} -> deriveShowDataFamInst sClass tyConName
FamilyI (FamilyD DataFam _ _ _) _ ->
error $ ns ++ "Cannot use a data family name. Use a data family instance constructor instead."
FamilyI (FamilyD TypeFam _ _ _) _ ->
error $ ns ++ "Cannot use a type family name."
_ -> error $ ns ++ "The name must be of a plain type constructor or data family instance constructor."
#else
DataConI{} -> dataConIError
_ -> error $ ns ++ "The name must be of a plain type constructor."
#endif
where
ns :: String
ns = "Text.Show.Text.TH.deriveShow: "
deriveShowPlainTy :: ShowClass -> Name -> Q [Dec]
deriveShowPlainTy sClass tyConName =
withTyCon tyConName fromCons
where
className :: Name
className = showClassNameTable sClass
fromCons :: Cxt -> [TyVarBndr] -> [Con] -> Q [Dec]
fromCons ctxt tvbs cons = (:[]) <$>
instanceD (return instanceCxt)
(return $ AppT (ConT className) instanceType)
(showbPrecDecs droppedNbs cons)
where
(instanceCxt, instanceType, droppedNbs) =
cxtAndTypePlainTy sClass tyConName ctxt tvbs
#if MIN_VERSION_template_haskell(2,7,0)
deriveShowDataFamInst :: ShowClass -> Name -> Q [Dec]
deriveShowDataFamInst sClass dataFamInstName =
withDataFamInstCon dataFamInstName fromDec
where
className :: Name
className = showClassNameTable sClass
fromDec :: [TyVarBndr] -> Cxt -> Name -> [Type] -> [Con] -> Q [Dec]
fromDec famTvbs ctxt parentName instTys cons = (:[]) <$>
instanceD (return instanceCxt)
(return $ AppT (ConT className) instanceType)
(showbPrecDecs droppedNbs cons)
where
(instanceCxt, instanceType, droppedNbs) =
cxtAndTypeDataFamInstCon sClass parentName ctxt famTvbs instTys
#endif
showbPrecDecs :: [NameBase] -> [Con] -> [Q Dec]
showbPrecDecs nbs cons =
[ funD classFuncName
[ clause []
(normalB $ mkShowForCons nbs cons)
[]
]
]
where
classFuncName :: Name
classFuncName = showbPrecNameTable . toEnum $ length nbs
mkShowbPrecClass :: ShowClass -> Name -> Q Exp
mkShowbPrecClass sClass tyConName = do
info <- reify tyConName
case info of
TyConI{} -> withTyCon tyConName $ \ctxt tvbs decs ->
let (_, _, nbs) = cxtAndTypePlainTy sClass tyConName ctxt tvbs
in mkShowForCons nbs decs
#if MIN_VERSION_template_haskell(2,7,0)
DataConI{} -> withDataFamInstCon tyConName $ \famTvbs ctxt parentName instTys cons ->
let (_, _, nbs) = cxtAndTypeDataFamInstCon sClass parentName ctxt famTvbs instTys
in mkShowForCons nbs cons
FamilyI (FamilyD DataFam _ _ _) _ ->
error $ ns ++ "Cannot use a data family name. Use a data family instance constructor instead."
FamilyI (FamilyD TypeFam _ _ _) _ ->
error $ ns ++ "Cannot use a type family name."
_ -> error $ ns ++ "The name must be of a plain type constructor or data family instance constructor."
#else
DataConI{} -> dataConIError
_ -> error $ ns ++ "The name must be of a plain type constructor."
#endif
where
ns :: String
ns = "Text.Show.Text.TH.mkShowbPrec: "
mkShowForCons :: [NameBase] -> [Con] -> Q Exp
mkShowForCons _ [] = error "Must have at least one data constructor"
mkShowForCons nbs cons = do
p <- newName "p"
value <- newName "value"
sps <- newNameList "sp" $ length nbs
let tvis = zip nbs sps
sClass = toEnum $ length nbs
lamE (map varP $ sps ++ [p, value])
. appsE
$ [ varE $ showbPrecConstNameTable sClass
, caseE (varE value) $ map (mkShowForCon p sClass tvis) cons
] ++ map varE sps
++ [varE p, varE value]
mkShowForCon :: Name -> ShowClass -> [TyVarInfo] -> Con -> Q Match
mkShowForCon _ _ _ (NormalC conName [])
= match (conP conName [])
(normalB [| fromString $(stringE (parenInfixConName conName "")) |])
[]
mkShowForCon p sClass tvis (NormalC conName [(_, argTy)]) = do
arg <- newName "arg"
let showArg = mkShowForArg appPrec1 sClass (nameBase conName) tvis argTy arg
namedArg = [| fromString $(stringE (parenInfixConName conName " ")) <> $(showArg) |]
match (conP conName [varP arg])
(normalB [| showbParen ($(varE p) > $(lift appPrec)) $(namedArg) |])
[]
mkShowForCon p sClass tvis (NormalC conName ts) = do
args <- newNameList "arg" $ length ts
if isNonUnitTuple conName
then do
let showArgs = map (\(arg, (_, argTy)) -> mkShowForArg 0 sClass (nameBase conName) tvis argTy arg)
(zip args ts)
parenCommaArgs = [| singleton '(' |] : intersperse [| singleton ',' |] showArgs
mappendArgs = foldr (`infixApp` [| (<>) |])
[| singleton ')' |]
parenCommaArgs
match (conP conName $ map varP args)
(normalB mappendArgs)
[]
else do
let showArgs = map (\(arg, (_, argTy)) -> mkShowForArg appPrec1 sClass (nameBase conName) tvis argTy arg)
(zip args ts)
mappendArgs = foldr1 (\v q -> [| $(v) <> showbSpace <> $(q) |]) showArgs
namedArgs = [| fromString $(stringE (parenInfixConName conName " ")) <> $(mappendArgs) |]
match (conP conName $ map varP args)
(normalB [| showbParen ($(varE p) > $(lift appPrec)) $(namedArgs) |])
[]
mkShowForCon p sClass tvis (RecC conName []) = mkShowForCon p sClass tvis $ NormalC conName []
mkShowForCon _p sClass tvis (RecC conName ts) = do
args <- newNameList "arg" $ length ts
let showArgs = concatMap (\(arg, (argName, _, argTy))
-> [ [| fromString $(stringE (nameBase argName ++ " = ")) |]
, mkShowForArg 0 sClass (nameBase conName) tvis argTy arg
, [| fromString ", " |]
]
)
(zip args ts)
braceCommaArgs = [| singleton '{' |] : take (length showArgs 1) showArgs
mappendArgs = foldr (`infixApp` [| (<>) |])
[| singleton '}' |]
braceCommaArgs
namedArgs = [| fromString $(stringE (parenInfixConName conName " ")) <> $(mappendArgs) |]
match (conP conName $ map varP args)
(normalB
#if __GLASGOW_HASKELL__ >= 711
namedArgs
#else
[| showbParen ($(varE _p) > $(lift appPrec)) $(namedArgs) |]
#endif
)
[]
mkShowForCon p sClass tvis (InfixC (_, alTy) conName (_, arTy)) = do
al <- newName "argL"
ar <- newName "argR"
info <- reify conName
let conPrec = case info of
DataConI _ _ _ (Fixity prec _) -> prec
other -> error $ "Text.Show.Text.TH.mkShowForCon: Unsupported type: " ++ S.show other
opName = nameBase conName
infixOpE = if isInfixTypeCon opName
then [| fromString $(stringE $ " " ++ opName ++ " " ) |]
else [| fromString $(stringE $ " `" ++ opName ++ "` ") |]
match (infixP (varP al) conName (varP ar))
(normalB $ appE [| showbParen ($(varE p) > conPrec) |]
[| $(mkShowForArg (conPrec + 1) sClass opName tvis alTy al)
<> $(infixOpE)
<> $(mkShowForArg (conPrec + 1) sClass opName tvis arTy ar)
|]
)
[]
mkShowForCon p sClass tvis (ForallC tvbs _ con) = mkShowForCon p sClass (removeForalled tvbs tvis) con
mkShowForArg :: Int
-> ShowClass
-> String
-> [TyVarInfo]
-> Type
-> Name
-> Q Exp
mkShowForArg p sClass conName tvis ty tyExpName = do
ty' <- expandSyn ty
mkShowForArg' p sClass conName tvis ty' tyExpName
mkShowForArg' :: Int
-> ShowClass
-> String
-> [TyVarInfo]
-> Type
-> Name
-> Q Exp
mkShowForArg' p _ _ _ (ConT tyName) tyExpName =
#if __GLASGOW_HASKELL__ >= 711
showE
where
tyVarE :: Q Exp
tyVarE = varE tyExpName
showE :: Q Exp
showE | tyName == ''Char# = [| showbPrec 0 (C# $(tyVarE)) <> singleton '#' |]
| tyName == ''Double# = [| showbPrec 0 (D# $(tyVarE)) <> fromString "##" |]
| tyName == ''Float# = [| showbPrec 0 (F# $(tyVarE)) <> singleton '#' |]
| tyName == ''Int# = [| showbPrec 0 (I# $(tyVarE)) <> singleton '#' |]
| tyName == ''Word# = [| showbPrec 0 (W# $(tyVarE)) <> fromString "##" |]
| otherwise = [| showbPrec p $(tyVarE) |]
#else
[| showbPrec p $(expr) |]
where
tyVarE :: Q Exp
tyVarE = varE tyExpName
expr :: Q Exp
expr | tyName == ''Char# = [| C# $(tyVarE) |]
| tyName == ''Double# = [| D# $(tyVarE) |]
| tyName == ''Float# = [| F# $(tyVarE) |]
| tyName == ''Int# = [| I# $(tyVarE) |]
| tyName == ''Word# = [| W# $(tyVarE) |]
| otherwise = tyVarE
#endif
mkShowForArg' p sClass conName tvis ty tyExpName =
[| $(mkShowForType sClass conName tvis ty) p $(varE tyExpName) |]
mkShowForType :: ShowClass
-> String
-> [TyVarInfo]
-> Type
-> Q Exp
mkShowForType _ _ tvis (VarT tyName) =
case lookup (NameBase tyName) tvis of
Just spExp -> varE spExp
Nothing -> [| showbPrec |]
mkShowForType sClass conName tvis (SigT ty _) = mkShowForType sClass conName tvis ty
mkShowForType sClass conName tvis (ForallT tvbs _ ty) = mkShowForType sClass conName (removeForalled tvbs tvis) ty
mkShowForType sClass conName tvis ty = do
let tyArgs :: [Type]
tyCon :| tyArgs = unapplyTy ty
numLastArgs :: Int
numLastArgs = min (fromEnum sClass) (length tyArgs)
lhsArgs, rhsArgs :: [Type]
(lhsArgs, rhsArgs) = splitAt (length tyArgs numLastArgs) tyArgs
tyVarNameBases :: [NameBase]
tyVarNameBases = map fst tvis
itf <- isTyFamily tyCon
if any (`mentionsNameBase` tyVarNameBases) lhsArgs
|| itf && any (`mentionsNameBase` tyVarNameBases) tyArgs
then outOfPlaceTyVarError conName tyVarNameBases numLastArgs
else appsE $ [ varE . showbPrecNameTable $ toEnum numLastArgs]
++ map (mkShowForType sClass conName tvis) rhsArgs
withTyCon :: Name
-> (Cxt -> [TyVarBndr] -> [Con] -> Q a)
-> Q a
withTyCon name f = do
info <- reify name
case info of
TyConI dec ->
case dec of
DataD ctxt _ tvbs cons _ -> f ctxt tvbs cons
NewtypeD ctxt _ tvbs con _ -> f ctxt tvbs [con]
other -> error $ ns ++ "Unsupported type " ++ S.show other ++ ". Must be a data type or newtype."
_ -> error $ ns ++ "The name must be of a plain type constructor."
where
ns :: String
ns = "Text.Show.Text.TH.withTyCon: "
#if MIN_VERSION_template_haskell(2,7,0)
withDataFam :: Name
-> ([TyVarBndr] -> [Dec] -> Q a)
-> Q a
withDataFam name f = do
info <- reify name
case info of
FamilyI (FamilyD DataFam _ tvbs _) decs -> f tvbs decs
FamilyI (FamilyD TypeFam _ _ _) _ ->
error $ ns ++ "Cannot use a type family name."
other -> error $ ns ++ "Unsupported type " ++ S.show other ++ ". Must be a data family name."
where
ns :: String
ns = "Text.Show.Text.TH.withDataFam: "
withDataFamInstCon :: Name
-> ([TyVarBndr] -> Cxt -> Name -> [Type] -> [Con] -> Q a)
-> Q a
withDataFamInstCon dficName f = do
dficInfo <- reify dficName
case dficInfo of
DataConI _ _ parentName _ -> do
parentInfo <- reify parentName
case parentInfo of
FamilyI (FamilyD DataFam _ _ _) _ -> withDataFam parentName $ \famTvbs decs ->
let sameDefDec = flip find decs $ \dec ->
case dec of
DataInstD _ _ _ cons' _ -> any ((dficName ==) . constructorName) cons'
NewtypeInstD _ _ _ con _ -> dficName == constructorName con
_ -> error $ ns ++ "Must be a data or newtype instance."
(ctxt, instTys, cons) = case sameDefDec of
Just (DataInstD ctxt' _ instTys' cons' _) -> (ctxt', instTys', cons')
Just (NewtypeInstD ctxt' _ instTys' con _) -> (ctxt', instTys', [con])
_ -> error $ ns ++ "Could not find data or newtype instance constructor."
in f famTvbs ctxt parentName instTys cons
_ -> error $ ns ++ "Data constructor " ++ S.show dficName ++ " is not from a data family instance."
other -> error $ ns ++ "Unsupported type " ++ S.show other ++ ". Must be a data family instance constructor."
where
ns :: String
ns = "Text.Show.Text.TH.withDataFamInstCon: "
#endif
cxtAndTypePlainTy :: ShowClass
-> Name
-> Cxt
-> [TyVarBndr]
-> (Cxt, Type, [NameBase])
cxtAndTypePlainTy sClass tyConName dataCxt tvbs =
if remainingLength < 0 || not (wellKinded droppedKinds)
then derivingKindError sClass tyConName
else if any (`predMentionsNameBase` droppedNbs) dataCxt
then datatypeContextError sClass instanceType
else (instanceCxt, instanceType, droppedNbs)
where
instanceCxt :: Cxt
instanceCxt = map (applyShowConstraint)
$ filter (needsConstraint sClass . tvbKind) remaining
instanceType :: Type
instanceType = applyTyCon tyConName $ map (VarT . tvbName) remaining
remainingLength :: Int
remainingLength = length tvbs fromEnum sClass
remaining, dropped :: [TyVarBndr]
(remaining, dropped) = splitAt remainingLength tvbs
droppedKinds :: [Kind]
droppedKinds = map tvbKind dropped
droppedNbs :: [NameBase]
droppedNbs = map (NameBase . tvbName) dropped
#if MIN_VERSION_template_haskell(2,7,0)
cxtAndTypeDataFamInstCon :: ShowClass
-> Name
-> Cxt
-> [TyVarBndr]
-> [Type]
-> (Cxt, Type, [NameBase])
cxtAndTypeDataFamInstCon sClass parentName dataCxt famTvbs instTysAndKinds =
if remainingLength < 0 || not (wellKinded droppedKinds)
then derivingKindError sClass parentName
else if any (`predMentionsNameBase` droppedNbs) dataCxt
then datatypeContextError sClass instanceType
else if canEtaReduce remaining dropped
then (instanceCxt, instanceType, droppedNbs)
else etaReductionError instanceType
where
instanceCxt :: Cxt
instanceCxt = map (applyShowConstraint)
$ filter (needsConstraint sClass . tvbKind) lhsTvbs
instanceType :: Type
instanceType = applyTyCon parentName
$ map unSigT remaining
remainingLength :: Int
remainingLength = length famTvbs fromEnum sClass
remaining, dropped :: [Type]
(remaining, dropped) = splitAt remainingLength rhsTypes
droppedKinds :: [Kind]
droppedKinds = map tvbKind . snd $ splitAt remainingLength famTvbs
droppedNbs :: [NameBase]
droppedNbs = map varTToNameBase dropped
instTypes :: [Type]
instTypes =
# if __GLASGOW_HASKELL__ >= 710 || !(MIN_VERSION_template_haskell(2,8,0))
instTysAndKinds
# else
drop (Set.size . Set.unions $ map (distinctKindVars . tvbKind) famTvbs)
instTysAndKinds
# endif
lhsTvbs :: [TyVarBndr]
lhsTvbs = map (uncurry replaceTyVarName)
. filter (isTyVar . snd)
. take remainingLength
$ zip famTvbs rhsTypes
rhsTypes :: [Type]
rhsTypes =
# if __GLASGOW_HASKELL__ >= 708 && __GLASGOW_HASKELL__ < 710
instTypes ++ map tvbToType
(drop (length instTypes)
famTvbs)
# else
instTypes
# endif
#endif
applyShowConstraint :: TyVarBndr -> Pred
applyShowConstraint (PlainTV name) = applyClass ''T.Show name
applyShowConstraint (KindedTV name kind) = applyClass className name
where
className :: Name
className = showClassNameTable . toEnum $ numKindArrows kind
needsConstraint :: ShowClass -> Kind -> Bool
needsConstraint sClass kind =
sClass >= toEnum (numKindArrows kind)
&& canRealizeKindStarChain kind
derivingKindError :: ShowClass -> Name -> a
derivingKindError sClass tyConName = error
. showString "Cannot derive well-kinded instance of form ‘"
. showString className
. showChar ' '
. showParen True
( showString (nameBase tyConName)
. showString " ..."
)
. showString "‘\n\tClass "
. showString className
. showString " expects an argument of kind "
. showString (pprint . createKindChain $ fromEnum sClass)
$ ""
where
className :: String
className = nameBase $ showClassNameTable sClass
etaReductionError :: Type -> a
etaReductionError instanceType = error $
"Cannot eta-reduce to an instance of form \n\tinstance (...) => "
++ pprint instanceType
datatypeContextError :: ShowClass -> Type -> a
datatypeContextError sClass instanceType = error
. showString "Can't make a derived instance of ‘"
. showString (pprint instanceType)
. showString "‘:\n\tData type ‘"
. showString className
. showString "‘ must not have a class context involving the last type argument(s)"
$ ""
where
className :: String
className = nameBase $ showClassNameTable sClass
outOfPlaceTyVarError :: String -> [NameBase] -> Int -> a
outOfPlaceTyVarError conName tyVarNames numLastArgs = error
. showString "Constructor ‘"
. showString conName
. showString "‘ must use the type variable"
. plural id (showChar 's')
. showString " "
. showsPrec 0 tyVarNames
. showString " only in the last "
. plural id (showsPrec 0 numLastArgs)
. showString "argument"
. plural id (showChar 's')
. showString " of a data type"
$ ""
where
plural :: ShowS -> ShowS -> ShowS
plural one many = case numLastArgs of
1 -> one
_ -> many
#if !(MIN_VERSION_template_haskell(2,7,0))
dataConIError :: a
dataConIError = error
. showString "Cannot use a data constructor."
. showString "\n\t(Note: if you are trying to derive Show for a type family,"
. showString "\n\tuse GHC >= 7.4 instead.)"
$ ""
#endif
expandSyn :: Type -> Q Type
expandSyn (ForallT tvs ctx t) = fmap (ForallT tvs ctx) $ expandSyn t
expandSyn t@AppT{} = expandSynApp t []
expandSyn t@ConT{} = expandSynApp t []
expandSyn (SigT t _) = expandSyn t
expandSyn t = return t
expandSynApp :: Type -> [Type] -> Q Type
expandSynApp (AppT t1 t2) ts = do
t2' <- expandSyn t2
expandSynApp t1 (t2':ts)
expandSynApp (ConT n) ts | nameBase n == "[]" = return $ foldl' AppT ListT ts
expandSynApp t@(ConT n) ts = do
info <- reify n
case info of
TyConI (TySynD _ tvs rhs) ->
let (ts', ts'') = splitAt (length tvs) ts
subs = mkSubst tvs ts'
rhs' = subst subs rhs
in expandSynApp rhs' ts''
_ -> return $ foldl' AppT t ts
expandSynApp t ts = do
t' <- expandSyn t
return $ foldl' AppT t' ts
type Subst = Map Name Type
mkSubst :: [TyVarBndr] -> [Type] -> Subst
mkSubst vs ts =
let vs' = map un vs
un (PlainTV v) = v
un (KindedTV v _) = v
in Map.fromList $ zip vs' ts
subst :: Subst -> Type -> Type
subst subs (ForallT v c t) = ForallT v c $ subst subs t
subst subs t@(VarT n) = fromMaybe t $ Map.lookup n subs
subst subs (AppT t1 t2) = AppT (subst subs t1) (subst subs t2)
subst subs (SigT t k) = SigT (subst subs t) k
subst _ t = t
data ShowClass = Show | Show1 | Show2
deriving (Enum, Eq, Ord)
showbPrecConstNameTable :: ShowClass -> Name
showbPrecConstNameTable Show = 'showbPrecConst
showbPrecConstNameTable Show1 = 'showbPrecWithConst
showbPrecConstNameTable Show2 = 'showbPrecWith2Const
showClassNameTable :: ShowClass -> Name
showClassNameTable Show = ''T.Show
showClassNameTable Show1 = ''Show1
showClassNameTable Show2 = ''Show2
showbPrecNameTable :: ShowClass -> Name
showbPrecNameTable Show = 'showbPrec
showbPrecNameTable Show1 = 'showbPrecWith
showbPrecNameTable Show2 = 'showbPrecWith2
showbPrecConst :: Builder -> Int -> a -> Builder
showbPrecConst = const . const
showbPrecWithConst :: Builder -> (Int -> a -> Builder) -> Int -> f a -> Builder
showbPrecWithConst = const . const . const
showbPrecWith2Const :: Builder -> (Int -> a -> Builder) -> (Int -> b -> Builder)
-> Int -> f a b -> Builder
showbPrecWith2Const = const . const . const . const
newtype NameBase = NameBase { getName :: Name }
getNameBase :: NameBase -> String
getNameBase = nameBase . getName
instance Eq NameBase where
(==) = (==) `on` getNameBase
instance Ord NameBase where
compare = compare `on` getNameBase
instance S.Show NameBase where
showsPrec p = showsPrec p . getNameBase
type TyVarInfo = (NameBase, Name)
newNameList :: String -> Int -> Q [Name]
newNameList prefix n = mapM (newName . (prefix ++) . S.show) [1..n]
removeForalled :: [TyVarBndr] -> [TyVarInfo] -> [TyVarInfo]
removeForalled tvbs = filter (not . foralled tvbs)
where
foralled :: [TyVarBndr] -> TyVarInfo -> Bool
foralled tvbs' tvi = fst tvi `elem` map (NameBase . tvbName) tvbs'
isNonUnitTuple :: Name -> Bool
isNonUnitTuple = isTupleString . nameBase
parenInfixConName :: Name -> ShowS
parenInfixConName conName =
let conNameBase = nameBase conName
in showParen (isInfixTypeCon conNameBase) $ showString conNameBase
tvbName :: TyVarBndr -> Name
tvbName (PlainTV name) = name
tvbName (KindedTV name _) = name
tvbKind :: TyVarBndr -> Kind
tvbKind (PlainTV _) = starK
tvbKind (KindedTV _ k) = k
replaceTyVarName :: TyVarBndr -> Type -> TyVarBndr
replaceTyVarName tvb (SigT t _) = replaceTyVarName tvb t
replaceTyVarName (PlainTV _) (VarT n) = PlainTV n
replaceTyVarName (KindedTV _ k) (VarT n) = KindedTV n k
replaceTyVarName tvb _ = tvb
applyClass :: Name -> Name -> Pred
#if MIN_VERSION_template_haskell(2,10,0)
applyClass con t = AppT (ConT con) (VarT t)
#else
applyClass con t = ClassP con [VarT t]
#endif
canEtaReduce :: [Type] -> [Type] -> Bool
canEtaReduce remaining dropped =
all isTyVar dropped
&& allDistinct nbs
&& not (any (`mentionsNameBase` nbs) remaining)
where
nbs :: [NameBase]
nbs = map varTToNameBase dropped
varTToName :: Type -> Name
varTToName (VarT n) = n
varTToName (SigT t _) = varTToName t
varTToName _ = error "Not a type variable!"
varTToNameBase :: Type -> NameBase
varTToNameBase = NameBase . varTToName
unSigT :: Type -> Type
unSigT (SigT t _) = t
unSigT t = t
isTyVar :: Type -> Bool
isTyVar (VarT _) = True
isTyVar (SigT t _) = isTyVar t
isTyVar _ = False
isTyFamily :: Type -> Q Bool
isTyFamily (ConT n) = do
info <- reify n
return $ case info of
#if MIN_VERSION_template_haskell(2,7,0)
FamilyI (FamilyD TypeFam _ _ _) _ -> True
#else
TyConI (FamilyD TypeFam _ _ _) -> True
#endif
_ -> False
isTyFamily _ = return False
allDistinct :: Ord a => [a] -> Bool
allDistinct = allDistinct' Set.empty
where
allDistinct' :: Ord a => Set a -> [a] -> Bool
allDistinct' uniqs (x:xs)
| x `Set.member` uniqs = False
| otherwise = allDistinct' (Set.insert x uniqs) xs
allDistinct' _ _ = True
mentionsNameBase :: Type -> [NameBase] -> Bool
mentionsNameBase = go Set.empty
where
go :: Set NameBase -> Type -> [NameBase] -> Bool
go foralls (ForallT tvbs _ t) nbs =
go (foralls `Set.union` Set.fromList (map (NameBase . tvbName) tvbs)) t nbs
go foralls (AppT t1 t2) nbs = go foralls t1 nbs || go foralls t2 nbs
go foralls (SigT t _) nbs = go foralls t nbs
go foralls (VarT n) nbs = varNb `elem` nbs && not (varNb `Set.member` foralls)
where
varNb = NameBase n
go _ _ _ = False
predMentionsNameBase :: Pred -> [NameBase] -> Bool
#if MIN_VERSION_template_haskell(2,10,0)
predMentionsNameBase = mentionsNameBase
#else
predMentionsNameBase (ClassP _ tys) nbs = any (`mentionsNameBase` nbs) tys
predMentionsNameBase (EqualP t1 t2) nbs = mentionsNameBase t1 nbs || mentionsNameBase t2 nbs
#endif
numKindArrows :: Kind -> Int
numKindArrows k = length (uncurryKind k) 1
applyTy :: Type -> [Type] -> Type
applyTy = foldl' AppT
applyTyCon :: Name -> [Type] -> Type
applyTyCon = applyTy . ConT
unapplyTy :: Type -> NonEmpty Type
unapplyTy = NE.reverse . go
where
go :: Type -> NonEmpty Type
go (AppT t1 t2) = t2 <| go t1
go (SigT t _) = go t
go t = t :| []
uncurryTy :: Type -> NonEmpty Type
uncurryTy (AppT (AppT ArrowT t1) t2) = t1 <| uncurryTy t2
uncurryTy (SigT t _) = uncurryTy t
uncurryTy t = t :| []
uncurryKind :: Kind -> NonEmpty Kind
#if MIN_VERSION_template_haskell(2,8,0)
uncurryKind = uncurryTy
#else
uncurryKind (ArrowK k1 k2) = k1 <| uncurryKind k2
uncurryKind k = k :| []
#endif
wellKinded :: [Kind] -> Bool
wellKinded = all canRealizeKindStar
canRealizeKindStarChain :: Kind -> Bool
canRealizeKindStarChain = all canRealizeKindStar . uncurryKind
canRealizeKindStar :: Kind -> Bool
canRealizeKindStar k = case uncurryKind k of
k' :| [] -> case k' of
#if MIN_VERSION_template_haskell(2,8,0)
StarT -> True
(VarT _) -> True
#else
StarK -> True
#endif
_ -> False
_ -> False
createKindChain :: Int -> Kind
createKindChain = go starK
where
go :: Kind -> Int -> Kind
go k !0 = k
#if MIN_VERSION_template_haskell(2,8,0)
go k !n = go (AppT (AppT ArrowT StarT) k) (n 1)
#else
go k !n = go (ArrowK StarK k) (n 1)
#endif
# if MIN_VERSION_template_haskell(2,8,0) && __GLASGOW_HASKELL__ < 710
distinctKindVars :: Kind -> Set Name
distinctKindVars (AppT k1 k2) = distinctKindVars k1 `Set.union` distinctKindVars k2
distinctKindVars (SigT k _) = distinctKindVars k
distinctKindVars (VarT k) = Set.singleton k
distinctKindVars _ = Set.empty
#endif
#if __GLASGOW_HASKELL__ >= 708 && __GLASGOW_HASKELL__ < 710
tvbToType :: TyVarBndr -> Type
tvbToType (PlainTV n) = VarT n
tvbToType (KindedTV n k) = SigT (VarT n) k
#endif
#if MIN_VERSION_template_haskell(2,7,0)
constructorName :: Con -> Name
constructorName (NormalC name _ ) = name
constructorName (RecC name _ ) = name
constructorName (InfixC _ name _ ) = name
constructorName (ForallC _ _ con) = constructorName con
#endif