packages feed

th-abstraction 0.1.3.0 → 0.2.0.0

raw patch · 6 files changed

+852/−207 lines, 6 filesdep ~basedep ~template-haskellPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, template-haskell

API changes (from Hackage documentation)

+ Language.Haskell.TH.Datatype: FieldStrictness :: Unpackedness -> Strictness -> FieldStrictness
+ Language.Haskell.TH.Datatype: InfixConstructor :: ConstructorVariant
+ Language.Haskell.TH.Datatype: [constructorStrictness] :: ConstructorInfo -> [FieldStrictness]
+ Language.Haskell.TH.Datatype: [fieldStrictness] :: FieldStrictness -> Strictness
+ Language.Haskell.TH.Datatype: [fieldUnpackedness] :: FieldStrictness -> Unpackedness
+ Language.Haskell.TH.Datatype: data FieldStrictness
+ Language.Haskell.TH.Datatype: instance Data.Data.Data Language.Haskell.TH.Datatype.FieldStrictness
+ Language.Haskell.TH.Datatype: instance Data.Data.Data Language.Haskell.TH.Datatype.Strictness
+ Language.Haskell.TH.Datatype: instance Data.Data.Data Language.Haskell.TH.Datatype.Unpackedness
+ Language.Haskell.TH.Datatype: instance GHC.Classes.Eq Language.Haskell.TH.Datatype.FieldStrictness
+ Language.Haskell.TH.Datatype: instance GHC.Classes.Eq Language.Haskell.TH.Datatype.Strictness
+ Language.Haskell.TH.Datatype: instance GHC.Classes.Eq Language.Haskell.TH.Datatype.Unpackedness
+ Language.Haskell.TH.Datatype: instance GHC.Classes.Ord Language.Haskell.TH.Datatype.FieldStrictness
+ Language.Haskell.TH.Datatype: instance GHC.Classes.Ord Language.Haskell.TH.Datatype.Strictness
+ Language.Haskell.TH.Datatype: instance GHC.Classes.Ord Language.Haskell.TH.Datatype.Unpackedness
+ Language.Haskell.TH.Datatype: instance GHC.Generics.Generic Language.Haskell.TH.Datatype.FieldStrictness
+ Language.Haskell.TH.Datatype: instance GHC.Generics.Generic Language.Haskell.TH.Datatype.Strictness
+ Language.Haskell.TH.Datatype: instance GHC.Generics.Generic Language.Haskell.TH.Datatype.Unpackedness
+ Language.Haskell.TH.Datatype: instance GHC.Show.Show Language.Haskell.TH.Datatype.FieldStrictness
+ Language.Haskell.TH.Datatype: instance GHC.Show.Show Language.Haskell.TH.Datatype.Strictness
+ Language.Haskell.TH.Datatype: instance GHC.Show.Show Language.Haskell.TH.Datatype.Unpackedness
+ Language.Haskell.TH.Datatype: isStrictAnnot :: FieldStrictness
+ Language.Haskell.TH.Datatype: notStrictAnnot :: FieldStrictness
+ Language.Haskell.TH.Datatype: reifyFixityCompat :: Name -> Q (Maybe Fixity)
+ Language.Haskell.TH.Datatype: unpackedAnnot :: FieldStrictness
- Language.Haskell.TH.Datatype: ConstructorInfo :: Name -> [TyVarBndr] -> Cxt -> [Type] -> ConstructorVariant -> ConstructorInfo
+ Language.Haskell.TH.Datatype: ConstructorInfo :: Name -> [TyVarBndr] -> Cxt -> [Type] -> [FieldStrictness] -> ConstructorVariant -> ConstructorInfo
- Language.Haskell.TH.Datatype: normalizeCon :: Name -> [Type] -> Con -> Q [ConstructorInfo]
+ Language.Haskell.TH.Datatype: normalizeCon :: Name -> [Type] -> DatatypeVariant -> Con -> Q [ConstructorInfo]

Files

