packages feed

derive-topdown 0.1.1.0 → 0.1.1.1

raw patch · 15 files changed

+420/−185 lines, 15 filesdep +haskell-src-extsPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependencies added: haskell-src-exts

API changes (from Hackage documentation)

+ Data.Derive.TopDown.Instance: instance_debug :: Name -> Name -> Q [Dec]
+ Data.Derive.TopDown.Instance: instance_with_breaks_debug :: Name -> Name -> [Name] -> Q [Dec]
+ Data.Derive.TopDown.Instance: instance_with_debug :: ClassName -> TypeName -> [TypeName] -> Maybe Overlap -> ContextGenerator -> Q [Dec]
+ Data.Derive.TopDown.Instance: instances_debug :: [Name] -> Name -> Q [Dec]
+ Data.Derive.TopDown.Instance: instancess_debug :: [Name] -> [Name] -> Q [Dec]
+ Data.Derive.TopDown.Standalone: deriving_debug :: Name -> Name -> Q [Dec]
+ Data.Derive.TopDown.Standalone: deriving_with_breaks_debug :: Name -> Name -> [Name] -> Q [Dec]
+ Data.Derive.TopDown.Standalone: deriving_with_debug :: ClassName -> TypeName -> Maybe DerivStrategy -> [TypeName] -> ContextGenerator -> Q [Dec]
+ Data.Derive.TopDown.Standalone: derivings_debug :: [Name] -> Name -> Q [Dec]
+ Data.Derive.TopDown.Standalone: derivingss_debug :: [Name] -> [Name] -> Q [Dec]
+ Data.Derive.TopDown.Standalone: strategy_deriving_debug :: DerivStrategy -> Name -> Name -> Q [Dec]
+ Data.Derive.TopDown.Standalone: strategy_derivings_debug :: DerivStrategy -> [Name] -> Name -> Q [Dec]
+ Data.Derive.TopDown.Standalone: strategy_derivingss_debug :: DerivStrategy -> [Name] -> [Name] -> Q [Dec]

Files

