{-# Language CPP, DeriveDataTypeable #-}
#if MIN_VERSION_base(4,4,0)
#define HAS_GENERICS
{-# Language DeriveGeneric #-}
#endif
module Language.Haskell.TH.Datatype
(
DatatypeInfo(..)
, ConstructorInfo(..)
, DatatypeVariant(..)
, ConstructorVariant(..)
, FieldStrictness(..)
, Unpackedness(..)
, Strictness(..)
, reifyDatatype
, reifyConstructor
, reifyRecord
, normalizeInfo
, normalizeDec
, normalizeCon
, lookupByConstructorName
, lookupByRecordName
, TypeSubstitution(..)
, quantifyType
, freeVariablesWellScoped
, freshenFreeVariables
, equalPred
, classPred
, asEqualPred
, asClassPred
, dataDCompat
, newtypeDCompat
, tySynInstDCompat
, pragLineDCompat
, arrowKCompat
, isStrictAnnot
, notStrictAnnot
, unpackedAnnot
, resolveTypeSynonyms
, resolveKindSynonyms
, resolvePredSynonyms
, resolveInfixT
, reifyFixityCompat
, showFixity
, showFixityDirection
, unifyTypes
, tvName
, tvKind
, datatypeType
) where
import Data.Data (Typeable, Data)
import Data.Foldable (foldMap, foldl')
import Data.List (nub, find, union, (\\))
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe
import qualified Data.Set as Set
import Data.Set (Set)
import qualified Data.Traversable as T
import Control.Monad
import Language.Haskell.TH
#if MIN_VERSION_template_haskell(2,11,0)
hiding (Extension(..))
#endif
import Language.Haskell.TH.Datatype.Internal
import Language.Haskell.TH.Lib (arrowK, starK)
#ifdef HAS_GENERICS
import GHC.Generics (Generic)
#endif
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative (Applicative(..), (<$>))
import Data.Monoid (Monoid(..))
#endif
data DatatypeInfo = DatatypeInfo
{ datatypeContext :: Cxt
, datatypeName :: Name
, datatypeVars :: [TyVarBndr]
, datatypeInstTypes :: [Type]
, datatypeVariant :: DatatypeVariant
, datatypeCons :: [ConstructorInfo]
}
deriving (Show, Eq, Typeable, Data
#ifdef HAS_GENERICS
,Generic
#endif
)
data DatatypeVariant
= Datatype
| Newtype
| DataInstance
| NewtypeInstance
deriving (Show, Read, Eq, Ord, Typeable, Data
#ifdef HAS_GENERICS
,Generic
#endif
)
data ConstructorInfo = ConstructorInfo
{ constructorName :: Name
, constructorVars :: [TyVarBndr]
, constructorContext :: Cxt
, constructorFields :: [Type]
, constructorStrictness :: [FieldStrictness]
, constructorVariant :: ConstructorVariant
}
deriving (Show, Eq, Typeable, Data
#ifdef HAS_GENERICS
,Generic
#endif
)
data ConstructorVariant
= NormalConstructor
| InfixConstructor
| RecordConstructor [Name]
deriving (Show, Eq, Ord, Typeable, Data
#ifdef HAS_GENERICS
,Generic
#endif
)
data FieldStrictness = FieldStrictness
{ fieldUnpackedness :: Unpackedness
, fieldStrictness :: Strictness
}
deriving (Show, Eq, Ord, Typeable, Data
#ifdef HAS_GENERICS
,Generic
#endif
)
data Unpackedness
= UnspecifiedUnpackedness
| NoUnpack
| Unpack
deriving (Show, Eq, Ord, Typeable, Data
#ifdef HAS_GENERICS
,Generic
#endif
)
data Strictness
= UnspecifiedStrictness
| Lazy
| Strict
deriving (Show, Eq, Ord, Typeable, Data
#ifdef HAS_GENERICS
,Generic
#endif
)
isStrictAnnot, notStrictAnnot, unpackedAnnot :: FieldStrictness
isStrictAnnot = FieldStrictness UnspecifiedUnpackedness Strict
notStrictAnnot = FieldStrictness UnspecifiedUnpackedness UnspecifiedStrictness
unpackedAnnot = FieldStrictness Unpack Strict
datatypeType :: DatatypeInfo -> Type
datatypeType di
= foldl AppT (ConT (datatypeName di))
$ map stripSigT
$ datatypeInstTypes di
reifyDatatype ::
Name ->
Q DatatypeInfo
reifyDatatype n = normalizeInfo' "reifyDatatype" isReified =<< reify n
reifyConstructor ::
Name ->
Q ConstructorInfo
reifyConstructor conName = do
dataInfo <- reifyDatatype conName
return $ lookupByConstructorName conName dataInfo
reifyRecord ::
Name ->
Q ConstructorInfo
reifyRecord recordName = do
dataInfo <- reifyDatatype recordName
return $ lookupByRecordName recordName dataInfo
lookupByConstructorName ::
Name ->
DatatypeInfo ->
ConstructorInfo
lookupByConstructorName conName dataInfo =
case find ((== conName) . constructorName) (datatypeCons dataInfo) of
Just conInfo -> conInfo
Nothing -> error $ "Datatype " ++ nameBase (datatypeName dataInfo)
++ " does not have a constructor named " ++ nameBase conName
lookupByRecordName ::
Name ->
DatatypeInfo ->
ConstructorInfo
lookupByRecordName recordName dataInfo =
case find (conHasRecord recordName) (datatypeCons dataInfo) of
Just conInfo -> conInfo
Nothing -> error $ "Datatype " ++ nameBase (datatypeName dataInfo)
++ " does not have any constructors with a "
++ "record selector named " ++ nameBase recordName
normalizeInfo :: Info -> Q DatatypeInfo
normalizeInfo = normalizeInfo' "normalizeInfo" isn'tReified
normalizeInfo' :: String -> IsReifiedDec -> Info -> Q DatatypeInfo
normalizeInfo' entry reifiedDec i =
case i of
PrimTyConI{} -> bad "Primitive type not supported"
ClassI{} -> bad "Class not supported"
#if MIN_VERSION_template_haskell(2,11,0)
FamilyI DataFamilyD{} _ ->
#elif MIN_VERSION_template_haskell(2,7,0)
FamilyI (FamilyD DataFam _ _ _) _ ->
#else
TyConI (FamilyD DataFam _ _ _) ->
#endif
bad "Use a value constructor to reify a data family instance"
#if MIN_VERSION_template_haskell(2,7,0)
FamilyI _ _ -> bad "Type families not supported"
#endif
TyConI dec -> normalizeDecFor reifiedDec dec
#if MIN_VERSION_template_haskell(2,11,0)
DataConI name _ parent -> reifyParent name parent
#else
DataConI name _ parent _ -> reifyParent name parent
#endif
#if MIN_VERSION_template_haskell(2,11,0)
VarI recName recTy _ -> reifyRecordType recName recTy
#else
VarI recName recTy _ _ -> reifyRecordType recName recTy
#endif
_ -> bad "Expected a type constructor"
where
bad msg = fail (entry ++ ": " ++ msg)
reifyParent :: Name -> Name -> Q DatatypeInfo
reifyParent con = reifyParentWith "reifyParent" p
where
p :: DatatypeInfo -> Bool
p info = con `elem` map constructorName (datatypeCons info)
reifyRecordType :: Name -> Type -> Q DatatypeInfo
reifyRecordType recName recTy =
let (_, _, argTys :|- _) = uncurryType recTy
in case argTys of
dataTy:_ -> decomposeDataType dataTy
_ -> notRecSelFailure
where
decomposeDataType :: Type -> Q DatatypeInfo
decomposeDataType ty =
do case decomposeType ty of
ConT parent :| _ -> reifyParentWith "reifyRecordType" p parent
_ -> notRecSelFailure
notRecSelFailure :: Q a
notRecSelFailure = fail $
"reifyRecordType: Not a record selector type: " ++
nameBase recName ++ " :: " ++ show recTy
p :: DatatypeInfo -> Bool
p info = any (conHasRecord recName) (datatypeCons info)
reifyParentWith ::
String ->
(DatatypeInfo -> Bool) ->
Name ->
Q DatatypeInfo
reifyParentWith prefix p n =
do info <- reify n
case info of
#if !(MIN_VERSION_template_haskell(2,11,0))
TyConI FamilyD{} -> dataFamiliesOnOldGHCsError
#endif
TyConI dec -> normalizeDecFor isReified dec
#if MIN_VERSION_template_haskell(2,7,0)
FamilyI dec instances ->
do let instances1 = map (repairDataFam dec) instances
instances2 <- mapM (normalizeDecFor isReified) instances1
case find p instances2 of
Just inst -> return inst
Nothing -> panic "lost the instance"
#endif
_ -> panic "unexpected parent"
where
dataFamiliesOnOldGHCsError :: Q a
dataFamiliesOnOldGHCsError = fail $
prefix ++ ": Data family instances can only be reified with GHC 7.4 or later"
panic :: String -> Q a
panic message = fail $ "PANIC: " ++ prefix ++ " " ++ message
#if MIN_VERSION_template_haskell(2,8,0) && (!MIN_VERSION_template_haskell(2,10,0))
sanitizeStars :: Kind -> Kind
sanitizeStars = go
where
go :: Kind -> Kind
go (AppT t1 t2) = AppT (go t1) (go t2)
go (SigT t k) = SigT (go t) (go k)
go (ConT n) | n == starKindName = StarT
go t = t
repairVarKindsWith' :: [TyVarBndr] -> [Type] -> [Type]
repairVarKindsWith' dvars ts =
let kindVars = freeVariables . map kindPart
kindPart (KindedTV _ k) = [k]
kindPart (PlainTV _ ) = []
nparams = length dvars
kparams = kindVars dvars
(tsKinds,tsNoKinds) = splitAt (length kparams) ts
tsKinds' = map sanitizeStars tsKinds
extraTys = drop (length tsNoKinds) (bndrParams dvars)
ts' = tsNoKinds ++ extraTys
in applySubstitution (Map.fromList (zip kparams tsKinds')) $
repairVarKindsWith dvars ts'
repairDataFam ::
Dec ->
Dec ->
Dec
repairDataFam
(FamilyD _ _ dvars _)
(NewtypeInstD cx n ts con deriv) =
NewtypeInstD cx n (repairVarKindsWith' dvars ts) con deriv
repairDataFam
(FamilyD _ _ dvars _)
(DataInstD cx n ts cons deriv) =
DataInstD cx n (repairVarKindsWith' dvars ts) cons deriv
#else
repairDataFam famD instD
# if MIN_VERSION_template_haskell(2,15,0)
| DataFamilyD _ dvars _ <- famD
, NewtypeInstD cx mbInstVars nts k c deriv <- instD
, con :| ts <- decomposeType nts
= NewtypeInstD cx mbInstVars
(foldl' AppT con (repairVarKindsWith dvars ts))
k c deriv
| DataFamilyD _ dvars _ <- famD
, DataInstD cx mbInstVars nts k c deriv <- instD
, con :| ts <- decomposeType nts
= DataInstD cx mbInstVars
(foldl' AppT con (repairVarKindsWith dvars ts))
k c deriv
# elif MIN_VERSION_template_haskell(2,11,0)
| DataFamilyD _ dvars _ <- famD
, NewtypeInstD cx n ts k c deriv <- instD
= NewtypeInstD cx n (repairVarKindsWith dvars ts) k c deriv
| DataFamilyD _ dvars _ <- famD
, DataInstD cx n ts k c deriv <- instD
= DataInstD cx n (repairVarKindsWith dvars ts) k c deriv
# else
| FamilyD _ _ dvars _ <- famD
, NewtypeInstD cx n ts c deriv <- instD
= NewtypeInstD cx n (repairVarKindsWith dvars ts) c deriv
| FamilyD _ _ dvars _ <- famD
, DataInstD cx n ts c deriv <- instD
= DataInstD cx n (repairVarKindsWith dvars ts) c deriv
# endif
#endif
repairDataFam _ instD = instD
repairVarKindsWith :: [TyVarBndr] -> [Type] -> [Type]
repairVarKindsWith = zipWith stealKindForType
stealKindForType :: TyVarBndr -> Type -> Type
stealKindForType tvb t@VarT{} = SigT t (tvKind tvb)
stealKindForType _ t = t
normalizeDec :: Dec -> Q DatatypeInfo
normalizeDec = normalizeDecFor isn'tReified
normalizeDecFor :: IsReifiedDec -> Dec -> Q DatatypeInfo
normalizeDecFor isReified dec =
case dec of
#if MIN_VERSION_template_haskell(2,12,0)
NewtypeD context name tyvars mbKind con _derives ->
normalizeDataD context name tyvars mbKind [con] Newtype
DataD context name tyvars mbKind cons _derives ->
normalizeDataD context name tyvars mbKind cons Datatype
# if MIN_VERSION_template_haskell(2,15,0)
NewtypeInstD context mbTyvars nameInstTys mbKind con _derives ->
normalizeDataInstDPostTH2'15 "newtype" context mbTyvars nameInstTys
mbKind [con] NewtypeInstance
DataInstD context mbTyvars nameInstTys mbKind cons _derives ->
normalizeDataInstDPostTH2'15 "data" context mbTyvars nameInstTys
mbKind cons DataInstance
# else
NewtypeInstD context name instTys mbKind con _derives ->
normalizeDataInstDPreTH2'15 context name instTys mbKind [con] NewtypeInstance
DataInstD context name instTys mbKind cons _derives ->
normalizeDataInstDPreTH2'15 context name instTys mbKind cons DataInstance
# endif
#elif MIN_VERSION_template_haskell(2,11,0)
NewtypeD context name tyvars mbKind con _derives ->
normalizeDataD context name tyvars mbKind [con] Newtype
DataD context name tyvars mbKind cons _derives ->
normalizeDataD context name tyvars mbKind cons Datatype
NewtypeInstD context name instTys mbKind con _derives ->
normalizeDataInstDPreTH2'15 context name instTys mbKind [con] NewtypeInstance
DataInstD context name instTys mbKind cons _derives ->
normalizeDataInstDPreTH2'15 context name instTys mbKind cons DataInstance
#else
NewtypeD context name tyvars con _derives ->
normalizeDataD context name tyvars Nothing [con] Newtype
DataD context name tyvars cons _derives ->
normalizeDataD context name tyvars Nothing cons Datatype
NewtypeInstD context name instTys con _derives ->
normalizeDataInstDPreTH2'15 context name instTys Nothing [con] NewtypeInstance
DataInstD context name instTys cons _derives ->
normalizeDataInstDPreTH2'15 context name instTys Nothing cons DataInstance
#endif
_ -> fail "normalizeDecFor: DataD or NewtypeD required"
where
repair13618' :: DatatypeInfo -> Q DatatypeInfo
repair13618' di@DatatypeInfo{datatypeVariant = variant}
| isReified && isFamInstVariant variant
= repair13618 di
| otherwise
= return di
datatypeFreeVars :: [Type] -> Maybe Kind -> [TyVarBndr]
datatypeFreeVars instTys mbKind =
freeVariablesWellScoped $ instTys ++
#if MIN_VERSION_template_haskell(2,8,0)
maybeToList mbKind
#else
[]
#endif
normalizeDataD :: Cxt -> Name -> [TyVarBndr] -> Maybe Kind
-> [Con] -> DatatypeVariant -> Q DatatypeInfo
normalizeDataD context name tyvars mbKind cons variant =
let params = bndrParams tyvars in
normalize' context name (datatypeFreeVars params mbKind)
params mbKind cons variant
normalizeDataInstDPostTH2'15
:: String -> Cxt -> Maybe [TyVarBndr] -> Type -> Maybe Kind
-> [Con] -> DatatypeVariant -> Q DatatypeInfo
normalizeDataInstDPostTH2'15 what context mbTyvars nameInstTys
mbKind cons variant =
case decomposeType nameInstTys of
ConT name :| instTys ->
normalize' context name
(fromMaybe (datatypeFreeVars instTys mbKind) mbTyvars)
instTys mbKind cons variant
_ -> fail $ "Unexpected " ++ what ++ " instance head: " ++ pprint nameInstTys
normalizeDataInstDPreTH2'15
:: Cxt -> Name -> [Type] -> Maybe Kind
-> [Con] -> DatatypeVariant -> Q DatatypeInfo
normalizeDataInstDPreTH2'15 context name instTys mbKind cons variant =
normalize' context name (datatypeFreeVars instTys mbKind)
instTys mbKind cons variant
normalize' :: Cxt -> Name -> [TyVarBndr] -> [Type] -> Maybe Kind
-> [Con] -> DatatypeVariant -> Q DatatypeInfo
normalize' context name tvbs instTys mbKind cons variant = do
extra_tvbs <- mkExtraKindBinders $ fromMaybe starK mbKind
let tvbs' = tvbs ++ extra_tvbs
instTys' = instTys ++ bndrParams extra_tvbs
dec <- normalizeDec' isReified context name tvbs' instTys' cons variant
repair13618' $ giveDIVarsStarKinds dec
mkExtraKindBinders :: Kind -> Q [TyVarBndr]
mkExtraKindBinders kind = do
kind' <- resolveKindSynonyms kind
let (_, _, args :|- _) = uncurryKind kind'
names <- replicateM (length args) (newName "x")
return $ zipWith KindedTV names args
isFamInstVariant :: DatatypeVariant -> Bool
isFamInstVariant dv =
case dv of
Datatype -> False
Newtype -> False
DataInstance -> True
NewtypeInstance -> True
bndrParams :: [TyVarBndr] -> [Type]
bndrParams = map $ \bndr ->
case bndr of
KindedTV t k -> SigT (VarT t) k
PlainTV t -> VarT t
tvKind :: TyVarBndr -> Kind
tvKind (PlainTV _) = starK
tvKind (KindedTV _ k) = k
stripSigT :: Type -> Type
stripSigT (SigT t _) = t
stripSigT t = t
normalizeDec' ::
IsReifiedDec ->
Cxt ->
Name ->
[TyVarBndr] ->
[Type] ->
[Con] ->
DatatypeVariant ->
Q DatatypeInfo
normalizeDec' reifiedDec context name params instTys cons variant =
do cons' <- concat <$> mapM (normalizeConFor reifiedDec name params instTys variant) cons
return DatatypeInfo
{ datatypeContext = context
, datatypeName = name
, datatypeVars = params
, datatypeInstTypes = instTys
, datatypeCons = cons'
, datatypeVariant = variant
}
normalizeCon ::
Name ->
[TyVarBndr] ->
[Type] ->
DatatypeVariant ->
Con ->
Q [ConstructorInfo]
normalizeCon = normalizeConFor isn'tReified
normalizeConFor ::
IsReifiedDec ->
Name ->
[TyVarBndr] ->
[Type] ->
DatatypeVariant ->
Con ->
Q [ConstructorInfo]
normalizeConFor reifiedDec typename params instTys variant =
fmap (map giveCIVarsStarKinds) . dispatch
where
checkGadtFixity :: [Type] -> Name -> Q ConstructorVariant
checkGadtFixity ts n = do
#if MIN_VERSION_template_haskell(2,11,0)
mbFi <- return Nothing `recover` reifyFixity n
let userSuppliedFixity = isJust mbFi
#else
mbFi <- reifyFixityCompat n
let userSuppliedFixity = isJust mbFi && mbFi /= Just defaultFixity
#endif
return $ if isInfixDataCon (nameBase n)
&& length ts == 2
&& userSuppliedFixity
then InfixConstructor
else NormalConstructor
isInfixDataCon :: String -> Bool
isInfixDataCon (':':_) = True
isInfixDataCon _ = False
dispatch :: Con -> Q [ConstructorInfo]
dispatch =
let defaultCase :: Con -> Q [ConstructorInfo]
defaultCase = go [] [] False
where
go :: [TyVarBndr]
-> Cxt
-> Bool
-> Con
-> Q [ConstructorInfo]
go tyvars context gadt c =
case c of
NormalC n xs -> do
let (bangs, ts) = unzip xs
stricts = map normalizeStrictness bangs
fi <- if gadt
then checkGadtFixity ts n
else return NormalConstructor
return [ConstructorInfo n tyvars context ts stricts fi]
InfixC l n r ->
let (bangs, ts) = unzip [l,r]
stricts = map normalizeStrictness bangs in
return [ConstructorInfo n tyvars context ts stricts
InfixConstructor]
RecC n xs ->
let fns = takeFieldNames xs
stricts = takeFieldStrictness xs in
return [ConstructorInfo n tyvars context
(takeFieldTypes xs) stricts (RecordConstructor fns)]
ForallC tyvars' context' c' ->
go (tyvars'++tyvars) (context'++context) True c'
#if MIN_VERSION_template_haskell(2,11,0)
GadtC ns xs innerType ->
let (bangs, ts) = unzip xs
stricts = map normalizeStrictness bangs in
gadtCase ns innerType ts stricts (checkGadtFixity ts)
RecGadtC ns xs innerType ->
let fns = takeFieldNames xs
stricts = takeFieldStrictness xs in
gadtCase ns innerType (takeFieldTypes xs) stricts
(const $ return $ RecordConstructor fns)
where
gadtCase = normalizeGadtC typename params instTys tyvars context
#endif
#if MIN_VERSION_template_haskell(2,8,0) && (!MIN_VERSION_template_haskell(2,10,0))
dataFamCompatCase :: Con -> Q [ConstructorInfo]
dataFamCompatCase = go []
where
go tyvars c =
case c of
NormalC n xs ->
let stricts = map (normalizeStrictness . fst) xs in
dataFamCase' n stricts NormalConstructor
InfixC l n r ->
let stricts = map (normalizeStrictness . fst) [l,r] in
dataFamCase' n stricts InfixConstructor
RecC n xs ->
let stricts = takeFieldStrictness xs in
dataFamCase' n stricts
(RecordConstructor (takeFieldNames xs))
ForallC tyvars' context' c' ->
go (tyvars'++tyvars) c'
dataFamCase' :: Name -> [FieldStrictness]
-> ConstructorVariant
-> Q [ConstructorInfo]
dataFamCase' n stricts variant = do
mbInfo <- reifyMaybe n
case mbInfo of
Just (DataConI _ ty _ _) -> do
let (tyvars, context, argTys :|- returnTy) = uncurryType ty
returnTy' <- resolveTypeSynonyms returnTy
normalizeGadtC typename params instTys tyvars context [n]
returnTy' argTys stricts (const $ return variant)
_ -> fail $ unlines
[ "normalizeCon: Cannot reify constructor " ++ nameBase n
, "You are likely calling normalizeDec on GHC 7.6 or 7.8 on a data family"
, "whose type variables have been eta-reduced due to GHC Trac #9692."
, "Unfortunately, without being able to reify the constructor's type,"
, "there is no way to recover the eta-reduced type variables in general."
, "A recommended workaround is to use reifyDatatype instead."
]
mightHaveBeenEtaReduced :: [Type] -> Bool
mightHaveBeenEtaReduced ts =
case unsnoc ts of
Nothing -> False
Just (initTs :|- lastT) ->
case varTName lastT of
Nothing -> False
Just n -> not (n `elem` freeVariables initTs)
unsnoc :: [a] -> Maybe (NonEmptySnoc a)
unsnoc [] = Nothing
unsnoc (x:xs) = case unsnoc xs of
Just (a :|- b) -> Just ((x:a) :|- b)
Nothing -> Just ([] :|- x)
varTName :: Type -> Maybe Name
varTName (SigT t _) = varTName t
varTName (VarT n) = Just n
varTName _ = Nothing
in case variant of
DataInstance
| reifiedDec, mightHaveBeenEtaReduced instTys
-> dataFamCompatCase
NewtypeInstance
| reifiedDec, mightHaveBeenEtaReduced instTys
-> dataFamCompatCase
_ -> defaultCase
#else
in defaultCase
#endif
#if MIN_VERSION_template_haskell(2,11,0)
normalizeStrictness :: Bang -> FieldStrictness
normalizeStrictness (Bang upk str) =
FieldStrictness (normalizeSourceUnpackedness upk)
(normalizeSourceStrictness str)
where
normalizeSourceUnpackedness :: SourceUnpackedness -> Unpackedness
normalizeSourceUnpackedness NoSourceUnpackedness = UnspecifiedUnpackedness
normalizeSourceUnpackedness SourceNoUnpack = NoUnpack
normalizeSourceUnpackedness SourceUnpack = Unpack
normalizeSourceStrictness :: SourceStrictness -> Strictness
normalizeSourceStrictness NoSourceStrictness = UnspecifiedStrictness
normalizeSourceStrictness SourceLazy = Lazy
normalizeSourceStrictness SourceStrict = Strict
#else
normalizeStrictness :: Strict -> FieldStrictness
normalizeStrictness IsStrict = isStrictAnnot
normalizeStrictness NotStrict = notStrictAnnot
# if MIN_VERSION_template_haskell(2,7,0)
normalizeStrictness Unpacked = unpackedAnnot
# endif
#endif
normalizeGadtC ::
Name ->
[TyVarBndr] ->
[Type] ->
[TyVarBndr] ->
Cxt ->
[Name] ->
Type ->
[Type] ->
[FieldStrictness] ->
(Name -> Q ConstructorVariant)
->
Q [ConstructorInfo]
normalizeGadtC typename params instTys tyvars context names innerType
fields stricts getVariant =
do
let implicitTyvars = freeVariablesWellScoped
[curryType tyvars context fields innerType]
allTyvars = implicitTyvars ++ tyvars
let conBoundNames =
concatMap (\tvb -> tvName tvb:freeVariables (tvKind tvb)) allTyvars
conSubst <- T.sequence $ Map.fromList [ (n, newName (nameBase n))
| n <- conBoundNames ]
let conSubst' = fmap VarT conSubst
renamedTyvars =
map (\tvb -> case tvb of
PlainTV n -> PlainTV (conSubst Map.! n)
KindedTV n k -> KindedTV (conSubst Map.! n)
(applySubstitution conSubst' k)) allTyvars
renamedContext = applySubstitution conSubst' context
renamedInnerType = applySubstitution conSubst' innerType
renamedFields = applySubstitution conSubst' fields
innerType' <- resolveTypeSynonyms renamedInnerType
case decomposeType innerType' of
ConT innerTyCon :| ts | typename == innerTyCon ->
let (substName, context1) =
closeOverKinds (kindsOfFVsOfTvbs renamedTyvars)
(kindsOfFVsOfTvbs params)
(mergeArguments instTys ts)
subst = VarT <$> substName
exTyvars = [ tv | tv <- renamedTyvars, Map.notMember (tvName tv) subst ]
exTyvars' = substTyVarBndrs subst exTyvars
context2 = applySubstitution subst (context1 ++ renamedContext)
fields' = applySubstitution subst renamedFields
in sequence [ ConstructorInfo name exTyvars' context2
fields' stricts <$> variantQ
| name <- names
, let variantQ = getVariant name
]
_ -> fail "normalizeGadtC: Expected type constructor application"
closeOverKinds :: Map Name Kind
-> Map Name Kind
-> (Map Name Name, Cxt)
-> (Map Name Name, Cxt)
closeOverKinds domainFVKinds rangeFVKinds = go
where
go :: (Map Name Name, Cxt) -> (Map Name Name, Cxt)
go (subst, context) =
let substList = Map.toList subst
(kindsInner, kindsOuter) =
unzip $
mapMaybe (\(d, r) -> do d' <- Map.lookup d domainFVKinds
r' <- Map.lookup r rangeFVKinds
return (d', r'))
substList
(kindSubst, kindContext) = mergeArgumentKinds kindsOuter kindsInner
(restSubst, restContext)
= if Map.null kindSubst
then (Map.empty, [])
else go (kindSubst, kindContext)
finalSubst = Map.unions [subst, kindSubst, restSubst]
finalContext = nub $ concat [context, kindContext, restContext]
in (finalSubst, finalContext)
kindsOfFVsOfTypes :: [Type] -> Map Name Kind
kindsOfFVsOfTypes = foldMap go
where
go :: Type -> Map Name Kind
go (AppT t1 t2) = go t1 `Map.union` go t2
go (SigT t k) =
let kSigs =
#if MIN_VERSION_template_haskell(2,8,0)
go k
#else
Map.empty
#endif
in case t of
VarT n -> Map.insert n k kSigs
_ -> go t `Map.union` kSigs
go (ForallT {}) = forallError
#if MIN_VERSION_template_haskell(2,16,0)
go (ForallVisT {}) = forallError
#endif
go _ = Map.empty
forallError :: a
forallError = error "`forall` type used in data family pattern"
kindsOfFVsOfTvbs :: [TyVarBndr] -> Map Name Kind
kindsOfFVsOfTvbs = foldMap go
where
go :: TyVarBndr -> Map Name Kind
go (PlainTV n) = Map.singleton n starK
go (KindedTV n k) =
let kSigs =
#if MIN_VERSION_template_haskell(2,8,0)
kindsOfFVsOfTypes [k]
#else
Map.empty
#endif
in Map.insert n k kSigs
mergeArguments ::
[Type] ->
[Type] ->
(Map Name Name, Cxt)
mergeArguments ns ts = foldr aux (Map.empty, []) (zip ns ts)
where
aux (f `AppT` x, g `AppT` y) sc =
aux (x,y) (aux (f,g) sc)
aux (VarT n,p) (subst, context) =
case p of
VarT m | m == n -> (subst, context)
| Just n' <- Map.lookup m subst
, n == n' -> (subst, context)
| Map.notMember m subst -> (Map.insert m n subst, context)
_ -> (subst, equalPred (VarT n) p : context)
aux (SigT x _, y) sc = aux (x,y) sc
aux (x, SigT y _) sc = aux (x,y) sc
aux _ sc = sc
mergeArgumentKinds ::
[Kind] ->
[Kind] ->
(Map Name Name, Cxt)
#if MIN_VERSION_template_haskell(2,8,0)
mergeArgumentKinds = mergeArguments
#else
mergeArgumentKinds _ _ = (Map.empty, [])
#endif
resolveTypeSynonyms :: Type -> Q Type
resolveTypeSynonyms t =
let (f, xs) = decomposeTypeArgs t
notTypeSynCase :: Type -> Q Type
notTypeSynCase ty = foldl appTypeArg ty <$> mapM resolveTypeArgSynonyms xs
expandCon :: Name
-> Type
-> Q Type
expandCon n ty = do
mbInfo <- reifyMaybe n
case mbInfo of
Just (TyConI (TySynD _ synvars def))
-> resolveTypeSynonyms $ expandSynonymRHS synvars (filterTANormals xs) def
_ -> notTypeSynCase ty
in case f of
ForallT tvbs ctxt body ->
ForallT `fmap` mapM resolve_tvb_syns tvbs
`ap` mapM resolvePredSynonyms ctxt
`ap` resolveTypeSynonyms body
SigT ty ki -> do
ty' <- resolveTypeSynonyms ty
ki' <- resolveKindSynonyms ki
notTypeSynCase $ SigT ty' ki'
ConT n -> expandCon n (ConT n)
#if MIN_VERSION_template_haskell(2,11,0)
InfixT t1 n t2 -> do
t1' <- resolveTypeSynonyms t1
t2' <- resolveTypeSynonyms t2
expandCon n (InfixT t1' n t2')
UInfixT t1 n t2 -> do
t1' <- resolveTypeSynonyms t1
t2' <- resolveTypeSynonyms t2
expandCon n (UInfixT t1' n t2')
#endif
#if MIN_VERSION_template_haskell(2,15,0)
ImplicitParamT n t -> do
ImplicitParamT n <$> resolveTypeSynonyms t
#endif
#if MIN_VERSION_template_haskell(2,16,0)
ForallVisT tvbs body ->
ForallVisT `fmap` mapM resolve_tvb_syns tvbs
`ap` resolveTypeSynonyms body
#endif
_ -> notTypeSynCase f
resolveTypeArgSynonyms :: TypeArg -> Q TypeArg
resolveTypeArgSynonyms (TANormal t) = TANormal <$> resolveTypeSynonyms t
resolveTypeArgSynonyms (TyArg k) = TyArg <$> resolveKindSynonyms k
resolveKindSynonyms :: Kind -> Q Kind
#if MIN_VERSION_template_haskell(2,8,0)
resolveKindSynonyms = resolveTypeSynonyms
#else
resolveKindSynonyms = return
#endif
resolve_tvb_syns :: TyVarBndr -> Q TyVarBndr
resolve_tvb_syns tvb@PlainTV{} = return tvb
resolve_tvb_syns (KindedTV n k) = KindedTV n <$> resolveKindSynonyms k
expandSynonymRHS ::
[TyVarBndr] ->
[Type] ->
Type ->
Type
expandSynonymRHS synvars ts def =
let argNames = map tvName synvars
(args,rest) = splitAt (length argNames) ts
subst = Map.fromList (zip argNames args)
in foldl AppT (applySubstitution subst def) rest
resolvePredSynonyms :: Pred -> Q Pred
#if MIN_VERSION_template_haskell(2,10,0)
resolvePredSynonyms = resolveTypeSynonyms
#else
resolvePredSynonyms (ClassP n ts) = do
mbInfo <- reifyMaybe n
case mbInfo of
Just (TyConI (TySynD _ synvars def))
-> resolvePredSynonyms $ typeToPred $ expandSynonymRHS synvars ts def
_ -> ClassP n <$> mapM resolveTypeSynonyms ts
resolvePredSynonyms (EqualP t1 t2) = do
t1' <- resolveTypeSynonyms t1
t2' <- resolveTypeSynonyms t2
return (EqualP t1' t2')
typeToPred :: Type -> Pred
typeToPred t =
let f :| xs = decomposeType t in
case f of
ConT n
| n == eqTypeName
# if __GLASGOW_HASKELL__ == 704
, [_,t1,t2] <- xs
# else
, [t1,t2] <- xs
# endif
-> EqualP t1 t2
| otherwise
-> ClassP n xs
_ -> error $ "typeToPred: Can't handle type " ++ show t
#endif
decomposeType :: Type -> NonEmpty Type
decomposeType t =
case decomposeTypeArgs t of
(f, x) -> f :| filterTANormals x
decomposeTypeArgs :: Type -> (Type, [TypeArg])
decomposeTypeArgs = go []
where
go :: [TypeArg] -> Type -> (Type, [TypeArg])
go args (AppT f x) = go (TANormal x:args) f
#if MIN_VERSION_template_haskell(2,11,0)
go args (ParensT t) = go args t
#endif
#if MIN_VERSION_template_haskell(2,15,0)
go args (AppKindT f x) = go (TyArg x:args) f
#endif
go args t = (t, args)
data TypeArg
= TANormal Type
| TyArg Kind
appTypeArg :: Type -> TypeArg -> Type
appTypeArg f (TANormal x) = f `AppT` x
appTypeArg f (TyArg _k) =
#if MIN_VERSION_template_haskell(2,15,0)
f `AppKindT` _k
#else
f
#endif
filterTANormals :: [TypeArg] -> [Type]
filterTANormals = mapMaybe f
where
f :: TypeArg -> Maybe Type
f (TANormal t) = Just t
f (TyArg {}) = Nothing
data NonEmpty a = a :| [a]
data NonEmptySnoc a = [a] :|- a
uncurryType :: Type -> ([TyVarBndr], Cxt, NonEmptySnoc Type)
uncurryType = go [] [] []
where
go tvbs ctxt args (AppT (AppT ArrowT t1) t2) = go tvbs ctxt (t1:args) t2
go tvbs ctxt args (ForallT tvbs' ctxt' t) = go (tvbs++tvbs') (ctxt++ctxt') args t
go tvbs ctxt args t = (tvbs, ctxt, reverse args :|- t)
uncurryKind :: Kind -> ([TyVarBndr], Cxt, NonEmptySnoc Kind)
#if MIN_VERSION_template_haskell(2,8,0)
uncurryKind = uncurryType
#else
uncurryKind = go []
where
go args (ArrowK k1 k2) = go (k1:args) k2
go args StarK = ([], [], reverse args :|- StarK)
#endif
curryType :: [TyVarBndr] -> Cxt -> [Type] -> Type -> Type
curryType tvbs ctxt args res =
ForallT tvbs ctxt $ foldr (\arg t -> ArrowT `AppT` arg `AppT` t) res args
resolveInfixT :: Type -> Q Type
#if MIN_VERSION_template_haskell(2,11,0)
resolveInfixT (ForallT vs cx t) = ForallT <$> traverse (traverseTvbKind resolveInfixT) vs
<*> mapM resolveInfixT cx
<*> resolveInfixT t
resolveInfixT (f `AppT` x) = resolveInfixT f `appT` resolveInfixT x
resolveInfixT (ParensT t) = resolveInfixT t
resolveInfixT (InfixT l o r) = conT o `appT` resolveInfixT l `appT` resolveInfixT r
resolveInfixT (SigT t k) = SigT <$> resolveInfixT t <*> resolveInfixT k
resolveInfixT t@UInfixT{} = resolveInfixT =<< resolveInfixT1 (gatherUInfixT t)
# if MIN_VERSION_template_haskell(2,15,0)
resolveInfixT (f `AppKindT` x) = appKindT (resolveInfixT f) (resolveInfixT x)
resolveInfixT (ImplicitParamT n t)
= implicitParamT n $ resolveInfixT t
# endif
# if MIN_VERSION_template_haskell(2,16,0)
resolveInfixT (ForallVisT vs t) = ForallVisT <$> traverse (traverseTvbKind resolveInfixT) vs
<*> resolveInfixT t
# endif
resolveInfixT t = return t
gatherUInfixT :: Type -> InfixList
gatherUInfixT (UInfixT l o r) = ilAppend (gatherUInfixT l) o (gatherUInfixT r)
gatherUInfixT t = ILNil t
resolveInfixT1 :: InfixList -> TypeQ
resolveInfixT1 = go []
where
go :: [(Type,Name,Fixity)] -> InfixList -> TypeQ
go ts (ILNil u) = return (foldl (\acc (l,o,_) -> ConT o `AppT` l `AppT` acc) u ts)
go ts (ILCons l o r) =
do ofx <- fromMaybe defaultFixity <$> reifyFixityCompat o
let push = go ((l,o,ofx):ts) r
case ts of
(l1,o1,o1fx):ts' ->
case compareFixity o1fx ofx of
Just True -> go ((ConT o1 `AppT` l1 `AppT` l, o, ofx):ts') r
Just False -> push
Nothing -> fail (precedenceError o1 o1fx o ofx)
_ -> push
compareFixity :: Fixity -> Fixity -> Maybe Bool
compareFixity (Fixity n1 InfixL) (Fixity n2 InfixL) = Just (n1 >= n2)
compareFixity (Fixity n1 InfixR) (Fixity n2 InfixR) = Just (n1 > n2)
compareFixity (Fixity n1 _ ) (Fixity n2 _ ) =
case compare n1 n2 of
GT -> Just True
LT -> Just False
EQ -> Nothing
precedenceError :: Name -> Fixity -> Name -> Fixity -> String
precedenceError o1 ofx1 o2 ofx2 =
"Precedence parsing error: cannot mix ‘" ++
nameBase o1 ++ "’ [" ++ showFixity ofx1 ++ "] and ‘" ++
nameBase o2 ++ "’ [" ++ showFixity ofx2 ++
"] in the same infix type expression"
data InfixList = ILCons Type Name InfixList | ILNil Type
ilAppend :: InfixList -> Name -> InfixList -> InfixList
ilAppend (ILNil l) o r = ILCons l o r
ilAppend (ILCons l1 o1 r1) o r = ILCons l1 o1 (ilAppend r1 o r)
#else
resolveInfixT = return
#endif
showFixity :: Fixity -> String
showFixity (Fixity n d) = showFixityDirection d ++ " " ++ show n
showFixityDirection :: FixityDirection -> String
showFixityDirection InfixL = "infixl"
showFixityDirection InfixR = "infixr"
showFixityDirection InfixN = "infix"
tvName :: TyVarBndr -> Name
tvName (PlainTV name ) = name
tvName (KindedTV name _) = name
takeFieldNames :: [(Name,a,b)] -> [Name]
takeFieldNames xs = [a | (a,_,_) <- xs]
#if MIN_VERSION_template_haskell(2,11,0)
takeFieldStrictness :: [(a,Bang,b)] -> [FieldStrictness]
#else
takeFieldStrictness :: [(a,Strict,b)] -> [FieldStrictness]
#endif
takeFieldStrictness xs = [normalizeStrictness a | (_,a,_) <- xs]
takeFieldTypes :: [(a,b,Type)] -> [Type]
takeFieldTypes xs = [a | (_,_,a) <- xs]
conHasRecord :: Name -> ConstructorInfo -> Bool
conHasRecord recName info =
case constructorVariant info of
NormalConstructor -> False
InfixConstructor -> False
RecordConstructor fields -> recName `elem` fields
quantifyType :: Type -> Type
quantifyType t
| null tvbs
= t
| ForallT tvbs' ctxt' t' <- t
= ForallT (tvbs ++ tvbs') ctxt' t'
| otherwise
= ForallT tvbs [] t
where
tvbs = freeVariablesWellScoped [t]
freeVariablesWellScoped :: [Type] -> [TyVarBndr]
freeVariablesWellScoped tys =
let fvs :: [Name]
fvs = freeVariables tys
varKindSigs :: Map Name Kind
varKindSigs = foldMap go_ty tys
where
go_ty :: Type -> Map Name Kind
go_ty (ForallT tvbs ctxt t) =
foldr (\tvb -> Map.delete (tvName tvb))
(foldMap go_pred ctxt `mappend` go_ty t) tvbs
go_ty (AppT t1 t2) = go_ty t1 `mappend` go_ty t2
go_ty (SigT t k) =
let kSigs =
#if MIN_VERSION_template_haskell(2,8,0)
go_ty k
#else
mempty
#endif
in case t of
VarT n -> Map.insert n k kSigs
_ -> go_ty t `mappend` kSigs
#if MIN_VERSION_template_haskell(2,15,0)
go_ty (AppKindT t k) = go_ty t `mappend` go_ty k
go_ty (ImplicitParamT _ t) = go_ty t
#endif
#if MIN_VERSION_template_haskell(2,16,0)
go_ty (ForallVisT tvbs t) =
foldr (\tvb -> Map.delete (tvName tvb)) (go_ty t) tvbs
#endif
go_ty _ = mempty
go_pred :: Pred -> Map Name Kind
#if MIN_VERSION_template_haskell(2,10,0)
go_pred = go_ty
#else
go_pred (ClassP _ ts) = foldMap go_ty ts
go_pred (EqualP t1 t2) = go_ty t1 `mappend` go_ty t2
#endif
scopedSort :: [Name] -> [Name]
scopedSort = go [] []
go :: [Name]
-> [Set Name]
-> [Name]
-> [Name]
go acc _fv_list [] = reverse acc
go acc fv_list (tv:tvs)
= go acc' fv_list' tvs
where
(acc', fv_list') = insert tv acc fv_list
insert :: Name
-> [Name]
-> [Set Name]
-> ([Name], [Set Name])
insert tv [] [] = ([tv], [kindFVSet tv])
insert tv (a:as) (fvs:fvss)
| tv `Set.member` fvs
, (as', fvss') <- insert tv as fvss
= (a:as', fvs `Set.union` fv_tv : fvss')
| otherwise
= (tv:a:as, fvs `Set.union` fv_tv : fvs : fvss)
where
fv_tv = kindFVSet tv
insert _ _ _ = error "scopedSort"
kindFVSet n =
maybe Set.empty (Set.fromList . freeVariables) (Map.lookup n varKindSigs)
ascribeWithKind n =
maybe (PlainTV n) (KindedTV n) (Map.lookup n varKindSigs)
isKindBinderOnOldGHCs
#if __GLASGOW_HASKELL__ >= 800
= const False
#else
= (`elem` kindVars)
where
kindVars = freeVariables $ Map.elems varKindSigs
#endif
in map ascribeWithKind $
filter (not . isKindBinderOnOldGHCs) $
scopedSort fvs
freshenFreeVariables :: Type -> Q Type
freshenFreeVariables t =
do let xs = [ (n, VarT <$> newName (nameBase n)) | n <- freeVariables t]
subst <- T.sequence (Map.fromList xs)
return (applySubstitution subst t)
class TypeSubstitution a where
applySubstitution :: Map Name Type -> a -> a
freeVariables :: a -> [Name]
instance TypeSubstitution a => TypeSubstitution [a] where
freeVariables = nub . concat . map freeVariables
applySubstitution = fmap . applySubstitution
instance TypeSubstitution Type where
applySubstitution subst = go
where
go (ForallT tvs context t) =
subst_tvbs tvs $ \subst' ->
ForallT (map (mapTvbKind (applySubstitution subst')) tvs)
(applySubstitution subst' context)
(applySubstitution subst' t)
go (AppT f x) = AppT (go f) (go x)
go (SigT t k) = SigT (go t) (applySubstitution subst k)
go (VarT v) = Map.findWithDefault (VarT v) v subst
#if MIN_VERSION_template_haskell(2,11,0)
go (InfixT l c r) = InfixT (go l) c (go r)
go (UInfixT l c r) = UInfixT (go l) c (go r)
go (ParensT t) = ParensT (go t)
#endif
#if MIN_VERSION_template_haskell(2,15,0)
go (AppKindT t k) = AppKindT (go t) (go k)
go (ImplicitParamT n t)
= ImplicitParamT n (go t)
#endif
#if MIN_VERSION_template_haskell(2,16,0)
go (ForallVisT tvs t) =
subst_tvbs tvs $ \subst' ->
ForallVisT (map (mapTvbKind (applySubstitution subst')) tvs)
(applySubstitution subst' t)
#endif
go t = t
subst_tvbs :: [TyVarBndr] -> (Map Name Type -> a) -> a
subst_tvbs tvs k = k $ foldl' (flip Map.delete) subst (map tvName tvs)
freeVariables t =
case t of
ForallT tvs context t' ->
fvs_under_forall tvs (freeVariables context `union` freeVariables t')
AppT f x -> freeVariables f `union` freeVariables x
SigT t' k -> freeVariables t' `union` freeVariables k
VarT v -> [v]
#if MIN_VERSION_template_haskell(2,11,0)
InfixT l _ r -> freeVariables l `union` freeVariables r
UInfixT l _ r -> freeVariables l `union` freeVariables r
ParensT t' -> freeVariables t'
#endif
#if MIN_VERSION_template_haskell(2,15,0)
AppKindT t k -> freeVariables t `union` freeVariables k
ImplicitParamT _ t
-> freeVariables t
#endif
#if MIN_VERSION_template_haskell(2,16,0)
ForallVisT tvs t'
-> fvs_under_forall tvs (freeVariables t')
#endif
_ -> []
where
fvs_under_forall :: [TyVarBndr] -> [Name] -> [Name]
fvs_under_forall tvs fvs =
(freeVariables (map tvKind tvs) `union` fvs)
\\ map tvName tvs
instance TypeSubstitution ConstructorInfo where
freeVariables ci =
(freeVariables (map tvKind (constructorVars ci))
`union` freeVariables (constructorContext ci)
`union` freeVariables (constructorFields ci))
\\ (tvName <$> constructorVars ci)
applySubstitution subst ci =
let subst' = foldl' (flip Map.delete) subst (map tvName (constructorVars ci)) in
ci { constructorVars = map (mapTvbKind (applySubstitution subst'))
(constructorVars ci)
, constructorContext = applySubstitution subst' (constructorContext ci)
, constructorFields = applySubstitution subst' (constructorFields ci)
}
mapTvbKind :: (Kind -> Kind) -> TyVarBndr -> TyVarBndr
mapTvbKind f tvb@PlainTV{} = tvb
mapTvbKind f (KindedTV n k) = KindedTV n (f k)
traverseTvbKind :: Applicative f => (Kind -> f Kind) -> TyVarBndr -> f TyVarBndr
traverseTvbKind f tvb@PlainTV{} = pure tvb
traverseTvbKind f (KindedTV n k) = KindedTV n <$> f k
#if !MIN_VERSION_template_haskell(2,10,0)
instance TypeSubstitution Pred where
freeVariables (ClassP _ xs) = freeVariables xs
freeVariables (EqualP x y) = freeVariables x `union` freeVariables y
applySubstitution p (ClassP n xs) = ClassP n (applySubstitution p xs)
applySubstitution p (EqualP x y) = EqualP (applySubstitution p x)
(applySubstitution p y)
#endif
#if !MIN_VERSION_template_haskell(2,8,0)
instance TypeSubstitution Kind where
freeVariables _ = []
applySubstitution _ k = k
#endif
substTyVarBndrs :: Map Name Type -> [TyVarBndr] -> [TyVarBndr]
substTyVarBndrs subst = map go
where
go tvb@(PlainTV {}) = tvb
go (KindedTV n k) = KindedTV n (applySubstitution subst k)
combineSubstitutions :: Map Name Type -> Map Name Type -> Map Name Type
combineSubstitutions x y = Map.union (fmap (applySubstitution y) x) y
unifyTypes :: [Type] -> Q (Map Name Type)
unifyTypes [] = return Map.empty
unifyTypes (t:ts) =
do t':ts' <- mapM resolveTypeSynonyms (t:ts)
let aux sub u =
do sub' <- unify' (applySubstitution sub t')
(applySubstitution sub u)
return (combineSubstitutions sub sub')
case foldM aux Map.empty ts' of
Right m -> return m
Left (x,y) ->
fail $ showString "Unable to unify types "
. showsPrec 11 x
. showString " and "
. showsPrec 11 y
$ ""
unify' :: Type -> Type -> Either (Type,Type) (Map Name Type)
unify' (VarT n) (VarT m) | n == m = pure Map.empty
unify' (VarT n) t | n `elem` freeVariables t = Left (VarT n, t)
| otherwise = Right (Map.singleton n t)
unify' t (VarT n) | n `elem` freeVariables t = Left (VarT n, t)
| otherwise = Right (Map.singleton n t)
unify' (AppT f1 x1) (AppT f2 x2) =
do sub1 <- unify' f1 f2
sub2 <- unify' (applySubstitution sub1 x1) (applySubstitution sub1 x2)
Right (combineSubstitutions sub1 sub2)
unify' (SigT t _) u = unify' t u
unify' t (SigT u _) = unify' t u
unify' t u
| t == u = Right Map.empty
| otherwise = Left (t,u)
equalPred :: Type -> Type -> Pred
equalPred x y =
#if MIN_VERSION_template_haskell(2,10,0)
AppT (AppT EqualityT x) y
#else
EqualP x y
#endif
classPred :: Name -> [Type] -> Pred
classPred =
#if MIN_VERSION_template_haskell(2,10,0)
foldl AppT . ConT
#else
ClassP
#endif
asEqualPred :: Pred -> Maybe (Type,Type)
#if MIN_VERSION_template_haskell(2,10,0)
asEqualPred (EqualityT `AppT` x `AppT` y) = Just (x,y)
asEqualPred (ConT eq `AppT` x `AppT` y) | eq == eqTypeName = Just (x,y)
#else
asEqualPred (EqualP x y) = Just (x,y)
#endif
asEqualPred _ = Nothing
asClassPred :: Pred -> Maybe (Name, [Type])
#if MIN_VERSION_template_haskell(2,10,0)
asClassPred t =
case decomposeType t of
ConT f :| xs | f /= eqTypeName -> Just (f,xs)
_ -> Nothing
#else
asClassPred (ClassP f xs) = Just (f,xs)
asClassPred _ = Nothing
#endif
type IsReifiedDec = Bool
isReified, isn'tReified :: IsReifiedDec
isReified = True
isn'tReified = False
giveDIVarsStarKinds :: DatatypeInfo -> DatatypeInfo
giveDIVarsStarKinds info =
info { datatypeVars = map giveTyVarBndrStarKind (datatypeVars info)
, datatypeInstTypes = map giveTypeStarKind (datatypeInstTypes info) }
giveCIVarsStarKinds :: ConstructorInfo -> ConstructorInfo
giveCIVarsStarKinds info =
info { constructorVars = map giveTyVarBndrStarKind (constructorVars info) }
giveTyVarBndrStarKind :: TyVarBndr -> TyVarBndr
giveTyVarBndrStarKind (PlainTV n) = KindedTV n starK
giveTyVarBndrStarKind tvb@KindedTV{} = tvb
giveTypeStarKind :: Type -> Type
giveTypeStarKind t@(VarT n) = SigT t starK
giveTypeStarKind t = t
repair13618 :: DatatypeInfo -> Q DatatypeInfo
repair13618 info =
do s <- T.sequence (Map.fromList substList)
return info { datatypeCons = applySubstitution s (datatypeCons info) }
where
used = freeVariables (datatypeCons info)
bound = map tvName (datatypeVars info)
free = used \\ bound
substList =
[ (u, substEntry u vs)
| u <- free
, let vs = [v | v <- bound, nameBase v == nameBase u]
]
substEntry _ [v] = varT v
substEntry u [] = fail ("Impossible free variable: " ++ show u)
substEntry u _ = fail ("Ambiguous free variable: " ++ show u)
dataDCompat ::
CxtQ ->
Name ->
[TyVarBndr] ->
[ConQ] ->
[Name] ->
DecQ
#if MIN_VERSION_template_haskell(2,12,0)
dataDCompat c n ts cs ds =
dataD c n ts Nothing cs
(if null ds then [] else [derivClause Nothing (map conT ds)])
#elif MIN_VERSION_template_haskell(2,11,0)
dataDCompat c n ts cs ds =
dataD c n ts Nothing cs
(return (map ConT ds))
#else
dataDCompat = dataD
#endif
newtypeDCompat ::
CxtQ ->
Name ->
[TyVarBndr] ->
ConQ ->
[Name] ->
DecQ
#if MIN_VERSION_template_haskell(2,12,0)
newtypeDCompat c n ts cs ds =
newtypeD c n ts Nothing cs
(if null ds then [] else [derivClause Nothing (map conT ds)])
#elif MIN_VERSION_template_haskell(2,11,0)
newtypeDCompat c n ts cs ds =
newtypeD c n ts Nothing cs
(return (map ConT ds))
#else
newtypeDCompat = newtypeD
#endif
tySynInstDCompat ::
Name ->
Maybe [Q TyVarBndr] ->
[TypeQ] ->
TypeQ ->
DecQ
#if MIN_VERSION_template_haskell(2,15,0)
tySynInstDCompat n mtvbs ps r = TySynInstD <$> (TySynEqn <$> mapM sequence mtvbs
<*> foldl' appT (conT n) ps
<*> r)
#elif MIN_VERSION_template_haskell(2,9,0)
tySynInstDCompat n _ ps r = TySynInstD n <$> (TySynEqn <$> sequence ps <*> r)
#else
tySynInstDCompat n _ = tySynInstD n
#endif
pragLineDCompat ::
Int ->
String ->
Maybe DecQ
#if MIN_VERSION_template_haskell(2,10,0)
pragLineDCompat ln fn = Just (pragLineD ln fn)
#else
pragLineDCompat _ _ = Nothing
#endif
arrowKCompat :: Kind -> Kind -> Kind
#if MIN_VERSION_template_haskell(2,8,0)
arrowKCompat x y = arrowK `appK` x `appK` y
#else
arrowKCompat = arrowK
#endif
reifyFixityCompat :: Name -> Q (Maybe Fixity)
#if MIN_VERSION_template_haskell(2,11,0)
reifyFixityCompat n = recover (return Nothing) ((`mplus` Just defaultFixity) <$> reifyFixity n)
#else
reifyFixityCompat n = recover (return Nothing) $
do info <- reify n
return $! case info of
ClassOpI _ _ _ fixity -> Just fixity
DataConI _ _ _ fixity -> Just fixity
VarI _ _ _ fixity -> Just fixity
_ -> Nothing
#endif
reifyMaybe :: Name -> Q (Maybe Info)
reifyMaybe n = return Nothing `recover` fmap Just (reify n)