ChangeLog.md view
@@ -1,6 +1,14 @@ # Revision history for th-abstraction -## 0.1.3.0 -- 2016-05-27+## 0.2.0.0 -- 2017-06-03++* Added `reifyFixityCompat`+* Added `constructorStrictness` field to `ConstructorInfo`+* Infer more kind signatures when missing on old GHCs+* Added parameter to `normalizeCon`+* Support GHC back to 7.0.4++## 0.1.3.0 -- 2017-05-27  * Added `resolveInfixT` which uses reified fixity information to resolve `UInfixT` * Added `asEqualPred` and `asClassPred`
src/Language/Haskell/TH/Datatype.hs view
@@ -1,5 +1,10 @@-{-# Language CPP, DeriveGeneric, DeriveDataTypeable #-}+{-# Language CPP, DeriveDataTypeable #-} +#if MIN_VERSION_base(4,4,0)+#define HAS_GENERICS+{-# Language DeriveGeneric #-}+#endif+ {-| Module      : Language.Haskell.TH.Datatype Description : Backwards-compatible interface to reified information about datatypes.@@ -17,22 +22,27 @@ 'DatatypeInfo'  { 'datatypeContext' = []  , 'datatypeName'    = GHC.Base.Maybe- , 'datatypeVars'    = [ 'VarT' a_3530822107858468866 ]+ , 'datatypeVars'    = [ 'SigT' ('VarT' a_3530822107858468866) 'StarT' ]  , 'datatypeVariant' = 'Datatype'  , 'datatypeCons'    =      [ 'ConstructorInfo'-         { 'constructorName'    = GHC.Base.Nothing-         , 'constructorVars'    = []-         , 'constructorContext' = []-         , 'constructorFields'  = []-         , 'constructorVariant' = 'NormalConstructor'+         { 'constructorName'       = GHC.Base.Nothing+         , 'constructorVars'       = []+         , 'constructorContext'    = []+         , 'constructorFields'     = []+         , 'constructorStrictness' = []+         , 'constructorVariant'    = 'NormalConstructor'          }      , 'ConstructorInfo'-         { 'constructorName'    = GHC.Base.Just-         , 'constructorVars'    = []-         , 'constructorContext' = []-         , 'constructorFields'  = [ 'VarT' a_3530822107858468866 ]-         , 'constructorVariant' = 'NormalConstructor'+         { 'constructorName'       = GHC.Base.Just+         , 'constructorVars'       = []+         , 'constructorContext'    = []+         , 'constructorFields'     = [ 'VarT' a_3530822107858468866 ]+         , 'constructorStrictness' = [ 'FieldStrictness'+                                         'UnspecifiedUnpackedness'+                                         'Lazy'+                                     ]+         , 'constructorVariant'    = 'NormalConstructor'          }      ]  }@@ -49,6 +59,7 @@   , ConstructorInfo(..)   , DatatypeVariant(..)   , ConstructorVariant(..)+  , FieldStrictness(..)    -- * Normalization functions   , reifyDatatype@@ -71,16 +82,24 @@   , dataDCompat   , arrowKCompat +  -- * Strictness annotations+  , isStrictAnnot+  , notStrictAnnot+  , unpackedAnnot+   -- * Type simplification   , resolveTypeSynonyms   , resolveInfixT +  -- * Fixities+  , reifyFixityCompat+  , showFixity+  , showFixityDirection+   -- * Convenience functions   , unifyTypes   , tvName   , datatypeType-  , showFixity-  , showFixityDirection   ) where  import           Data.Data (Typeable, Data)@@ -88,19 +107,30 @@ import           Data.List (find, union, (\\)) import           Data.Map (Map) import qualified Data.Map as Map-import           Data.Maybe (fromMaybe)-import           Control.Monad (foldM)-import           GHC.Generics (Generic)+import           Data.Maybe+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) -- needed for th-2.4+import           Language.Haskell.TH.Lib (arrowK, starK) -- needed for th-2.4 +#ifdef HAS_GENERICS+import           GHC.Generics (Generic)+#endif+ #if !MIN_VERSION_base(4,8,0) import           Control.Applicative (Applicative(..), (<$>))-import           Data.Traversable (traverse, sequenceA) #endif  -- | Normalized information about newtypes and data types.+--+-- 'datatypeVars' types will have an outermost 'SigT' to indicate the+-- parameter's kind. These types will be simple variables for /ADT/s+-- declared with @data@ and @newtype@, but can be more complex for+-- types declared with @data instance@ and @newtype instance@. data DatatypeInfo = DatatypeInfo   { datatypeContext :: Cxt               -- ^ Data type context (deprecated)   , datatypeName    :: Name              -- ^ Type constructor@@ -108,34 +138,114 @@   , datatypeVariant :: DatatypeVariant   -- ^ Extra information   , datatypeCons    :: [ConstructorInfo] -- ^ Normalize constructor information   }-  deriving (Show, Eq, Typeable, Data, Generic)+  deriving (Show, Eq, Typeable, Data+#ifdef HAS_GENERICS+           ,Generic+#endif+           )  -- | Possible variants of data type declarations. data DatatypeVariant-  = Datatype -- ^ Type declared with @data@-  | Newtype  -- ^ Type declared with @newtype@-  | DataInstance -- ^ Type declared with @data instance@+  = Datatype        -- ^ Type declared with @data@+  | Newtype         -- ^ Type declared with @newtype@+  | DataInstance    -- ^ Type declared with @data instance@   | NewtypeInstance -- ^ Type declared with @newtype instance@-  deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)+  deriving (Show, Read, Eq, Ord, Typeable, Data+#ifdef HAS_GENERICS+           ,Generic+#endif+           )  -- | Normalized information about constructors associated with newtypes and -- data types. data ConstructorInfo = ConstructorInfo-  { constructorName    :: Name               -- ^ Constructor name-  , constructorVars    :: [TyVarBndr]        -- ^ Constructor type parameters-  , constructorContext :: Cxt                -- ^ Constructor constraints-  , constructorFields  :: [Type]             -- ^ Constructor fields-  , constructorVariant :: ConstructorVariant -- ^ Extra information+  { constructorName       :: Name               -- ^ Constructor name+  , constructorVars       :: [TyVarBndr]        -- ^ Constructor type parameters+  , constructorContext    :: Cxt                -- ^ Constructor constraints+  , constructorFields     :: [Type]             -- ^ Constructor fields+  , constructorStrictness :: [FieldStrictness]  -- ^ Constructor fields' strictness+                                                --   (Invariant: has the same length+                                                --   as constructorFields)+  , constructorVariant    :: ConstructorVariant -- ^ Extra information   }-  deriving (Show, Eq, Typeable, Data, Generic)+  deriving (Show, Eq, Typeable, Data+#ifdef HAS_GENERICS+           ,Generic+#endif+           )  -- | Possible variants of data constructors. data ConstructorVariant   = NormalConstructor        -- ^ Constructor without field names+  | InfixConstructor         -- ^ Constructor without field names that is+                             --   declared infix   | RecordConstructor [Name] -- ^ Constructor with field names-  deriving (Show, Eq, Ord, Typeable, Data, Generic)+  deriving (Show, Eq, Ord, Typeable, Data+#ifdef HAS_GENERICS+           ,Generic+#endif+           ) +-- | Normalized information about a constructor field's @UNPACK@ and+-- strictness annotations.+--+-- Note that the interface for reifying strictness in Template Haskell changed+-- considerably in GHC 8.0. The presentation in this library mirrors that which+-- can be found in GHC 8.0 or later, whereas previously, unpackedness and+-- strictness were represented with a single data type:+--+-- @+-- data Strict+--   = IsStrict+--   | NotStrict+--   | Unpacked -- On GHC 7.4 or later+-- @+--+-- For backwards compatibility, we retrofit these constructors onto the+-- following three values, respectively:+--+-- @+-- 'isStrictAnnot'  = 'FieldStrictness' 'UnspecifiedUnpackedness' 'Strict'+-- 'notStrictAnnot' = 'FieldStrictness' 'UnspecifiedUnpackedness' 'UnspecifiedStrictness'+-- 'unpackedAnnot'  = 'FieldStrictness' 'Unpack' 'Strict'+-- @+data FieldStrictness = FieldStrictness+  { fieldUnpackedness :: Unpackedness+  , fieldStrictness   :: Strictness+  }+  deriving (Show, Eq, Ord, Typeable, Data+#ifdef HAS_GENERICS+           ,Generic+#endif+           ) +-- | Information about a constructor field's unpackedness annotation.+data Unpackedness+  = UnspecifiedUnpackedness -- ^ No annotation whatsoever+  | NoUnpack                -- ^ Annotated with @{\-\# NOUNPACK \#-\}@+  | Unpack                  -- ^ Annotated with @{\-\# UNPACK \#-\}@+  deriving (Show, Eq, Ord, Typeable, Data+#ifdef HAS_GENERICS+           ,Generic+#endif+           )++-- | Information about a constructor field's strictness annotation.+data Strictness+  = UnspecifiedStrictness -- ^ No annotation whatsoever+  | Lazy                  -- ^ Annotated with @~@+  | Strict                -- ^ Annotated with @!@+  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+ -- | Construct a Type using the datatype's type constructor and type -- parameters. Kind signatures are removed. datatypeType :: DatatypeInfo -> Type@@ -146,36 +256,74 @@   -- | Compute a normalized view of the metadata about a data type or newtype--- given a type constructor.+-- given a constructor.+--+-- This function will accept any constructor (value or type) for a type+-- declared with newtype or data. Value constructors must be used to+-- lookup datatype information about /data instances/ and /newtype instances/.+--+-- GADT constructors are normalized into datatypes with explicit equality+-- constraints.+--+-- This function will apply various bug-fixes to the output of the underlying+-- @template-haskell@ library in order to provide a view of datatypes in+-- as uniform a way as possible. reifyDatatype ::-  Name {- ^ type constructor -} ->+  Name {- ^ constructor -} ->   Q DatatypeInfo-reifyDatatype n = normalizeInfo =<< reify n+reifyDatatype n = normalizeInfo' "reifyDatatype" =<< reify n   -- | Normalize 'Info' for a newtype or datatype into a 'DatatypeInfo'. -- Fail in 'Q' otherwise. normalizeInfo :: Info -> Q DatatypeInfo-normalizeInfo (TyConI dec) = normalizeDec dec-# if MIN_VERSION_template_haskell(2,11,0)-normalizeInfo (DataConI name ty parent) = reifyParent name ty parent-# else-normalizeInfo (DataConI name ty parent _) = reifyParent name ty parent-# endif-normalizeInfo _ = fail "reifyDatatype: Expected a type constructor"+normalizeInfo = normalizeInfo' "normalizeInfo" +normalizeInfo' :: String -> Info -> Q DatatypeInfo+normalizeInfo' entry 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                        -> normalizeDec dec+#if MIN_VERSION_template_haskell(2,11,0)+    DataConI name _ parent            -> reifyParent name parent+#elif MIN_VERSION_template_haskell(2,7,0)+    DataConI name _ parent _          -> reifyParent name parent+#else+    -- Give a sensible error message if you try to look up a data family+    -- instance constructor in GHC 7.0 or 7.2+    DataConI{}                        -> bad $ "Data family instances can only " +++                                               "be reified with GHC 7.4 or later"+#endif+    _                                 -> bad "Expected a type constructor"+  where+    bad msg = fail (entry ++ ": " ++ msg) -reifyParent :: Name -> Type -> Name -> Q DatatypeInfo-reifyParent con ty parent =++reifyParent :: Name -> Name -> Q DatatypeInfo+reifyParent con parent =   do info <- reify parent      case info of        TyConI dec -> normalizeDec dec+#if MIN_VERSION_template_haskell(2,7,0)        FamilyI dec instances ->-         do let instances1 = map (repairInstance dec ty) instances-            instances2 <- traverse normalizeDec instances1+         do let instances1 = map (repairDataFam dec) instances+            instances2 <- mapM normalizeDec instances1             case find p instances2 of               Just inst -> return inst               Nothing   -> fail "PANIC: reifyParent lost the instance"+#endif        _ -> fail "PANIC: reifyParent unexpected parent"   where     p info = con `elem` map constructorName (datatypeCons info)@@ -184,66 +332,120 @@     kindPart (KindedTV _ k) = [k]     kindPart (PlainTV  _  ) = [] -    countKindVars = length . freeVariables . map kindPart-    -- GHC 7.8.4 will eta-reduce data instances. We can find the missing-    -- type variables on the data constructor.-    repairInstance+    -- A version of repairVarKindsWith that does much more extra work to+    -- (1) eta-expand missing type patterns, and (2) ensure that the kind+    -- signatures for these new type patterns match accordingly.+    repairVarKindsWith' :: [TyVarBndr] -> [Type] -> [Type]+    repairVarKindsWith' dvars ts =+      let 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 -- eta-expand+      in applySubstitution (Map.fromList (zip kparams tsKinds')) $+         repairVarKindsWith dvars ts'++    -- A GHC 7.6-specific bug requires us to replace all occurrences of+    -- (ConT GHC.Prim.*) with StarT, or else Template Haskell will reject it.+    -- Luckily, (ConT GHC.Prim.*) only seems to occur in this one spot.+    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++    kindVars = freeVariables . map kindPart++    -- Sadly, Template Haskell's treatment of data family instances leaves much+    -- to be desired. Here are some problems that we have to work around:+    --+    -- 1. On all versions of GHC, TH leaves off the kind signatures on the+    --    type patterns of data family instances where a kind signature isn't+    --    specified explicitly. Here, we can use the parent data family's+    --    type variable binders to reconstruct the kind signatures if they+    --    are missing.+    -- 2. On GHC 7.6 and 7.8, TH will eta-reduce data instances. We can find+    --    the missing type variables on the data constructor.+    --+    -- We opt to avoid propagating these new type variables through to the+    -- constructor now, but we will return to this task in normalizeCon.+    repairDataFam       (FamilyD _ _ dvars _)-      (ForallT tvars _ _)       (NewtypeInstD cx n ts con deriv) =-        NewtypeInstD cx n ts' con deriv-      where-        nparams = length dvars-        kparams = countKindVars dvars-        ts'     = take nparams (drop kparams (ts ++ bndrParams tvars))-    repairInstance+        NewtypeInstD cx n (repairVarKindsWith' dvars ts) con deriv+    repairDataFam       (FamilyD _ _ dvars _)-      (ForallT tvars _ _)       (DataInstD cx n ts cons deriv) =-        DataInstD cx n ts' cons deriv-      where-        nparams = length dvars-        kparams = countKindVars dvars-        ts'     = take nparams (drop kparams (ts ++ bndrParams tvars))+        DataInstD cx n (repairVarKindsWith' dvars ts) cons deriv+#else+    repairDataFam famD instD+# if 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-    repairInstance _ _ x = x+    repairDataFam _ instD = instD +repairVarKindsWith :: [TyVarBndr] -> [Type] -> [Type]+repairVarKindsWith = zipWith stealKindForType +-- If a VarT is missing an explicit kind signature, steal it from a TyVarBndr.+stealKindForType :: TyVarBndr -> Type -> Type+stealKindForType tvb t@VarT{} = SigT t (tvbKind tvb)+stealKindForType _   t        = t+ -- | Normalize 'Dec' for a newtype or datatype into a 'DatatypeInfo'. -- Fail in 'Q' otherwise. normalizeDec :: Dec -> Q DatatypeInfo #if MIN_VERSION_template_haskell(2,12,0) normalizeDec (NewtypeD context name tyvars _kind con _derives) =-  normalizeDec' context name (bndrParams tyvars) [con] Newtype+  giveTypesStarKinds <$> normalizeDec' context name (bndrParams tyvars) [con] Newtype normalizeDec (DataD context name tyvars _kind cons _derives) =-  normalizeDec' context name (bndrParams tyvars) cons Datatype+  giveTypesStarKinds <$> normalizeDec' context name (bndrParams tyvars) cons Datatype normalizeDec (NewtypeInstD context name params _kind con _derives) =-  repair13618 =<<+  repair13618 . giveTypesStarKinds =<<   normalizeDec' context name params [con] NewtypeInstance normalizeDec (DataInstD context name params _kind cons _derives) =-  repair13618 =<<+  repair13618 . giveTypesStarKinds =<<   normalizeDec' context name params cons DataInstance #elif MIN_VERSION_template_haskell(2,11,0) normalizeDec (NewtypeD context name tyvars _kind con _derives) =-  normalizeDec' context name (bndrParams tyvars) [con] Newtype+  giveTypesStarKinds <$> normalizeDec' context name (bndrParams tyvars) [con] Newtype normalizeDec (DataD context name tyvars _kind cons _derives) =-  normalizeDec' context name (bndrParams tyvars) cons Datatype+  giveTypesStarKinds <$> normalizeDec' context name (bndrParams tyvars) cons Datatype normalizeDec (NewtypeInstD context name params _kind con _derives) =-  repair13618 =<<+  repair13618 . giveTypesStarKinds =<<   normalizeDec' context name params [con] NewtypeInstance normalizeDec (DataInstD context name params _kind cons _derives) =-  repair13618 =<<+  repair13618 . giveTypesStarKinds =<<   normalizeDec' context name params cons DataInstance #else normalizeDec (NewtypeD context name tyvars con _derives) =-  normalizeDec' context name (bndrParams tyvars) [con] Newtype+  giveTypesStarKinds <$> normalizeDec' context name (bndrParams tyvars) [con] Newtype normalizeDec (DataD context name tyvars cons _derives) =-  normalizeDec' context name (bndrParams tyvars) cons Datatype+  giveTypesStarKinds <$> normalizeDec' context name (bndrParams tyvars) cons Datatype normalizeDec (NewtypeInstD context name params con _derives) =-  repair13618 =<<+  repair13618 . giveTypesStarKinds =<<   normalizeDec' context name params [con] NewtypeInstance normalizeDec (DataInstD context name params cons _derives) =-  repair13618 =<<+  repair13618 . giveTypesStarKinds =<<   normalizeDec' context name params cons DataInstance #endif normalizeDec _ = fail "reifyDatatype: DataD or NewtypeD required"@@ -254,6 +456,10 @@     KindedTV t k -> SigT (VarT t) k     PlainTV  t   -> VarT t +-- | Extract the kind from a 'TyVarBndr'. Assumes 'PlainTV' has kind @*@.+tvbKind :: TyVarBndr -> Kind+tvbKind (PlainTV  _)   = starK+tvbKind (KindedTV _ k) = k  -- | Remove the outermost 'SigT'. stripSigT :: Type -> Type@@ -269,8 +475,8 @@   DatatypeVariant {- ^ Extra information   -} ->   Q DatatypeInfo normalizeDec' context name params cons variant =-  do cons' <- concat <$> traverse (normalizeCon name params) cons-     pure DatatypeInfo+  do cons' <- concat <$> mapM (normalizeCon name params variant) cons+     return DatatypeInfo        { datatypeContext = context        , datatypeName    = name        , datatypeVars    = params@@ -279,49 +485,195 @@        }  -- | Normalize a 'Con' into a 'ConstructorInfo'. This requires knowledge of--- the type and parameters of the constructor as extracted from the outer+-- the type and parameters of the constructor, as well as whether the constructor+-- is for a data family instance, as extracted from the outer -- 'Dec'. normalizeCon ::-  Name   {- ^ Type constructor -} ->-  [Type] {- ^ Type parameters  -} ->-  Con    {- ^ Constructor      -} ->+  Name            {- ^ Type constructor  -} ->+  [Type]          {- ^ Type parameters   -} ->+  DatatypeVariant {- ^ Extra information -} ->+  Con             {- ^ Constructor       -} ->   Q [ConstructorInfo]-normalizeCon typename params = go [] []+normalizeCon typename params variant = fmap (map giveTyVarBndrsStarKinds) . dispatch   where-    go tyvars context c =-      case c of-        NormalC n xs ->-          pure [ConstructorInfo n tyvars context (map snd xs) NormalConstructor]-        InfixC l n r ->-          pure [ConstructorInfo n tyvars context [snd l,snd r] NormalConstructor]-        RecC n xs ->-          let fns = takeFieldNames xs in-          pure [ConstructorInfo n tyvars context-                  (takeFieldTypes xs) (RecordConstructor fns)]-        ForallC tyvars' context' c' ->-          go (tyvars'++tyvars) (context'++context) c'+    -- A GADT constructor is declared infix when:+    --+    -- 1. Its name uses operator syntax (e.g., (:*:))+    -- 2. It has exactly two fields+    -- 3. It has a programmer-supplied fixity declaration+    checkGadtFixity :: [Type] -> Name -> Q ConstructorVariant+    checkGadtFixity ts n = do+#if MIN_VERSION_template_haskell(2,11,0)+      mbFi <- reifyFixity n+      let userSuppliedFixity = isJust mbFi+#else+      -- On old GHCs, there is a bug where infix GADT constructors will+      -- mistakenly be marked as (ForallC (NormalC ...)) instead of+      -- (ForallC (InfixC ...)). This is especially annoying since on these+      -- versions of GHC, Template Haskell doesn't grant the ability to query+      -- whether a constructor was given a user-supplied fixity declaration.+      -- Rather, you can only check the fixity that GHC ultimately decides on+      -- for a constructor, regardless of whether it was a default fixity or+      -- it was user-supplied.+      --+      -- We can approximate whether a fixity was user-supplied by checking if+      -- it is not equal to defaultFixity (infixl 9). Unfortunately,+      -- there is no way to distinguish between a user-supplied fixity of+      -- infixl 9 and the fixity that GHC defaults to, so we cannot properly+      -- handle that case.+      DataConI _ _ _ fi <- reify n+      let userSuppliedFixity = fi /= defaultFixity+#endif+      return $ if isInfixDataCon (nameBase n)+                  && length ts == 2+                  && userSuppliedFixity+               then InfixConstructor+               else NormalConstructor +    -- Checks if a String names a valid Haskell infix data+    -- constructor (i.e., does it begin with a colon?).+    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 -- Is this a GADT? (see the documentation for+                         -- for checkGadtFixity)+                 -> 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 ->-          gadtCase ns innerType (map snd xs) NormalConstructor-        RecGadtC ns xs innerType ->-          let fns = takeFieldNames xs in-          gadtCase ns innerType (takeFieldTypes xs) (RecordConstructor fns)-      where-        gadtCase = normalizeGadtC typename params tyvars context+                  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 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 tyvars stricts NormalConstructor+                  InfixC l n r ->+                    let stricts = map (normalizeStrictness . fst) [l,r] in+                    dataFamCase' n tyvars stricts InfixConstructor+                  RecC n xs ->+                    let stricts = takeFieldStrictness xs in+                    dataFamCase' n tyvars stricts+                                 (RecordConstructor (takeFieldNames xs))+                  ForallC tyvars' context' c' ->+                    go (tyvars'++tyvars) c' +          dataFamCase' :: Name -> [TyVarBndr] -> [FieldStrictness]+                       -> ConstructorVariant+                       -> Q [ConstructorInfo]+          dataFamCase' n tyvars stricts variant = do+            info <- reify n+            case info of+              DataConI _ ty _ _ -> do+                let (context, argTys :|- returnTy) = uncurryType ty+                returnTy' <- resolveTypeSynonyms returnTy+                -- Notice that we've ignored the Cxt and argument Types from the+                -- Con argument above, as they might be scoped over eta-reduced+                -- variables. Instead of trying to figure out what the+                -- eta-reduced variables should be substituted with post facto,+                -- we opt for the simpler approach of using the context and+                -- argument types from the reified constructor Info, which will+                -- at least be correctly scoped. This will make the task of+                -- substituting those types with the variables we put in+                -- place of the eta-reduced variables (in normalizeDec)+                -- much easier.+                normalizeGadtC typename params tyvars context [n]+                               returnTy' argTys stricts (const $ return variant)+              _ -> fail "normalizeCon: impossible" +      in case variant of+           -- On GHC 7.6 and 7.8, there's quite a bit of post-processing that+           -- needs to be performed to work around an old bug that eta-reduces the+           -- type patterns of data families.+           DataInstance    -> dataFamCompatCase+           NewtypeInstance -> dataFamCompatCase+           Datatype        -> defaultCase+           Newtype         -> 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               {- ^ Type constructor             -} ->-  [Type]             {- ^ Type parameters              -} ->-  [TyVarBndr]        {- ^ Constructor parameters       -} ->-  Cxt                {- ^ Constructor context          -} ->-  [Name]             {- ^ Constructor names            -} ->-  Type               {- ^ Declared type of constructor -} ->-  [Type]             {- ^ Constructor field types      -} ->-  ConstructorVariant {- ^ Constructor variant          -} ->+  Name              {- ^ Type constructor             -} ->+  [Type]            {- ^ Type parameters              -} ->+  [TyVarBndr]       {- ^ Constructor parameters       -} ->+  Cxt               {- ^ Constructor context          -} ->+  [Name]            {- ^ Constructor names            -} ->+  Type              {- ^ Declared type of constructor -} ->+  [Type]            {- ^ Constructor field types      -} ->+  [FieldStrictness] {- ^ Constructor field strictness -} ->+  (Name -> Q ConstructorVariant)+                    {- ^ Determine a constructor variant+                         from its 'Name' -}              ->   Q [ConstructorInfo]-normalizeGadtC typename params tyvars context names innerType fields variant =+normalizeGadtC typename params tyvars context names innerType+               fields stricts getVariant =   do innerType' <- resolveTypeSynonyms innerType      case decomposeType innerType' of        ConT innerTyCon :| ts | typename == innerTyCon ->@@ -332,8 +684,11 @@               context2 = applySubstitution subst (context1 ++ context)              fields'  = applySubstitution subst fields-         in pure [ConstructorInfo name tyvars' context2 fields' variant-                 | name <- names]+         in sequence [ ConstructorInfo name tyvars' context2+                                       fields' stricts <$> variantQ+                     | name <- names+                     , let variantQ = getVariant name+                     ]         _ -> fail "normalizeGadtC: Expected type constructor application" @@ -352,17 +707,16 @@     aux (VarT n,p) (subst, context) =       case p of         VarT m | Map.notMember m subst -> (Map.insert m n subst, context)-        _ -> (subst, EqualityT `AppT` VarT n `AppT` p : context)+        _ -> (subst, equalPred (VarT n) p : context)      aux _ sc = sc-#endif  -- | Expand all of the type synonyms in a type. resolveTypeSynonyms :: Type -> Q Type resolveTypeSynonyms t =   let f :| xs = decomposeType t -      notTypeSynCase = foldl AppT f <$> traverse resolveTypeSynonyms xs in+      notTypeSynCase = foldl AppT f <$> mapM resolveTypeSynonyms xs in    case f of     ConT n ->@@ -395,20 +749,38 @@ -- saves dependencies for supporting older GHCs data NonEmpty a = a :| [a] +#if MIN_VERSION_template_haskell(2,8,0) && (!MIN_VERSION_template_haskell(2,10,0))+data NonEmptySnoc a = [a] :|- a +-- Decompose a function type into its context, argument types,+-- and return types. For instance, this+--+--   (Show a, b ~ Int) => (a -> b) -> Char -> Int+--+-- becomes+--+--   ([Show a, b ~ Int], [a -> b, Char] :|- Int)+uncurryType :: Type -> (Cxt, NonEmptySnoc Type)+uncurryType = go [] []+  where+    go ctxt args (AppT (AppT ArrowT t1) t2) = go ctxt (t1:args) t2+    go ctxt args (ForallT _ ctxt' t)        = go (ctxt++ctxt') args t+    go ctxt args t                          = (ctxt, reverse args :|- t)+#endif+ -- | Resolve any infix type application in a type using the fixities that -- are currently available. Starting in `template-haskell-2.11` types could -- contain unresolved infix applications. resolveInfixT :: Type -> Q Type  #if MIN_VERSION_template_haskell(2,11,0)-resolveInfixT (ForallT vs cx t) = forallT vs (traverse resolveInfixT cx) (resolveInfixT t)+resolveInfixT (ForallT vs cx t) = forallT 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)-resolveInfixT t                 = pure t+resolveInfixT t                 = return t  gatherUInfixT :: Type -> InfixList gatherUInfixT (UInfixT l o r) = ilAppend (gatherUInfixT l) o (gatherUInfixT r)@@ -419,7 +791,7 @@ resolveInfixT1 = go []   where     go :: [(Type,Name,Fixity)] -> InfixList -> TypeQ-    go ts (ILNil u) = pure (foldl (\acc (l,o,_) -> ConT o `AppT` l `AppT` acc) u ts)+    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 <$> reifyFixity o          let push = go ((l,o,ofx):ts) r@@ -455,7 +827,7 @@  #else -- older template-haskell packages don't have UInfixT-resolveInfixT = pure+resolveInfixT = return #endif  @@ -484,6 +856,13 @@ 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] @@ -506,7 +885,7 @@ freshenFreeVariables :: Type -> Q Type freshenFreeVariables t =   do let xs = [ (n, VarT <$> newName (nameBase n)) | n <- freeVariables t]-     subst <- sequenceA (Map.fromList xs)+     subst <- T.sequence (Map.fromList xs)      return (applySubstitution subst t)  @@ -591,9 +970,9 @@ -- | Compute the type variable substitution that unifies a list of types, -- or fail in 'Q'. unifyTypes :: [Type] -> Q (Map Name Type)-unifyTypes [] = pure Map.empty+unifyTypes [] = return Map.empty unifyTypes (t:ts) =-  do t':ts' <- traverse resolveTypeSynonyms (t:ts)+  do t':ts' <- mapM resolveTypeSynonyms (t:ts)      let aux sub u =            do sub' <- unify' (applySubstitution sub t')                              (applySubstitution sub u)@@ -675,6 +1054,30 @@  ------------------------------------------------------------------------ +-- On old versions of GHC, reify would not give you kind signatures for+-- GADT type variables of kind *. To work around this, we insert the kinds+-- manually on any types without a signature.++giveTypesStarKinds :: DatatypeInfo -> DatatypeInfo+giveTypesStarKinds info =+  info { datatypeVars = annotateVars (datatypeVars info) }+  where+    annotateVars :: [Type] -> [Type]+    annotateVars = map $ \t ->+      case t of+        VarT n -> SigT (VarT n) starK+        _      -> t++giveTyVarBndrsStarKinds :: ConstructorInfo -> ConstructorInfo+giveTyVarBndrsStarKinds info =+  info { constructorVars = annotateVars (constructorVars info) }+  where+    annotateVars :: [TyVarBndr] -> [TyVarBndr]+    annotateVars = map $ \tvb ->+      case tvb of+        PlainTV n -> KindedTV n starK+        _         -> tvb+ -- | Prior to GHC 8.2.1, reify was broken for data instances and newtype -- instances. This code attempts to detect the problem and repair it if -- possible.@@ -693,7 +1096,7 @@ -- https://ghc.haskell.org/trac/ghc/ticket/13618 repair13618 :: DatatypeInfo -> Q DatatypeInfo repair13618 info =-  do s <- sequenceA (Map.fromList substList)+  do s <- T.sequence (Map.fromList substList)      return info { datatypeCons = applySubstitution s (datatypeCons info) }    where@@ -728,7 +1131,7 @@ #elif MIN_VERSION_template_haskell(2,11,0) dataDCompat c n ts cs ds =   dataD c n ts Nothing cs-    (pure (map ConT ds))+    (return (map ConT ds)) #else dataDCompat = dataD #endif@@ -738,4 +1141,28 @@ arrowKCompat x y = arrowK `appK` x `appK` y #else arrowKCompat = arrowK+#endif++------------------------------------------------------------------------++-- | Backwards compatibility wrapper for 'Fixity' lookup.+--+-- In @template-haskell-2.11.0.0@ and later, the answer will always+-- be 'Just' of a fixity.+--+-- Before @template-haskell-2.11.0.0@ it was only possible to determine+-- fixity information for variables, class methods, and data constructors.+-- In this case for type operators the answer could be 'Nothing', which+-- indicates that the answer is unavailable.+reifyFixityCompat :: Name -> Q (Maybe Fixity)+#if MIN_VERSION_template_haskell(2,11,0)+reifyFixityCompat n = (`mplus` Just defaultFixity) <$> reifyFixity n+#else+reifyFixityCompat n =+  do info <- reify n+     return $! case info of+       ClassOpI _ _ _ fixity -> Just fixity+       DataConI _ _ _ fixity -> Just fixity+       VarI     _ _ _ fixity -> Just fixity+       _                     -> Nothing #endif
src/Language/Haskell/TH/Datatype/Internal.hs view
@@ -14,3 +14,7 @@  eqTypeName :: Name eqTypeName = mkNameG_tc "base" "Data.Type.Equality" "~"++-- This is only needed for GHC 7.6-specific bug+starKindName :: Name+starKindName = mkNameG_tc "ghc-prim" "GHC.Prim" "*"
test/Harness.hs view
@@ -1,4 +1,4 @@-{-# Language TemplateHaskell #-}+{-# Language CPP, TemplateHaskell #-}  {-| Module      : Harness@@ -12,20 +12,17 @@ up to alpha renaming.  -}-module Harness (validate) where+module Harness (validate, varKCompat) where  import           Control.Monad import qualified Data.Map as Map import           Language.Haskell.TH import           Language.Haskell.TH.Datatype+import           Language.Haskell.TH.Lib (starK)  validate :: DatatypeInfo -> DatatypeInfo -> ExpQ validate x y = either fail (\_ -> [| return () |]) (equateDI x y) -stripOuterSigT :: Type -> Type-stripOuterSigT (SigT t _) = t-stripOuterSigT t          = t- -- | If the arguments are equal up to renaming return @'Right' ()@, -- otherwise return a string exlaining the mismatch. equateDI :: DatatypeInfo -> DatatypeInfo -> Either String ()@@ -38,29 +35,34 @@      let sub = Map.fromList (zip (freeVariables (datatypeVars dat2))                                  (map VarT (freeVariables (datatypeVars dat1)))) -     check "datatypeContext" id+     zipWithM_ (equateCxt "datatypeContext")        (datatypeContext dat1)        (applySubstitution sub (datatypeContext dat2))       check "datatypeVars" id-       (map stripOuterSigT (datatypeVars dat1))+       (datatypeVars dat1)        (applySubstitution sub (datatypeVars dat2))       zipWithM_ equateCI        (datatypeCons dat1)        (applySubstitution sub (datatypeCons dat2)) +equateCxt :: String -> Pred -> Pred -> Either String ()+equateCxt lbl pred1 pred2 =+  do check (lbl ++ " class")    asClassPred pred1 pred2+     check (lbl ++ " equality") asEqualPred pred1 pred2+ -- | If the arguments are equal up to renaming return @'Right' ()@, -- otherwise return a string exlaining the mismatch. equateCI :: ConstructorInfo -> ConstructorInfo -> Either String () equateCI con1 con2 =-  do check "constructorName"     constructorName    con1 con2-     check "constructorVariant"  constructorVariant con1 con2+  do check "constructorName"       constructorName       con1 con2+     check "constructorVariant"    constructorVariant    con1 con2       let sub = Map.fromList (zip (map tvName (constructorVars con2))                                  (map VarT (map tvName (constructorVars con1)))) -     check "constructorContext" id+     zipWithM_ (equateCxt "constructorContext")         (constructorContext con1)         (applySubstitution sub (constructorContext con2)) @@ -68,7 +70,35 @@         (constructorFields con1)         (applySubstitution sub (constructorFields con2)) +     zipWithM_ equateStrictness+        (constructorStrictness con1)+        (constructorStrictness con2)++equateStrictness :: FieldStrictness -> FieldStrictness -> Either String ()+equateStrictness fs1 fs2 =+  check "constructorStrictness" oldGhcHack fs1 fs2+  where+#if MIN_VERSION_template_haskell(2,7,0)+    oldGhcHack = id+#else+    -- GHC 7.0 and 7.2 didn't have an Unpacked TH constructor, so as a+    -- simple workaround, we will treat unpackedAnnot as isStrictAnnot+    -- (the closest equivalent).+    oldGhcHack fs+      | fs == unpackedAnnot = isStrictAnnot+      | otherwise           = fs+#endif+ check :: (Show b, Eq b) => String -> (a -> b) -> a -> a -> Either String () check lbl f x y   | f x == f y = Right ()   | otherwise  = Left (lbl ++ ":\n\n" ++ show (f x) ++ "\n\n" ++ show (f y))++-- If on a recent-enough version of Template Haskell, construct a kind variable.+-- Otherwise, default to starK.+varKCompat :: Name -> Kind+#if MIN_VERSION_template_haskell(2,8,0)+varKCompat = VarT+#else+varKCompat _ = starK+#endif
test/Main.hs view
@@ -1,5 +1,9 @@-{-# Language CPP, PolyKinds, TypeFamilies, KindSignatures, TemplateHaskell, GADTs #-}+{-# Language CPP, TypeFamilies, KindSignatures, TemplateHaskell, GADTs #-} +#if MIN_VERSION_template_haskell(2,8,0)+{-# Language PolyKinds #-}+#endif+ {-| Module      : Main Description : Test cases for the th-abstraction package@@ -16,14 +20,18 @@  import Language.Haskell.TH import Language.Haskell.TH.Datatype+import Language.Haskell.TH.Lib (starK)  import Harness  type Gadt1Int = Gadt1 Int +infixr 6 :**: data Gadt1 (a :: *) where-  Gadtc1 :: Int   -> Gadt1Int-  Gadtc2 :: (a,a) -> Gadt1 a+  Gadtc1 :: Int          -> Gadt1Int+  Gadtc2 :: (a,a)        -> Gadt1 a+  (:**:) :: Bool -> Char -> Gadt1 ()     -- This is declared infix+  (:!!:) :: Char -> Bool -> Gadt1 Double -- This is not  data Adt1 (a :: *) (b :: *) = Adtc1 (a,b) | Bool `Adtc2` Int @@ -43,20 +51,43 @@   Gadt2c2 :: Gadt2 [a] a   Gadt2c3 :: Gadt2 [a] [a] +data VoidStoS (f :: * -> *)++data StrictDemo = StrictDemo Int !Int {-# UNPACK #-} !Int++#if MIN_VERSION_template_haskell(2,7,0)++-- Data families+ data family DF (a :: *) data instance DF (Maybe a) = DFMaybe Int [a] -#if MIN_VERSION_template_haskell(2,9,0)+# if MIN_VERSION_template_haskell(2,8,0) data family DF1 (a :: k)-#elif MIN_VERSION_template_haskell(2,8,0)-data family DF1 a-#else+# else data family DF1 (a :: *)-#endif+# endif data instance DF1 b = DF1 b -data VoidStoS (f :: * -> *) +# if MIN_VERSION_template_haskell(2,8,0)+data family Poly (a :: k)+# else+data family Poly (a :: *)+# endif+data instance Poly a = MkPoly++data family GadtFam (a :: *) (b :: *)+data instance GadtFam c d where+  MkGadtFam1 :: x   -> y        -> GadtFam y x+  (:&&:)     :: e   -> f        -> GadtFam [e] f   -- This is declard infix+  (:^^:)     :: Int -> Int      -> GadtFam Int Int -- This is not+  MkGadtFam4 :: (Int ~ z) => z  -> GadtFam z z+  MkGadtFam5 :: (q ~ Char) => q -> GadtFam Bool Bool+infixl 3 :&&:++#endif+ return [] -- segment type declarations above from refiy below  -- | Test entry point. Tests will pass or fail at compile time.@@ -69,21 +100,28 @@      equalTest      showableTest      recordTest+     voidstosTest+     strictDemoTest+#if MIN_VERSION_template_haskell(2,7,0)      dataFamilyTest      ghc78bugTest-     voidstosTest+     polyTest+     gadtFamTest+#endif+     fixityLookupTest  adt1Test :: IO () adt1Test =   $(do info <- reifyDatatype ''Adt1 -       let [a,b] = map (VarT . mkName) ["a","b"]+       let vars@[a,b]  = map (VarT . mkName) ["a","b"]+           [aSig,bSig] = map (\v -> SigT v starK) vars         validate info          DatatypeInfo            { datatypeName = ''Adt1            , datatypeContext = []-           , datatypeVars = [a, b]+           , datatypeVars = [aSig, bSig]            , datatypeVariant = Datatype            , datatypeCons =                [ ConstructorInfo@@ -91,13 +129,15 @@                    , constructorContext = []                    , constructorVars = []                    , constructorFields = [AppT (AppT (TupleT 2) a) b]+                   , constructorStrictness = [notStrictAnnot]                    , constructorVariant = NormalConstructor }                , ConstructorInfo                    { constructorName = 'Adtc2                    , constructorContext = []                    , constructorVars = []                    , constructorFields = [ConT ''Bool, ConT ''Int]-                   , constructorVariant = NormalConstructor }+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant = InfixConstructor }                ]            }    )@@ -112,7 +152,7 @@          DatatypeInfo            { datatypeName = ''Gadt1            , datatypeContext = []-           , datatypeVars = [a]+           , datatypeVars = [SigT a starK]            , datatypeVariant = Datatype            , datatypeCons =                [ ConstructorInfo@@ -120,13 +160,29 @@                    , constructorVars = []                    , constructorContext = [equalPred a (ConT ''Int)]                    , constructorFields = [ConT ''Int]+                   , constructorStrictness = [notStrictAnnot]                    , constructorVariant = NormalConstructor }                , ConstructorInfo                    { constructorName = 'Gadtc2                    , constructorVars = []                    , constructorContext = []                    , constructorFields = [AppT (AppT (TupleT 2) a) a]+                   , constructorStrictness = [notStrictAnnot]                    , constructorVariant = NormalConstructor }+               , ConstructorInfo+                   { constructorName = '(:**:)+                   , constructorVars = []+                   , constructorContext = [equalPred a (TupleT 0)]+                   , constructorFields = [ConT ''Bool, ConT ''Char]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant = InfixConstructor }+               , ConstructorInfo+                   { constructorName = '(:!!:)+                   , constructorVars = []+                   , constructorContext = [equalPred a (ConT ''Double)]+                   , constructorFields = [ConT ''Char, ConT ''Bool]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant = NormalConstructor }                ]            }    )@@ -135,22 +191,24 @@ gadtrec1Test =   $(do info <- reifyDatatype ''Gadtrec1 -       let a = VarT (mkName "a")-       let [v1,v2] = map mkName ["v1","v2"]+       let a             = VarT (mkName "a")+           names@[v1,v2] = map mkName ["v1","v2"]+           [v1K,v2K]     = map (\n -> KindedTV n starK) names         let con = ConstructorInfo-                   { constructorName    = 'Gadtrecc1-                   , constructorVars    = [PlainTV v1, PlainTV v2]-                   , constructorContext =+                   { constructorName       = 'Gadtrecc1+                   , constructorVars       = [v1K, v2K]+                   , constructorContext    =                         [equalPred a (AppT (AppT (TupleT 2) (VarT v1)) (VarT v2))]-                   , constructorFields  = [VarT v1, VarT v2]-                   , constructorVariant = RecordConstructor ['gadtrec1a, 'gadtrec1b] }+                   , constructorFields     = [VarT v1, VarT v2]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant    = RecordConstructor ['gadtrec1a, 'gadtrec1b] }         validate info          DatatypeInfo            { datatypeName    = ''Gadtrec1            , datatypeContext = []-           , datatypeVars    = [a]+           , datatypeVars    = [SigT a starK]            , datatypeVariant = Datatype            , datatypeCons    =                [ con, con { constructorName = 'Gadtrecc2 } ]@@ -161,23 +219,26 @@ equalTest =   $(do info <- reifyDatatype ''Equal -       let [a,b,c] = map (VarT . mkName) ["a","b","c"]+       let vars@[a,b,c]     = map (VarT . mkName) ["a","b","c"]+           [aSig,bSig,cSig] = map (\v -> SigT v starK) vars         validate info          DatatypeInfo            { datatypeName    = ''Equal            , datatypeContext = []-           , datatypeVars    = [a, b, c]+           , datatypeVars    = [aSig, bSig, cSig]            , datatypeVariant = Datatype            , datatypeCons    =                [ ConstructorInfo-                   { constructorName    = 'Equalc-                   , constructorVars    = []-                   , constructorContext =+                   { constructorName       = 'Equalc+                   , constructorVars       = []+                   , constructorContext    =                         [equalPred a c, equalPred b c, classPred ''Read [c], classPred ''Show [c] ]-                   , constructorFields  =+                   , constructorFields     =                         [ListT `AppT` c, ConT ''Maybe `AppT` c]-                   , constructorVariant = NormalConstructor }+                   , constructorStrictness =+                        [notStrictAnnot, notStrictAnnot]+                   , constructorVariant    = NormalConstructor }                ]            }    )@@ -196,11 +257,12 @@            , datatypeVariant = Datatype            , datatypeCons    =                [ ConstructorInfo-                   { constructorName    = 'Showable-                   , constructorVars    = [PlainTV a]-                   , constructorContext = [classPred ''Show [VarT a]]-                   , constructorFields  = [VarT a]-                   , constructorVariant = NormalConstructor }+                   { constructorName       = 'Showable+                   , constructorVars       = [PlainTV a]+                   , constructorContext    = [classPred ''Show [VarT a]]+                   , constructorFields     = [VarT a]+                   , constructorStrictness = [notStrictAnnot]+                   , constructorVariant    = NormalConstructor }                ]            }    )@@ -216,11 +278,12 @@            , datatypeVariant = Datatype            , datatypeCons    =                [ ConstructorInfo-                   { constructorName    = 'R1-                   , constructorVars    = []-                   , constructorContext = []-                   , constructorFields  = [ConT ''Int, ConT ''Int]-                   , constructorVariant = RecordConstructor ['field1, 'field2] }+                   { constructorName       = 'R1+                   , constructorVars       = []+                   , constructorContext    = []+                   , constructorFields     = [ConT ''Int, ConT ''Int]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant    = RecordConstructor ['field1, 'field2] }                ]            }    )@@ -228,19 +291,21 @@ gadt2Test :: IO () gadt2Test =   $(do info <- reifyDatatype ''Gadt2-       let [a,b] = map (VarT . mkName) ["a","b"]+       let vars@[a,b]  = map (VarT . mkName) ["a","b"]+           [aSig,bSig] = map (\v -> SigT v starK) vars            x     = mkName "x"            con   = ConstructorInfo-                     { constructorName    = undefined-                     , constructorVars    = []-                     , constructorContext = []-                     , constructorFields  = []-                     , constructorVariant = NormalConstructor }+                     { constructorName       = undefined+                     , constructorVars       = []+                     , constructorContext    = []+                     , constructorFields     = []+                     , constructorStrictness = []+                     , constructorVariant    = NormalConstructor }        validate info          DatatypeInfo            { datatypeName    = ''Gadt2            , datatypeContext = []-           , datatypeVars    = [a, b]+           , datatypeVars    = [aSig, bSig]            , datatypeVariant = Datatype            , datatypeCons    =                [ con { constructorName = 'Gadt2c1@@ -248,13 +313,51 @@                , con { constructorName = 'Gadt2c2                      , constructorContext = [equalPred a (AppT ListT b)] }                , con { constructorName = 'Gadt2c3-                     , constructorVars = [PlainTV x]+                     , constructorVars = [KindedTV x starK]                      , constructorContext =                          [equalPred a (AppT ListT (VarT x))                          ,equalPred b (AppT ListT (VarT x))] } ]            }   ) +voidstosTest :: IO ()+voidstosTest =+  $(do info <- reifyDatatype ''VoidStoS+       let g = mkName "g"+       validate info+         DatatypeInfo+           { datatypeName    = ''VoidStoS+           , datatypeContext = []+           , datatypeVars    = [SigT (VarT g) (arrowKCompat starK starK)]+           , datatypeVariant = Datatype+           , datatypeCons    = []+           }+  )++strictDemoTest :: IO ()+strictDemoTest =+  $(do info <- reifyDatatype ''StrictDemo+       validate info+         DatatypeInfo+           { datatypeName    = ''StrictDemo+           , datatypeContext = []+           , datatypeVars    = []+           , datatypeVariant = Datatype+           , datatypeCons    =+               [ ConstructorInfo+                   { constructorName       = 'StrictDemo+                   , constructorVars       = []+                   , constructorContext    = []+                   , constructorFields     = [ConT ''Int, ConT ''Int, ConT ''Int]+                   , constructorStrictness = [ notStrictAnnot+                                             , isStrictAnnot+                                             , unpackedAnnot+                                             ]+                   , constructorVariant    = NormalConstructor } ]+           }+   )++#if MIN_VERSION_template_haskell(2,7,0) dataFamilyTest :: IO () dataFamilyTest =   $(do info <- reifyDatatype 'DFMaybe@@ -267,44 +370,117 @@            , datatypeVariant = DataInstance            , datatypeCons    =                [ ConstructorInfo-                   { constructorName    = 'DFMaybe-                   , constructorVars    = []-                   , constructorContext = []-                   , constructorFields  = [ConT ''Int, ListT `AppT` VarT a]-                   , constructorVariant = NormalConstructor } ]+                   { constructorName       = 'DFMaybe+                   , constructorVars       = []+                   , constructorContext    = []+                   , constructorFields     = [ConT ''Int, ListT `AppT` VarT a]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant    = NormalConstructor } ]            }   )  ghc78bugTest :: IO () ghc78bugTest =   $(do info <- reifyDatatype 'DF1-       let c = mkName "c"+       let c = VarT (mkName "c")        validate info          DatatypeInfo            { datatypeName    = ''DF1            , datatypeContext = []-           , datatypeVars    = [VarT c]+           , datatypeVars    = [SigT c starK]            , datatypeVariant = DataInstance            , datatypeCons    =                [ ConstructorInfo-                   { constructorName    = 'DF1-                   , constructorVars    = []-                   , constructorContext = []-                   , constructorFields  = [VarT c]-                   , constructorVariant = NormalConstructor } ]+                   { constructorName       = 'DF1+                   , constructorVars       = []+                   , constructorContext    = []+                   , constructorFields     = [c]+                   , constructorStrictness = [notStrictAnnot]+                   , constructorVariant    = NormalConstructor } ]            }   ) -voidstosTest :: IO ()-voidstosTest =-  $(do info <- reifyDatatype ''VoidStoS-       let g = mkName "g"+polyTest :: IO ()+polyTest =+  $(do info <- reifyDatatype 'MkPoly+       let [a,k] = map mkName ["a","k"]        validate info          DatatypeInfo-           { datatypeName    = ''VoidStoS+           { datatypeName    = ''Poly            , datatypeContext = []-           , datatypeVars    = [VarT g]-           , datatypeVariant = Datatype-           , datatypeCons    = []+           , datatypeVars    = [SigT (VarT a) (varKCompat k)]+           , datatypeVariant = DataInstance+           , datatypeCons    =+               [ ConstructorInfo+                   { constructorName       = 'MkPoly+                   , constructorVars       = []+                   , constructorContext    = []+                   , constructorFields     = []+                   , constructorStrictness = []+                   , constructorVariant    = NormalConstructor } ]            }   )++gadtFamTest :: IO ()+gadtFamTest =+  $(do info <- reifyDatatype 'MkGadtFam1+       let names@[c,d,e,q]   = map mkName ["c","d","e","q"]+           [cTy,dTy,eTy,qTy] = map VarT names+           [cSig,dSig]       = map (\v -> SigT v starK) [cTy,dTy]+       validate info+         DatatypeInfo+           { datatypeName    = ''GadtFam+           , datatypeContext = []+           , datatypeVars    = [cSig,dSig]+           , datatypeVariant = DataInstance+           , datatypeCons    =+               [ ConstructorInfo+                   { constructorName       = 'MkGadtFam1+                   , constructorVars       = []+                   , constructorContext    = []+                   , constructorFields     = [dTy,cTy]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant    = NormalConstructor }+               , ConstructorInfo+                   { constructorName       = '(:&&:)+                   , constructorVars       = [PlainTV e]+                   , constructorContext    = [equalPred cTy (AppT ListT eTy)]+                   , constructorFields     = [eTy,dTy]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant    = InfixConstructor }+               , ConstructorInfo+                   { constructorName       = '(:^^:)+                   , constructorVars       = []+                   , constructorContext    = [ equalPred cTy (ConT ''Int)+                                             , equalPred dTy (ConT ''Int)+                                             ]+                   , constructorFields     = [ConT ''Int, ConT ''Int]+                   , constructorStrictness = [notStrictAnnot, notStrictAnnot]+                   , constructorVariant    = NormalConstructor }+               , ConstructorInfo+                   { constructorName       = 'MkGadtFam4+                   , constructorVars       = []+                   , constructorContext    = [ equalPred cTy dTy+                                             , equalPred (ConT ''Int) dTy+                                             ]+                   , constructorFields     = [dTy]+                   , constructorStrictness = [notStrictAnnot]+                   , constructorVariant    = NormalConstructor }+               , ConstructorInfo+                   { constructorName       = 'MkGadtFam5+                   , constructorVars       = [PlainTV q]+                   , constructorContext    = [ equalPred cTy (ConT ''Bool)+                                             , equalPred dTy (ConT ''Bool)+                                             , equalPred qTy (ConT ''Char)+                                             ]+                   , constructorFields     = [qTy]+                   , constructorStrictness = [notStrictAnnot]+                   , constructorVariant    = NormalConstructor } ]+           }+   )+#endif++fixityLookupTest :: IO ()+fixityLookupTest =+  $(do Just (Fixity 6 InfixR) <- reifyFixityCompat '(:**:)+       [| return () |])
th-abstraction.cabal view
@@ -1,5 +1,5 @@ name:                th-abstraction-version:             0.1.3.0+version:             0.2.0.0 synopsis:            Nicer interface for reified information about data types description:         This package normalizes variations in the interface for                      inspecting datatype information via Template Haskell@@ -17,7 +17,7 @@ build-type:          Simple extra-source-files:  ChangeLog.md cabal-version:       >=1.10-tested-with:         GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2+tested-with:         GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2, GHC==7.2.2, GHC==7.0.4  source-repository head   type: git@@ -26,9 +26,9 @@ library   exposed-modules:     Language.Haskell.TH.Datatype   other-modules:       Language.Haskell.TH.Datatype.Internal-  build-depends:       base             >=4.5   && <5,+  build-depends:       base             >=4.3   && <5,                        ghc-prim,-                       template-haskell >=2.7   && <2.13,+                       template-haskell >=2.5   && <2.13,                        containers       >=0.4   && <0.6   hs-source-dirs:      src   default-language:    Haskell2010