README.md view
@@ -62,9 +62,9 @@ instance Binary a_af4Y => Binary (Company a_af4Y) ``` ## 3. Usage with Template Haskell-For generating instances with a template Haskell function, `deriving_th`, `deriving_ths` and `deriving_thss` can be used:+For generating instances with a template Haskell function, `derivingTH`, `derivingTHs` and `derivingTHss` can be used: ```haskell-deriving_ths+derivingTHs     [(''ToJSON, deriveToJSON defaultOptions),     (''FromJSON, deriveFromJSON defaultOptions)]     ''Company
derive-topdown.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.37.0.+-- This file has been generated from package.yaml by hpack version 0.39.1. -- -- see: https://github.com/sol/hpack  name:           derive-topdown-version:        0.1.1.0+version:        0.1.1.1 synopsis:       Derive type class instances description:    This package will make it easier to derive class instance for complex composited data types by using Template Haskell. category:       Development@@ -18,7 +18,7 @@ license-file:   LICENSE build-type:     Simple tested-with:-    GHC == 8.2.2 , GHC == 8.4.4 , GHC == 8.6.5 , GHC == 8.8.4 , GHC == 8.10.7 , GHC == 9.0.2 , GHC == 9.2.8 , GHC == 9.4.8 , GHC == 9.6.5 , GHC == 9.8.2 , GHC == 9.10.1+    GHC == 8.4.4 , GHC == 8.6.5 , GHC == 8.8.4 , GHC == 8.10.7 , GHC == 9.0.2 , GHC == 9.2.8 , GHC == 9.4.8 , GHC == 9.6.5 , GHC == 9.8.2 , GHC == 9.10.1 , GHC == 9.12.2 , GHC == 9.14.1 extra-source-files:     README.md     CHANGELOG.md@@ -40,6 +40,8 @@       Data.Derive.TopDown   other-modules:       Data.Derive.TopDown.Lib+      Data.Derive.TopDown.StandaloneDecGen+      Data.Derive.TopDown.InstanceDecGen   hs-source-dirs:       src   default-extensions:@@ -83,6 +85,7 @@     , derive-topdown     , ghc     , haskell-src+    , haskell-src-exts     , mtl     , primitive     , syb
src/Data/Derive/Superclass.hs view
@@ -28,6 +28,7 @@                                                 , nub                                                 ) import           Language.Haskell.TH+import           Debug.Trace                    (traceM)    -- Only support class that has paramter with kind * or * -> * deriving_superclasses'@@ -63,9 +64,9 @@               ConT className -> do                 superclass_decls <- deriving_superclasses' st className tn                 return superclass_decls-              x -> error $ "cannot generate class for " ++ show x+              x -> traceM ("cannot generate class for " ++ show x) >> error ""           return $ topClassInstance ++ ss-        _ -> error $ show cn ++ "is not type class"+        _ -> traceM (show cn ++ "is not type class") >> error ""  {- | Note: It cannot be used with mutual recursive types. 
src/Data/Derive/TopDown/CxtGen.hs view
@@ -50,6 +50,7 @@ import           Data.Set                       ( Set ) import           GHC.Generics import           Language.Haskell.TH+import           Debug.Trace  data Env = Env   { inferring    :: [Name]             -- ^ encountered types during infer process@@ -131,34 +132,34 @@   SigT     ty _  -> doesFieldContainPotentialContext ty   VarT      _    -> return True   ConT      _    -> return False-  PromotedT _    -> error "impossible field for PromotedT"+  PromotedT _    -> traceM "impossible field for PromotedT" >> error ""   InfixT t1 _ t2 -> liftA2 (||)                            (doesFieldContainPotentialContext t1)                            (doesFieldContainPotentialContext t2)-  UInfixT         _ _ _ -> error "impossible field for UInfixT"+  UInfixT         _ _ _ -> traceM "impossible field for UInfixT" >> error "" #if __GLASGOW_HASKELL__ >= 904-  PromotedInfixT  _ _ _ -> error "impossible field for PromotedInfixT"-  PromotedUInfixT _ _ _ -> error "impossible field for PromotedUInfixT"+  PromotedInfixT  _ _ _ -> traceM "impossible field for PromotedInfixT" >> error ""+  PromotedUInfixT _ _ _ -> traceM "impossible field for PromotedUInfixT" >> error "" #endif   ParensT       ty      -> doesFieldContainPotentialContext ty-  TupleT        _       -> error "impossible field for TupleT"-  UnboxedTupleT _       -> error "impossible field for UnboxedTupleT"-  UnboxedSumT   _       -> error "impossible field for UnboxedSumT"+  TupleT        _       -> traceM "impossible field for TupleT" >> error ""+  UnboxedTupleT _       -> traceM "impossible field for UnboxedTupleT" >> error ""+  UnboxedSumT   _       -> traceM "impossible field for UnboxedSumT" >> error ""   ArrowT                -> undefined -- should put app of Arrow into context? #if __GLASGOW_HASKELL__ >= 900   MulArrowT             -> undefined #endif-  EqualityT             -> error "impossible field for EqualityT"-  ListT                 -> error "impossible field for ListT"-  PromotedTupleT _      -> error "impossible field for PromotedTupleT"-  PromotedNilT          -> error "impossible field for PromotedNilT"-  PromotedConsT         -> error "impossible field for PromotedConsT"-  StarT                 -> error "impossible field for StarT"-  ConstraintT           -> error "impossible field for ConstraintT"-  LitT _                -> error "impossible field for LitT"-  WildCardT             -> error "impossible field for WildCardT"+  EqualityT             -> traceM "impossible field for EqualityT" >> error ""+  ListT                 -> traceM "impossible field for ListT" >> error ""+  PromotedTupleT _      -> traceM "impossible field for PromotedTupleT" >> error ""+  PromotedNilT          -> traceM "impossible field for PromotedNilT" >> error ""+  PromotedConsT         -> traceM "impossible field for PromotedConsT" >> error ""+  StarT                 -> traceM "impossible field for StarT" >> error ""+  ConstraintT           -> traceM "impossible field for ConstraintT" >> error ""+  LitT _                -> traceM "impossible field for LitT" >> error ""+  WildCardT             -> traceM "impossible field for WildCardT" >> error "" #if __GLASGOW_HASKELL__ >= 808-  ImplicitParamT _ _    -> error "impossible field for ImplicitParamT"+  ImplicitParamT _ _    -> traceM "impossible field for ImplicitParamT" >> error "" #endif  -- | a lazily applied type paramters lookup function@@ -221,14 +222,19 @@           return $ S.fromList tn_context'  apply_until_fix_point :: Name -> CIM ()-apply_until_fix_point tn = do-  env <- get-  let tn_fields = fields env ! tn-  gen_subst tn-  subst_data_newtype tn-  env' <- get-  let tn_fields' = fields env' ! tn-  if tn_fields == tn_fields' then return () else apply_until_fix_point tn+apply_until_fix_point tn = go []+ where+  go seen = do+    env <- get+    let tn_fields = fields env ! tn+    if tn_fields `elem` seen+      then return ()+      else do+        gen_subst tn+        subst_data_newtype tn+        env' <- get+        let tn_fields' = fields env' ! tn+        if tn_fields == tn_fields' then return () else go (tn_fields : seen)  -- put fields of data or newtype fields into map gen_subst :: Name -> CIM ()@@ -273,12 +279,12 @@             map (VarT . mkName) [ 'a' : show x | x <- [1 .. n] ]       assert (length args == length tup_param_names)              (modify (putSubst tn t (zip tup_param_names args)))-    err_t -> error $ "gen_subst does not support type: " ++ show err_t+    err_t -> traceM $ "gen_subst does not support type: " ++ show err_t >> error ""  subst_data_newtype :: Name -> CIM () subst_data_newtype tn = do   env <- get-  let tn_substs = M.toList $ substitution env ! tn+  let tn_substs = M.toList $ M.findWithDefault M.empty tn (substitution env)   forM_ tn_substs $ \(t, t2t) -> case getLeftMostType t of     ConT ctn -> do       e <- get@@ -307,7 +313,7 @@             S.union (S.fromList new_context) (S.delete t (fields e ! tn))       modify $ putFields tn new_tn_fields     err_ty ->-      error $ "subst_data_newtype does not support type: " ++ show err_ty+      traceM $ "subst_data_newtype does not support type: " ++ show err_ty >> error ""  genInferredContext :: ClassName -> TypeName -> Q Cxt genInferredContext cn tn = if cn == ''Generic
src/Data/Derive/TopDown/Instance.hs view
@@ -16,65 +16,25 @@   , instances   , instancess   , instance_with+  , instance_debug+  , instance_with_breaks_debug+  , instances_debug+  , instancess_debug+  , instance_with_debug   ) where -import           Control.Monad import           Control.Monad.State import           Data.Derive.TopDown.CxtGen     ( genInferredContext )-import           Data.Derive.TopDown.IsInstance-import           Data.Derive.TopDown.Lib import           Data.Derive.TopDown.Types-import           Data.List                      ( foldl1' )+import           Data.Derive.TopDown.InstanceDecGen import           Language.Haskell.TH -gen_instance_decl-  :: ClassName-  -> TypeName-  -> [TypeName]  -- ^ a list of types that breaks the generation process-  -> Maybe Overlap-  -> ContextGenerator -- ^ a context generator-  -> StateT [Type] Q [Dec]-gen_instance_decl cn tn breaks mo cg = do-  (tvbs, cons) <- lift $ getTyVarCons tn-  let typeNames = map getTVBName tvbs-  isCnHighOrderClass <- lift $ isHigherOrderClass cn-  -- prevent calling isInstance class with * -> * and type with *-  if isCnHighOrderClass && null typeNames-    then return []-    else do-      saturatedType <- lift $ foldl1' appT (conT tn : map varT typeNames)-      instanceType  <- if isCnHighOrderClass && (not . null) typeNames-        then-          let pns = init typeNames-          in  if null pns-                then lift $ conT tn-                else lift $ foldl1' appT (conT tn : (map varT pns))-        else return saturatedType-      isMember <- lift $ isInstance' cn [instanceType]-      table    <- get-      if isMember || elem instanceType table || elem tn breaks-         -- normally empty instance will not be used to derive Generic-         -- so I do not check Generic and Generic1-        then return []-        else do-          classContext <- if isCnHighOrderClass-            then return []-            else lift $ cg cn tn-          let decl =-                [InstanceD mo classContext (AppT (ConT cn) instanceType) []]-          modify (instanceType :)-          names  <- lift $ fmap concat $ mapM getCompositeTypeNames cons-          names' <- lift-            $ filterM (\x -> isTypeFamily x >>= \b -> return $ not b) names-          xs <- mapM (\n -> gen_instance_decl cn n breaks mo cg) names'-          return $ concat xs ++ decl- instance_   :: Name -- ^ class name   -> Name -- ^ type name   -> Q [Dec] instance_ cn tn =-  evalStateT (gen_instance_decl cn tn [] Nothing genInferredContext) []+  evalStateT (gen_instance_decl cn tn [] Nothing genInferredContext False) []  instance_with_breaks   :: Name -- ^ class name@@ -82,7 +42,7 @@   -> [Name] -- ^ type names that stop the deriving process   -> Q [Dec] instance_with_breaks cn tn bs =-  evalStateT (gen_instance_decl cn tn bs Nothing genInferredContext) []+  evalStateT (gen_instance_decl cn tn bs Nothing genInferredContext False) []  instances   :: [Name] -- ^ class names@@ -103,4 +63,41 @@   -> Maybe Overlap   -> ContextGenerator -- ^ a context generator   -> Q [Dec]-instance_with cn tn bs mo cg = evalStateT (gen_instance_decl cn tn bs mo cg) []+instance_with cn tn bs mo cg = evalStateT (gen_instance_decl cn tn bs mo cg False) []+++instance_debug+  :: Name -- ^ class name+  -> Name -- ^ type name+  -> Q [Dec]+instance_debug cn tn =+  evalStateT (gen_instance_decl cn tn [] Nothing genInferredContext True) []++instance_with_breaks_debug+  :: Name -- ^ class name+  -> Name -- ^ type name+  -> [Name] -- ^ type names that stop the deriving process+  -> Q [Dec]+instance_with_breaks_debug cn tn bs =+  evalStateT (gen_instance_decl cn tn bs Nothing genInferredContext True) []++instances_debug+  :: [Name] -- ^ class names+  -> Name   -- ^ type name+  -> Q [Dec]+instances_debug cns tn = fmap concat (mapM (\x -> instance_ x tn) cns)++instancess_debug+  :: [Name] -- ^ class names+  -> [Name] -- ^ type names+  -> Q [Dec]+instancess_debug cns tns = fmap concat (mapM (\x -> instances cns x) tns)++instance_with_debug+  :: ClassName+  -> TypeName+  -> [TypeName]        -- ^ a list of types that breaks the generation process+  -> Maybe Overlap+  -> ContextGenerator -- ^ a context generator+  -> Q [Dec]+instance_with_debug cn tn bs mo cg = evalStateT (gen_instance_decl cn tn bs mo cg True) []
+ src/Data/Derive/TopDown/InstanceDecGen.hs view
@@ -0,0 +1,80 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Derive.TopDown.InstanceDecGen+-- Copyright   :  (c) Song Zhang+-- License     :  BSD-style (see the LICENSE file)+-- +-- Maintainer  :  haskell.zhang.song `at` hotmail.com+-- Stability   :  experimental+-- Portability :  non-portable+--+-----------------------------------------------------------------------------++module Data.Derive.TopDown.InstanceDecGen (+    gen_instance_decl+) where++import           Control.Monad+import           Control.Monad.State+import           Data.Derive.TopDown.IsInstance+import           Data.Derive.TopDown.Lib+import           Data.Derive.TopDown.Types+import           Data.List                      ( foldl1' )+import           Data.Primitive.Types+import           Language.Haskell.TH+import           Debug.Trace++gen_instance_decl+  :: ClassName+  -> TypeName+  -> [TypeName]  -- ^ a list of types that breaks the generation process+  -> Maybe Overlap+  -> ContextGenerator -- ^ a context generator+  -> Bool             -- ^ is debug+  -> StateT [Type] Q [Dec]+gen_instance_decl cn tn breaks mo cg debug = do+  when debug $ do+    traceM $ "standalone_deriving_decl: `" +            ++ show tn ++ "\' for class `"  ++ show cn ++ "\'"+  (tvbs, cons) <- lift $ getTyVarCons tn+  let typeNames = map getTVBName tvbs+  isCnHighOrderClass <- lift $ isHigherOrderClass cn+  -- prevent calling isInstance class with * -> * and type with *+  if isCnHighOrderClass && null typeNames+    then return []+    else do+      saturatedType <- lift $ foldl1' appT (conT tn : map varT typeNames)+      instanceType  <- if isCnHighOrderClass && (not . null) typeNames+        then+          let pns = init typeNames+          in  if null pns+                then lift $ conT tn+                else lift $ foldl1' appT (conT tn : (map varT pns))+        else return saturatedType+      isMember <- lift $ isInstance' cn [instanceType]+      when debug $ do+        traceM $ "standalone_deriving_decl: `" ++ show tn +                ++ "\' is instance of `" ++ show cn ++ "\':"+                ++ show isMember+      table    <- get+      isPrimitive <-lift $ isInstance' ''Prim [saturatedType]+      if isMember || elem instanceType table || elem tn breaks || isPrimitive+         -- normally empty instance will not be used to derive Generic+         -- so I do not check Generic and Generic1+        then return []+        else do+          classContext <- if isCnHighOrderClass+            then return []+            else lift $ cg cn tn+          when debug $ do+            traceM $ "standalone_deriving_decl: `"+                        ++ show tn ++ "\' context is " +                        ++ pprint classContext+          let decl =+                [InstanceD mo classContext (AppT (ConT cn) instanceType) []]+          modify (instanceType :)+          names  <- lift $ fmap concat $ mapM getCompositeTypeNames cons+          names' <- lift+            $ filterM (\x -> isTypeFamily x >>= \b -> return $ not b) names+          xs <- mapM (\n -> gen_instance_decl cn n breaks mo cg debug) names'+          return $ concat xs ++ decl
src/Data/Derive/TopDown/Lib.hs view
@@ -38,7 +38,7 @@     DatatypeInfo(..),     reifyDatatype     )-+import Debug.Trace (trace, traceM) noWarnExpandSynsWith :: Type -> Q Type noWarnExpandSynsWith = expandSynsWith noWarnTypeFamilies @@ -60,7 +60,7 @@                                     then t                                     else x substitute (VarT _, _) x = x-substitute (t, _) x = error $ "cannot substitute " ++ show t ++ " with " ++ show x+substitute (t, _) x = trace ("cannot substitute " ++ show t ++ " with " ++ show x) (error "")  substituteVar :: (Type, Type) -> Type -> Type substituteVar s = everywhere (mkT (substitute s))@@ -173,8 +173,8 @@                               if k == StarT                                 then return False                                 else return True-                  _ -> error $ "Cannot reify kind of class " ++ show cn-        _ -> error $ show cn ++ " is not a class"+                  _ -> traceM ("Cannot reify kind of class " ++ show cn) >> error ""+        _ -> traceM (show cn ++ " is not a class") >> error ""  getGadtCon :: Con -> [Con] getGadtCon g@(GadtC _ _ _) = [g]@@ -202,8 +202,8 @@ getAllConFields (ForallC  tvb   _  con)   = let ns = map (getTVBName. voidTyVarBndrFlag) tvb                                               in getAllConFields (replaceVarInForallTypeTrans ns con) -- https://gitlab.haskell.org/ghc/ghc/-/issues/13885#note_476439-getAllConFields (GadtC    _ _ _  ) = error "Should not use this to get fields of GADT"-getAllConFields (RecGadtC _ _ _  ) = error "Should not use this to get fields of GADT"+getAllConFields (GadtC    _ _ _  ) = trace "Should not use this to get fields of GADT" (error "")+getAllConFields (RecGadtC _ _ _  ) = trace "Should not use this to get fields of GADT" (error "")  {-| data T a1 a2 = Con1 a1 | Con2 a2 ...  return [a1, a2], [Con1 a1, Con2 a2]@@ -220,12 +220,13 @@                 case dec of                   DataD    _ _ tvbs _ cons _  -> return (map voidTyVarBndrFlag tvbs, cons)                   NewtypeD _ _ tvbs _ con  _  -> return (map voidTyVarBndrFlag tvbs, [con])-                  TySynD   _ _ _        -> error $ show name ++ " is a type synonym and `TypeSynonymInstances' is not supported.\n"-                      ++ "If you did not derive it then this is a bug, please report this bug to the author of `derive-topdown' package."+                  TySynD   _ _ _        -> traceM (show name ++ " is a type synonym and `TypeSynonymInstances' is not supported."+                      ++ "If you did not derive it then this is a bug, please report this bug to the author of `derive-topdown' package.") +                      >> (error "")                   x -> do-                      error $ pprint (x :: Dec) ++ " is not a data or newtype definition."+                      traceM (pprint (x :: Dec) ++ " is not a data or newtype definition.") >> error ""               PrimTyConI _ _ _ -> return ([], [])-              x -> error $ show x ++ " is not supported"+              x -> traceM (show x ++ " is not supported") >> error ""  #if __GLASGOW_HASKELL__ >= 900 getTyVarFields :: TypeName -> Q ([TyVarBndr ()], [Type])@@ -249,11 +250,12 @@                       else do                         return $ (map voidTyVarBndrFlag tvbs, getAllConsFields cons)                   NewtypeD _ _ tvbs _ con  _  -> return (map voidTyVarBndrFlag tvbs, getAllConsFields [con])-                  TySynD   _ _ _        -> error $ show name ++ " is a type synonym and `TypeSynonymInstances' is not supported.\n"-                      ++ "If you did not derive it then this is a bug, please report this bug to the author of `derive-topdown' package."+                  TySynD   _ _ _        -> traceM (show name ++ " is a type synonym and `TypeSynonymInstances' is not supported.\n"+                      ++ "If you did not derive it then this is a bug, please report this bug to the author of `derive-topdown' package.")+                      >> error ""                   x -> do-                      error $ pprint (x :: Dec) ++ " is not a data or newtype definition."-              _ -> error $ "Cannot generate instances for " ++ show name+                      traceM (pprint (x :: Dec) ++ " is not a data or newtype definition.") >> error ""+              _ -> traceM ("Cannot generate instances for " ++ show name) >> error ""  getTypeConstructor :: Type -> Type getTypeConstructor (AppT a1 _) = getTypeConstructor a1@@ -265,7 +267,7 @@                 case info of                   TyConI (DataD _ _ tvb _ _ _)    -> return $ map getTVBName tvb                   TyConI (NewtypeD _ _ tvb _ _ _) -> return $ map getTVBName tvb-                  _                             -> error "impossible case in reifyTypeParameters"+                  _                             -> traceM "impossible case in reifyTypeParameters" >> error ""                data DecTyType = Data | Newtype | TypeSyn | BuiltIn deriving (Show, Enum, Eq) @@ -277,9 +279,9 @@               DataD _ _ _ _ _ _   -> return Data               NewtypeD _ _ _ _ _ _ -> return Newtype               TySynD _ _ _ -> return TypeSyn-              _ -> error $ "not a type declaration: " ++ show name+              _ -> traceM ("not a type declaration: " ++ show name) >> (error "")            PrimTyConI _ _ _ -> return BuiltIn-           _ ->  error $ "not a type declaration: " ++ show name +           _ ->  traceM ("not a type declaration: " ++ show name ) >> (error "")   getTypeNames :: Type -> [Name]
src/Data/Derive/TopDown/Standalone.hs view
@@ -18,88 +18,32 @@    , derivings    , derivingss    , deriving_with+   , deriving_debug+   , deriving_with_breaks_debug+   , derivings_debug+   , derivingss_debug+   , deriving_with_debug #if __GLASGOW_HASKELL__ >= 802    , strategy_deriving    , strategy_derivings    , strategy_derivingss+   , strategy_deriving_debug+   , strategy_derivings_debug+   , strategy_derivingss_debug #endif ) - where -import Data.Derive.TopDown.Lib import Data.Derive.TopDown.CxtGen (genInferredContext) import Language.Haskell.TH-import Control.Monad-import Control.Monad.Trans import Control.Monad.State-import Data.Derive.TopDown.IsInstance import Data.Derive.TopDown.Types-import Data.List (foldl1')-import Data.Primitive.Types-import GHC.Generics---reset_strategy :: TypeName -> Maybe DerivStrategy -> Q (Maybe DerivStrategy)-reset_strategy tn st = do-        declareType <- decType tn-        case (declareType, st) of-          (_, Nothing) -> return Nothing-          (Data, Just NewtypeStrategy) -> return Nothing-          _ -> return st--gen_standalone_deriving_decl :: ClassName-                          -> TypeName-                          -> Maybe DerivStrategy  -                          -> [TypeName]  -- ^ a list of types that breaks the generation process-                          -> ContextGenerator -- ^ a context generator-                          -> StateT [Type] Q [Dec]-gen_standalone_deriving_decl cn tn st breaks cg = do-                       (tvbs, cons) <- lift $ getTyVarCons tn-                       let typeNames = map getTVBName tvbs-                       isCnHighOrderClass <- lift $ isHigherOrderClass cn-                       -- prevent calling isInstance class with * -> * and type with *-                       if isCnHighOrderClass && null typeNames-                        then return []-                        else do-                           saturatedType <- lift $ foldl1' appT (conT tn : map varT typeNames)-                           instanceType <- if isCnHighOrderClass && (not . null) typeNames-                                                then let pns = init typeNames-                                                      in  if null pns-                                                            then lift $ conT tn-                                                            else lift $ foldl1' appT (conT tn : (map varT pns))-                                                else return saturatedType-                           -- Stop generating further instances-                           -- 1. it is already a member of that type class-                           -- 2. we have already generated it, which is kind of same with case 1-                           -- 3. for GHC.Generic, if it is a primitive type like Int, Double-                           -- 4. It will stop on the types in breaks-                           -- 5. It will stop on primitive types and Integer when deriving Typeable-                           isMember <- lift $ isInstance' cn [instanceType]-                           isPrimitive <-lift $ isInstance' ''Prim [saturatedType]-                           let isGeneric = ''Generic == cn-                           let isGeneric1 = ''Generic1 == cn-                           table <- get-                           if isMember || elem instanceType table || elem tn breaks ||-                              (isPrimitive && (isGeneric || isGeneric1)) || -                              (tn == ''Integer && (isGeneric || isGeneric1))-                              then return []-                              else do-                                 classContext <- if isCnHighOrderClass -                                                   then return []-                                                   else lift $ cg  cn tn-                                 s <- lift $ reset_strategy tn st-                                 let decl = [StandaloneDerivD s classContext (AppT (ConT cn) instanceType)]-                                 modify (instanceType:)-                                 names <- lift $ fmap concat $ mapM getCompositeTypeNames cons-                                 names' <- lift $ filterM (\x -> isTypeFamily x >>= \b -> return $ not b) names-                                 xs <- mapM (\n -> gen_standalone_deriving_decl cn n st breaks cg) names'-                                 return $ concat xs ++ decl+import Data.Derive.TopDown.StandaloneDecGen  deriving_ :: Name -- ^ class name           -> Name -- ^ type name           -> Q [Dec]-deriving_ cn tn = evalStateT (gen_standalone_deriving_decl cn tn Nothing [] genInferredContext) []+deriving_ cn tn = evalStateT (gen_standalone_deriving_decl cn tn Nothing [] genInferredContext False) []  {- | This is particularly useful with 'Generic' class. @@ -115,7 +59,7 @@           -> Name -- ^ type name           -> [Name] -- ^ type names that stop the deriving process           -> Q [Dec]-deriving_with_breaks cn tn bs = evalStateT (gen_standalone_deriving_decl cn tn Nothing bs genInferredContext) []+deriving_with_breaks cn tn bs = evalStateT (gen_standalone_deriving_decl cn tn Nothing bs genInferredContext False) []  derivings :: [Name] -- ^ class names           -> Name   -- ^ type name@@ -134,7 +78,7 @@                   -> Name                   -> Q [Dec] -strategy_deriving st cn tn = evalStateT (gen_standalone_deriving_decl cn tn (Just st) [] genInferredContext) []+strategy_deriving st cn tn = evalStateT (gen_standalone_deriving_decl cn tn (Just st) [] genInferredContext False) []  strategy_derivings :: DerivStrategy                    -> [Name]@@ -171,4 +115,83 @@               -> [TypeName]        -- ^ a list of types that breaks the generation process               -> ContextGenerator -- ^ a context generator,  @genInferredContext@, @genHoleContext@ or @genAllFieldsContext@               -> Q [Dec]-deriving_with cn tn st bs cg = evalStateT (gen_standalone_deriving_decl cn tn st bs cg) []+deriving_with cn tn st bs cg = evalStateT (gen_standalone_deriving_decl cn tn st bs cg False) []++++deriving_debug :: Name -- ^ class name+          -> Name -- ^ type name+          -> Q [Dec]+deriving_debug cn tn = evalStateT (gen_standalone_deriving_decl cn tn Nothing [] genInferredContext True) []++{- | This is particularly useful with 'Generic' class.++For the types like 'Int', 'Char','Ratio' or other types which are not 'Generic', there must be a way to stop the generation process on those types.++However, the deriving topdown function will only stop generating 'Generic' instances on primitive types and 'Integer' by default, so you do not need to break on them manually.++Another circumtances might be deriving for 'Typeable' class. Since there is a bug in GHC, isInstance function in TH library is not working on 'Typeable', you can manually give the types which are already instances of 'Typeable' to stop the generation process.++For others cases, there is no need to use this function, bacause for a data type @A@ which is composited by another type, when you manually write an instance declaration for @A@, the process will stop on @A@ automatically since it is already an instance of the type class.+-}+deriving_with_breaks_debug :: Name -- ^ class name+          -> Name -- ^ type name+          -> [Name] -- ^ type names that stop the deriving process+          -> Q [Dec]+deriving_with_breaks_debug cn tn bs = evalStateT (gen_standalone_deriving_decl cn tn Nothing bs genInferredContext True) []++derivings_debug :: [Name] -- ^ class names+          -> Name   -- ^ type name+          -> Q [Dec]+derivings_debug cns tn = fmap concat (mapM (\x -> deriving_ x tn) cns)++derivingss_debug :: [Name] -- ^ class names+           -> [Name] -- ^ type names+           -> Q [Dec]+derivingss_debug cns tns = fmap concat (mapM (\x -> derivings cns x) tns)+++#if __GLASGOW_HASKELL__ >= 802+strategy_deriving_debug :: DerivStrategy+                  -> Name+                  -> Name+                  -> Q [Dec]++strategy_deriving_debug st cn tn = evalStateT (gen_standalone_deriving_decl cn tn (Just st) [] genInferredContext True) []++strategy_derivings_debug :: DerivStrategy+                   -> [Name]+                   -> Name+                   -> Q [Dec]++strategy_derivings_debug st cns tn = fmap concat $ (mapM (\x -> strategy_deriving st x tn) cns)++strategy_derivingss_debug :: DerivStrategy+                    -> [Name]+                    -> [Name]+                    -> Q [Dec]+strategy_derivingss_debug st cns tns = fmap concat $ (mapM (\x -> strategy_derivings st cns x) tns)+#endif++{-| Context generator be the following 3 functions++ 1. @genHoleContext@: It requires PartialTypeSignatures to make the context of deriving+    context a `hole' e.g. @_ => Cls (D a b)@. This case cannot handle type family+    since GHC cannot handle it++ 2. @genInferredContext@: It will try to infer the context including cases with type families.++ 3. @genAllFieldsContext@: It will put all fields into the context. It may generate like the followings++ @+ data List a = Nil | Cons a (List a)+ deriving instance (Show a, Show (List a)) => Show (List a)+ @+-}+deriving_with_debug :: ClassName+              -> TypeName+              -> Maybe DerivStrategy -- ^ deriving strategy+              -> [TypeName]        -- ^ a list of types that breaks the generation process+              -> ContextGenerator -- ^ a context generator,  @genInferredContext@, @genHoleContext@ or @genAllFieldsContext@+              -> Q [Dec]+deriving_with_debug cn tn st bs cg = evalStateT (gen_standalone_deriving_decl cn tn st bs cg True) []
+ src/Data/Derive/TopDown/StandaloneDecGen.hs view
@@ -0,0 +1,97 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Derive.TopDown.DecGen+-- Copyright   :  (c) Song Zhang+-- License     :  BSD-style (see the LICENSE file)+-- +-- Maintainer  :  haskell.zhang.song `at` hotmail.com+-- Stability   :  experimental+-- Portability :  non-portable+--+-----------------------------------------------------------------------------++module Data.Derive.TopDown.StandaloneDecGen (+    gen_standalone_deriving_decl+)+where++import Data.Derive.TopDown.Lib+import Language.Haskell.TH+import Control.Monad+import Control.Monad.Trans+import Control.Monad.State+import Data.Derive.TopDown.IsInstance+import Data.Derive.TopDown.Types+import Data.List (foldl1')+import Data.Primitive.Types+import GHC.Generics+import Debug.Trace++reset_strategy :: TypeName -> Maybe DerivStrategy -> Q (Maybe DerivStrategy)+reset_strategy tn st = do+        declareType <- decType tn+        case (declareType, st) of+          (_, Nothing) -> return Nothing+          (Data, Just NewtypeStrategy) -> return Nothing+          _ -> return st++type Debug = Bool++gen_standalone_deriving_decl :: ClassName+                             -> TypeName+                             -> Maybe DerivStrategy  +                             -> [TypeName]  -- ^ a list of types that breaks the generation process+                             -> ContextGenerator -- ^ a context generator+                             -> Debug+                             -> StateT [Type] Q [Dec]+gen_standalone_deriving_decl cn tn st breaks cg debug = do+                       when debug $ do+                           traceM $ "standalone_deriving_decl: `" +                              ++ show tn ++ "\' for class `"  ++ show cn ++ "\'"+                       (tvbs, cons) <- lift $ getTyVarCons tn+                       let typeNames = map getTVBName tvbs+                       isCnHighOrderClass <- lift $ isHigherOrderClass cn+                       -- prevent calling isInstance class with * -> * and type with *+                       if isCnHighOrderClass && null typeNames+                        then return []+                        else do+                           saturatedType <- lift $ foldl1' appT (conT tn : map varT typeNames)+                           instanceType <- if isCnHighOrderClass && (not . null) typeNames+                                                then let pns = init typeNames+                                                      in  if null pns+                                                            then lift $ conT tn+                                                            else lift $ foldl1' appT (conT tn : (map varT pns))+                                                else return saturatedType+                           -- Stop generating further instances+                           -- 1. it is already a member of that type class+                           -- 2. we have already generated it, which is kind of same with case 1+                           -- 3. for GHC.Generic, if it is a primitive type like Int, Double+                           -- 4. It will stop on the types in breaks+                           -- 5. It will stop on primitive types and Integer when deriving Typeable+                           isMember <- lift $ isInstance' cn [instanceType]+                           when debug $ do+                              traceM $ "standalone_deriving_decl: `" ++ show tn +                                       ++ "\' is instance of `" ++ show cn ++ "\':"+                                       ++ show isMember+                           isPrimitive <-lift $ isInstance' ''Prim [saturatedType]+                           let isGeneric = ''Generic == cn+                           let isGeneric1 = ''Generic1 == cn+                           table <- get+                           if isMember || elem instanceType table || elem tn breaks ||+                              isPrimitive || (tn == ''Integer && (isGeneric || isGeneric1))+                              then return []+                              else do+                                 classContext <- if isCnHighOrderClass +                                                   then return []+                                                   else lift $ cg  cn tn+                                 when debug $ do+                                    traceM $ "standalone_deriving_decl: `"+                                             ++ show tn ++ "\' context is " +                                             ++ pprint classContext+                                 s <- lift $ reset_strategy tn st+                                 let decl = [StandaloneDerivD s classContext (AppT (ConT cn) instanceType)]+                                 modify (instanceType:)+                                 names <- lift $ fmap concat $ mapM getCompositeTypeNames cons+                                 names' <- lift $ filterM (\x -> isTypeFamily x >>= \b -> return $ not b) names+                                 xs <- mapM (\n -> gen_standalone_deriving_decl cn n st breaks cg debug) names'+                                 return $ concat xs ++ decl
src/Data/Derive/TopDown/TH.hs view
@@ -54,7 +54,7 @@       return $ concat decls ++ decl  deriving_th-  :: (Name, Name -> Q [Dec]) -- ^ class name and corresponding instance generation function+  :: (Name, Name -> Q [Dec]) -- ^ class name and corresponding isntance generation function   -> Name -- ^ type name   -> Q [Dec] deriving_th cd tname = evalStateT (genTH cd tname []) []
test/Derive.hs view
@@ -6,10 +6,16 @@ import           Data.Derive.TopDown.IsInstance import           Language.Haskell.TH     hiding ( Exp ) import           Test.HUnit+import           Arity import           Types import           Utils import qualified "haskell-src"  Language.Haskell.Syntax as H+import qualified "haskell-src-exts" Language.Haskell.Exts.Syntax as Hs+import GHC.Core.Opt.Arity (typeArity)+import Test.HUnit (Test(TestCase))+import qualified Language.Haskell.Exts as Hs + eqPerson = TestCase   (assertEqual "Person is instance of Eq"                True@@ -186,4 +192,16 @@   (assertEqual "HsModule is instance of Ord"                True                $((qBoolToExp $ isInstance' ''Ord [apps [ConT ''H.HsDecl]]))+  )++typeArityHsModule = TestCase+  (assertEqual "type arity of HsModule is 1"+               True+               $((qBoolToExp $ isInstance' ''TypeArity [apps [ConT ''Hs.ModuleHead]]))+  )++typeArityHsName = TestCase+  (assertEqual "HsName is instance of TypeArity"+               True+               $((qBoolToExp $ isInstance' ''TypeArity [apps [ConT ''Hs.Name]]))   )
test/GhcAst.hs view
@@ -8,10 +8,11 @@ {-# LANGUAGE DeriveGeneric #-}  module GhcAst where++#if __GLASGOW_HASKELL__ >= 906 import qualified Data.Maybe as Maybe-import qualified "ghc" Language.Haskell.Syntax as G import           Data.Derive.TopDown-#if __GLASGOW_HASKELL__ >= 906+import qualified "ghc" Language.Haskell.Syntax as G import Language.Haskell.Syntax.Module.Name import Language.Haskell.Syntax.ImpExp import GHC.Types.SrcLoc@@ -19,14 +20,16 @@ import Language.Haskell.Syntax.Decls import Language.Haskell.Syntax.Type import GHC.Types.Var+#if __GLASGOW_HASKELL__ <= 908 import Language.Haskell.Syntax.Concrete+#endif import GHC.Data.FastString import Language.Haskell.Syntax.Expr import GHC.Types.Name.Reader import GHC.Unit.Types import GHC.Types.Name import GHC.Core.TyCo.Rep-import qualified GHC.Core.TyCon as GCT+import GHC.Core.TyCon  import GHC.Types.Unique import Language.Haskell.Syntax.Basic import GHC.Types.ForeignCall@@ -52,13 +55,12 @@ import GHC.ForeignPtr import Data.ByteString.Internal - $(deriving_with ''Generic ''G.HsModule Maybe.Nothing [     ''ShortByteString,      ''ForeignPtr,     ''Array,     ''Var,-    ''GCT.TyCon,+    ''TyCon,     ''IORef,     ''STRef,     ''Bag,
test/GhcTest.hs view
@@ -3,16 +3,16 @@ {-# LANGUAGE CPP #-} module GhcTest where +import Test.HUnit+#if __GLASGOW_HASKELL__ >= 906 import GhcAst import Data.Derive.TopDown.IsInstance import GHC.Generics import qualified "ghc" Language.Haskell.Syntax as G import Utils import Language.Haskell.TH-import Test.HUnit import Types -#if __GLASGOW_HASKELL__ >= 906 genericGhcHsModule = TestCase   (assertEqual "GhcHsModule is instance of Generic"                True
test/Spec.hs view
@@ -119,6 +119,8 @@  ghcAst = TestList [genericGhcHsModule] +hsExt = TestList [typeArityHsModule, typeArityHsName]+ main :: IO () main = do   void $ runTestTT derive@@ -126,3 +128,4 @@   void $ runTestTT instances   void $ runTestTT templates   void $ runTestTT ghcAst+  void $ runTestTT hsExt
test/Types.hs view
@@ -21,7 +21,6 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE PackageImports #-} - module Types where import           Arity import           Control.Monad.IO.Class@@ -35,7 +34,7 @@                                                 , D                                                 ) import qualified "haskell-src"  Language.Haskell.Syntax as H-+import qualified "haskell-src-exts" Language.Haskell.Exts.Syntax as Hs -- types for testing  -- ^ simple cases@@ -254,12 +253,14 @@ $(deriving_ ''Functor ''P) $(deriving_ ''Generic1 ''P) $(deriving_th (''TypeArity, makeTypeArity) ''P)-#if __GLASGOW_HASKELL__ >= 804-$(deriving_with ''Binary ''E Nothing [] genHoleContext)-#else-$(deriving_with ''Binary ''E Nothing [] genInferredContext)-#endif +$(strategy_deriving anyclass ''Binary ''P)+-- #if __GLASGOW_HASKELL__ >= 804+-- $(deriving_with ''Binary ''E Nothing [] genHoleContext)+-- #else+-- $(deriving_with ''Binary ''E Nothing [] genInferredContext)+-- #endif+ -- $(instance_with ''Binary ''E  [] Nothing genHoleContext) -- GHC deriving does not work on ForallT  data C b = C (forall a. Show a => a) b | C2 Int b (Maybe Bool)@@ -289,3 +290,5 @@ $(instance_ ''Binary ''H.HsModule) $(deriving_th (''TypeArity, makeTypeArity) ''H.HsModule) +-- ModuleHead+$(deriving_th (''TypeArity, makeTypeArity) ''Hs.ModuleHead)