{-# LANGUAGE CPP #-}

-- See what names from the module being spliced are in scope to TH.
#define DBG_NAMES 0

-- These types come from arguments to the seqaidTH splice.
#define DBG_TYPES 0

-- XXX A bit later yet: This could be handled completely
-- automatically (without needing to depend on seqaid.config
-- "exclude:" field or something), with new seqaidpp-calls-TH
-- idea ... it can see whether "seqaid" is called anywhere
-- in a bind(ing group)'s RHS(s), and decide on exclusion
-- that way...
-------
-- XXX Later: This can now be handled gracefully by seqaidpp
-- but this has not yet been implemented...
-------
-- I'd love to be able to do this, but so far as I can see, we
-- don't get to look at the RHS's of Dec's using reify Name,
-- only get the types... (So user has to add an Exclude ANN
-- as well as their manual seqaidDispatch injection, to any
-- bind which would be excluded by this TH code on other grounds,
-- such as [at present] being polymorphic.)
--- #define EXCLUDE_MANUALLY_INSTRUMENTED 1

-- Now the norm (and the ONLY way I could find to make
-- seqaid blanket harnessing feasible).
#define INJECT_DUMMY_CLASS_AND_INSTANCE_TO_BLOCK_DEAD_CODE_ELIMINATION 1

-- We want this to be 0, but at present the plugin is broken unless it's 1.
#define EXCLUDE_POLYMORPHIC_TYPES 1
--- #define EXCLUDE_MULTIPARAM_TYPES 0

-- You'll need this for some kinds of debugging...
#define SHOW_CONSTRAINT 0

{-# LANGUAGE TemplateHaskell #-}

-- XXX Some sites where I'm using this, should be using TH API to
-- issue errors and warnings...
----
-- Helpful with code tracing.
{-# LANGUAGE BangPatterns #-}

-------------------------------------------------------------------------------

-- |
-- Module      :  Seqaid.TH
-- Copyright   :  (c) 2014, Andrew G. Seniuk
-- License     :  BSD-style (see the file LICENSE)
--
-- Maintainer  :  Andrew Seniuk <rasfar@gmail.com>
-- Stability   :  provisional
-- Portability :  GHC (TH)
--
-- Template Haskell parts of seqaid.
--
-- None of these splices needs to (or should) be called by the user.

  module Seqaid.TH (

    seqaidTH ,

    seqaidValidate ,

--  seqaidSOP ,

--  seqaidManTH ,

--  seqaidInstancesTH ,

    strInstancesTH ,

    bindsIncludedTH ,

#if TRY_INJECT_NOINLINE_ON_REQUESTED_BINDS
    noinlineTH ,
#endif

    module Seqaid.Runtime ,
    module Seqaid.Ann ,

  ) where

  import Language.Haskell.TH
  import Language.Haskell.TH.Syntax ( qLocation )
#if SEQAIDPP_TYPES
  -- actually we use it in both cases, if you want to still
  -- do the top-level RHS wrapping technique; but I'm headed
  -- towards more general type-based subexpression wrapping,
  -- now that the preprocessor has made that possible...
  --   Actually, I suppose TH could be fed a config file, too...
  -- Consider porting all the config-file oriented stuff there?
  -- seqaidpp would only handle injection of static content.
  -- But no, it won't work, we need to know the types in the prepro
  -- at least to create the "deriving instance" declarations.
  import Language.Haskell.TH.Module.Magic ( names )
#else
  import Language.Haskell.TH.Module.Magic ( names )
#endif

  import Data.Generics ( listify, everywhere, mkT )

#if SEQABLE_ONLY
  import Generics.SOP.Universe ( Generic )
#endif

#if NFDATAN_ONLY
  import Control.DeepSeq.Bounded ( NFDataN )
#else
  import Control.DeepSeq.Bounded ( NFDataP )
#endif

  import Seqaid.Runtime ( seqaidDispatch, SiteID )
--import Seqaid.Runtime ( seqaid_internal )
  import Seqaid.Ann

  import Data.Maybe
  import Data.Either
  import Data.List ( intercalate, nub, nubBy )
  import Control.Monad ( liftM, zipWithM, foldM )

#if 0
  import qualified GHC.Environment as GHC ( getFullArgs )
#endif

  -- For global Bool state, to indicate that a warning has already been issued.
  import Data.IORef
  import System.IO.Unsafe ( unsafePerformIO )

  -- Regex only used to beautify warning messages.
  import Text.Regex.PCRE
  import Data.Array ( (!) )
  import Data.Array ( indices )

  import Debug.Trace ( trace )

  import qualified Type as GHC ( Type )

-------------------------------------------------------------------------------

  firstWarningPassed :: IORef Bool
  firstWarningPassed = unsafePerformIO $ newIORef False

-------------------------------------------------------------------------------

  seqaidInstancesTH :: Q [Dec]
  seqaidInstancesTH = do
#if SEQABLE_ONLY
    is <- getInstances ''Generics.SOP.Universe.Generic
#else
#if NFDATAN_ONLY
    is <- getInstances ''NFDataN
#else
    is <- getInstances ''NFDataP
#endif
#endif
    dss <- instancesToSeqinjDecls is
    let ds = concat dss
    return ds

-------------------------------------------------------------------------------

  strInstancesTH :: Q [Dec]
  strInstancesTH = do
#if SEQABLE_ONLY
    is <- getInstances ''Generics.SOP.Universe.Generic
#else
#if NFDATAN_ONLY
    is <- getInstances ''NFDataN
#else
    is <- getInstances ''NFDataP
#endif
#endif
    ss <- instancesToTypeStrings is
#if 1
    exp <- [e| SeqaidAnnAvailableInstances ss |]
--  runIO $ putStrLn $ " :|: exp =\n" ++ pprint exp
    let pragma_decl = PragmaD (AnnP ModuleAnnotation exp)
    return [pragma_decl]
#else
-- > runQ [d| ss = [ "a", "bc" ] |]
-- [ValD (VarP ss_0) (NormalB (ListE [LitE (StringL "a"),LitE (StringL "bc")])) []]
    let lites = map (\x -> LitE (StringL x)) ss
    vp <- newName "seqaid_instance_strings"
    let dec = ValD (VarP vp) (NormalB (ListE lites)) []
    return [dec]
#endif

-------------------------------------------------------------------------------

  bindsIncludedTH :: [String] -> Q [Dec]
  bindsIncludedTH bns = do
    exp <- [e| SeqaidAnnBindsIncluded bns |]
--  runIO $ putStrLn $ " :|: exp =\n" ++ pprint exp
    let pragma_decl = PragmaD (AnnP ModuleAnnotation exp)
    return [pragma_decl]

-------------------------------------------------------------------------------

  -- (And this doesn't even require th-expand-syns.)
  seqaidValidate :: [Name] -> Q [Dec]
  seqaidValidate names = do
    infos' <- mapM reify names
    infos <- mapM seqaidValidate' infos'  -- but will it get forced?!?
                       -- also, this could be quite expensive in worst case!
--  runIO $! evaluate (force infos)  -- I'm doubtful of an instance...
-- No instance.
-- Maybe we'll get lucky and TH is strict in this part??...
    return []
   where
    seqaidValidate' :: Info -> Q Info
    seqaidValidate' t = do
      case t of
        TyConI (TySynD name tyVarBndrs typ) -> error $ "seqaidpp: type synonym in instances list (seqaid.config):\n        " ++ pprint name
--      TyConI (TySynD name tyVarBndrs typ) -> error $ "seqaidpp: type synonym in instances list (seqaid.config):\n" ++ pprint t
        _ -> return t

-------------------------------------------------------------------------------

-- Always takes the seqaidpp-provided Type list now, even if
-- it does nothing with them for some reason (eg. leaky FS=4).
#if 1 || SEQAIDPP_TYPES
#if 1
  -- XXX To do this, I'm injecting [q| |] quasis [?] as argument
  -- in the module being spliced. (Injection by seqaidpp.)
  -- ... XXX ... except that doesn't quite work, because
  -- [t| etc. are in the Q monad. So we need to inject a bit
  -- more TH (slippery slope!) -- or is it even possible?...
#if 1
  -- After: And even better haha! Well, this works in the
  -- standalone test, so hang on...
  seqaidTH :: [Q Type] -> Q [Dec]
  seqaidTH types_actions = do
#else
  seqaidTH :: [Type] -> Q [Dec]
  seqaidTH types = do
#endif
#else
  seqaidTH :: [String] -> Q [Dec]
  seqaidTH type_strs = do
#endif
#else
  seqaidTH :: Q [Dec]
  seqaidTH = do
#endif
#if SEQAIDPP_TYPES
    types <- mapM runQ types_actions
#else
    let types = []
#endif
    modname <- fmap loc_module qLocation
    runIO $ putStrLn $ "Included in seqaid harness: " ++ modname
--  runIO $ putStrLn $ "Included in seqaid harness: " ++ dropQuals modname
    do
#if 0
    fullargs <- runIO $ GHC.getFullArgs
--  runIO $ putStrLn $ intercalate "\n" fullargs
--  error "STOP"
{-
-fplugin=Seqaid.Plugin
-fplugin-opt=Seqaid.Plugin:S03
-}
--  runIO $ putStrLn $ show modname
--  error "STOP"
--  modname <- fmap loc_module qLocation >>= \mod -> return (LitE (StringL mod))
--  Module pkgname modname <- reifyModule thisModule
  -- This prevents splicing anything in, unless the plugin is active,
  -- in in particular, is active for the module we're compiling.
    if not $    elem "-fplugin=Seqaid.Plugin" fullargs
             && elem ("-fplugin-opt=Seqaid.Plugin:" ++ modname) fullargs
    then return []
    else do
#endif

#if 1 || SEQAIDPP_TYPES
#if 0
#if 0
     Just types_name <- lookupValueName "seqaid_types"
     types <- reify types_name
--   types <- [d| seqaid_types |]
#endif
     types <- mapM (liftM fromJust . lookupTypeName) type_strs
#else
     let type_strs = map pprint types
#endif
#endif

-- XXX We would like to pass [Type.Type] in the SeqaidAnnTypes ANN.
-- What I can't figure out is how to get Type.Type from TH.Type.
#if 1 || SEQAIDPP_TYPES
#if TH_TYPE_IN_TYPES_ANN
-- I whish this had worked out, but I don't see how to do it...
#if 0
#elif 1
     ghc_types <- $(types)
     sats_exp <- [e| SeqaidAnnTypes ghc_types |]
#elif 0
     sats_exp <- [e| SeqaidAnnTypes $(types) |]
#elif 0
     let ghc_types = map (\x -> $(x)) types
     sats_exp <- [e| SeqaidAnnTypes ghc_types |]
#endif
#else
     sats_exp <- [e| SeqaidAnnTypes type_strs |]
#endif
#if DBG_TYPES
     runIO $ putStrLn $ " :|: sats_exp =\n" ++ pprint sats_exp
#endif
     let sats_pragma_decl = PragmaD (AnnP ModuleAnnotation sats_exp)
#endif

-- XXX Trying to still use the IncludeList, even for blanket
-- by-types wrapping in Core, since want to be able to distinguish
-- synthetic and original binds.
#if INFER_TOP_LEVEL_TYPES
     ns <- names :: Q [Name]
--makeNameType :: Either Name Type -> Q (Either Name (Maybe Name,Type))
     ents_names <- mapM ( makeNameType . (\x->Left x) ) ns :: Q [Either Name (Maybe Name,Type)]
--   ents_names <- mapM makeNameType ns  -- :: Q [Either Name (Name,Type)]
#if DBG_NAMES
     runIO $ putStrLn $ "Top-level names in scope:\n" ++ show ns
#endif
#else
     let ents_names = []
#endif

#if SEQAIDPP_TYPES
     -- This is returning Left's, but should be Right (Nothing,ty):
     ents_types <- mapM ( makeNameType_types . (\x->Right x) ) types :: Q [Either Name (Maybe Name,Type)]
#else
     let ents_types = []
#endif

#if DBG_TYPES
     runIO $ putStrLn $ " !! length ents_names=" ++ (show $ length ents_names)
     runIO $ putStrLn $ " !! length ents_types=" ++ (show $ length ents_types)
#endif

     let ents = ents_names ++ ents_types

#if DBG_TYPES || DBG_NAMES
     runIO $ putStrLn $ show ents
#endif
     let nts = rights ents

     if null nts
     then do
#if DBG_NAMES
      runIO $ putStrLn $ "modulespection:names = []"
#endif
      return []
     else do
#if DBG_NAMES
      let ss = map (\ (n,t) -> pprint n ++ " :: " ++ pprint t) nts :: [String]
--    let ss = map pprint ns :: [String]
      let ss' = intercalate "\n  " ss
      runIO $ putStrLn $ "modulespection:names = \n  " ++ ss'
--    reportWarning ss'
#endif
      sidtyp <- [t| SiteID |]
      ([ann]:dss') <- manifestSeqinjDecls sidtyp nts
--    runIO $ putStrLn $ show $ map length dss'
      let dss = dss'
--    let dss = map reverse dss'
#if INJECT_DUMMY_CLASS_AND_INSTANCE_TO_BLOCK_DEAD_CODE_ELIMINATION
      (clsd:instd:[]) <- manifestDummyClassAndInstance sidtyp dss
#endif

--    error "STOP"

      -- Pattern of decls is: Anns, TypeSig, Binding, TypeSig, Binding, ...
#if SEQAIDPP_TYPES
      let ds = sats_pragma_decl : ann : clsd : instd : reverse (concat $ map reverse dss)
#else
#if INJECT_DUMMY_CLASS_AND_INSTANCE_TO_BLOCK_DEAD_CODE_ELIMINATION
      let ds = ann : clsd : instd : reverse (concat $ map reverse dss)
#else
      let ds = ann : reverse (concat $ map reverse dss)
#endif
#endif

      return ds

-------------------------------------------------------------------------------

  instancesToSeqinjDecls :: [InstanceDec] -> Q [[Dec]]
  instancesToSeqinjDecls ids = zipWithM instancesToSeqinjDecl' [0,1..] ids
   where
    instancesToSeqinjDecl' :: Int -> InstanceDec -> Q [Dec]
    instancesToSeqinjDecl' idx (InstanceD ctx t ds) = do
     let (AppT _ t2) = t  -- (AppT (AppT ArrowT t2) t2)
     (seqinj_dec:_) <- [d| seqinj = seqaidDispatch :: () -> () |]  -- inefficient
--   (seqinj_dec:_) <- [d| seqinj = forcep "#" :: () -> () |]  -- inefficient
     let (ValD (VarP vp1) (NormalB (SigE ae1 (AppT (AppT ArrowT _) _))) [])
          = seqinj_dec
#if 0
     let vp1' = vp1
#else
     let vp1s = show vp1
     let (vp1s1,vp1s2) = break (=='_') vp1s
     let vp1s' = "seqinjinst_" ++ show idx
--   let vp1s' = "seqinjinst" ++ vp1s2
     vp1' <- newName vp1s'
--   let vp1' = mkName vp1s'
#endif
-- > runQ [d| seqinj_blah = forcep "#" |]
-- [ValD (VarP seqinj_blah_0) (NormalB (AppE (VarE Control.DeepSeq.Bounded.NFDataP.forcep) (LitE (StringL "#")))) []]
--  vs.
-- > runQ [d| seqinj_blah = forcep "#" :: Float -> Float |]
-- [ValD (VarP seqinj_blah_1) (NormalB (SigE (AppE (VarE Control.DeepSeq.Bounded.NFDataP.forcep) (LitE (StringL "#"))) (AppT (AppT ArrowT (ConT GHC.Types.Float)) (ConT GHC.Types.Float)))) []]
     let free_tvars_t2 = getFreeTVars t2
     let bind_tvars_t2 = map bindTVars free_tvars_t2
     let ctx2 = make_ctx Nothing free_tvars_t2 ctx
--   ForallT [TyVarBndr] Cxt Type
     let seqinj_tdec
          = SigD vp1' (ForallT bind_tvars_t2 ctx2 (AppT (AppT ArrowT t2) t2))
--        = SigD vp1' (ForallT free_tvars_t2 [] (AppT (AppT ArrowT t2) t2))
--        = SigD vp1' (AppT (AppT ArrowT t2) t2)
--   seqinj_tdec <- [d| $(vp1') :: $(t2) -> $(t2) |]
     let seqinj_fdec
          = (ValD (VarP vp1') (NormalB       ae1                            ) [])
--        = (ValD (VarP vp1') (NormalB       ae1                            ) [])
--        = (ValD (VarP vp1') (NormalB (SigE ae1 (AppT (AppT ArrowT t2) t2))) [])
--   return [seqinj_tdec]
     return [seqinj_tdec, seqinj_fdec]
--   return (seqinj_tdec, seqinj_fdec)

-------------------------------------------------------------------------------

  -- (Cloned from [ancient] instancesToSeqinjDecls. Probably doesn't
  -- need the zipping with unique Int's.)
  instancesToTypeStrings :: [InstanceDec] -> Q [String]
  instancesToTypeStrings ids = zipWithM instancesToTypeString' [0,1..] ids
   where
    instancesToTypeString' :: Int -> InstanceDec -> Q String
    instancesToTypeString' idx (InstanceD ctx t ds) = do
     let (AppT _ t2) = t  -- (AppT (AppT ArrowT t2) t2)
     return $ pprint t
---  -- (AppT (AppT ArrowT SiteID) (AppT (AppT ArrowT t2) t2))
---  let (AppT _ (AppT _ t2)) = t

-------------------------------------------------------------------------------

  bindTVars :: Type -> TyVarBndr  -- specifically, VarT ->
  bindTVars (VarT name) = PlainTV name
  bindTVars _ = error "bindTVars: unexpected!"

-------------------------------------------------------------------------------

  getFreeTVars :: Type -> [Type]  -- specifically, -> [VarT]
  getFreeTVars t = listify f t
   where
    f :: Type -> Bool
    f x@(VarT name) = True
    f x = False

-------------------------------------------------------------------------------

  -- Thanks to John L. in http://stackoverflow.com/a/5398910
  -- This was my introduction to TH.

  -- get a list of instances
  getInstances :: Name -> Q [InstanceDec]
--getInstances :: Name -> Q [ClassInstance]
  getInstances typ = do
    ClassI _ instances <- reify typ
    return instances

#if 0
  -- convert the list of instances into an Exp so they can be displayed in GHCi
  showInstances :: Name -> Q Exp
  showInstances typ = do
    ins <- getInstances typ
    return . LitE . stringL $ show ins
#endif

-------------------------------------------------------------------------------

-- XXX Okay, I've run into trouble already here.
-- Between Type and Name (and String).
-- We want the **Type** Types.TA (from the String "Types.TA").
-- But if reify . loopupTypeName, you get (which is cool and nice;
-- and is due to the fact that the types are imported) the full
-- declarations:
--   data Types.TA
--    = Types.A1 GHC.Types.Int | Types.A2 Types.TB GHC.Types.Int Types.TC
--   type Types.State = Types.TA
-- So I guess I could pattern-match on these and other type constructors,
-- and extract the types from it directly.  But can we not just avoid it???
--   lookupTypeName :: String -> Maybe Name
--   reify :: Name -> Decl
--   Name -> Q Info with VarI (eg. a function binding), TyConI (what
-- we are getting at present), ...
--   But can't we just say the equivalent of "typeOf Name"?
-------
-- XXX Decided to clone this (and decruft the copy, as usual),
-- since the type case has more than a few differences...

--makeNameType :: Either Name Name -> Q (Either Name (Maybe Name,Type))
  makeNameType :: Either Name Type -> Q (Either Name (Maybe Name,Type))
--makeNameType :: Either Name Type -> Q (Either Name (Name,Type))
--makeNameType :: Either Name Type -> Q (Maybe (Name,Type))

  makeNameType (Right _) = error "makeNameType: Right unexpected!"
  makeNameType enm@(Left nm) = do
   modname <- fmap loc_module qLocation
#if 0
   !_ <- trace ("nm="++pprint nm++" modname="++modname) $ return ()
   if False && takeQuals (pprint nm) /= modname
   then do
     !_ <- trace "HERE-1" $ return ()
     return $ Left nm
-- then return $ Left nm
   else do
#else
   do
#endif
--  Just nm <- lookupValueName nm_string
{-
data TH.Info =
 ClassI Dec [InstanceDec]
 ClassOpI Name Type ParentName Fixity
 TyConI Dec
 FamilyI Dec [InstanceDec]
 PrimTyConI Name Arity Unlifted
 DataConI Name Type ParentName Fixity
 VarI Name Type (Maybe Dec) Fixity
-}
#if 1
--- !_ <- trace "HERE-2" $ return ()
    rnm <- reify nm
--- !_ <- trace ("<><><><> " ++ pprint rnm) $ return ()
    let mnmt
         = case rnm of
-- XXX You might think it would be better to just OMIT all but VarI
-- types (gracefully) -- which I should have tried already, and will
-- certainly try in a moment ... But, probably, you'll NEED to deal
-- with things like DataConI's, since the associated types will
-- have to be in scope ... or ... no?...
              VarI nm_ t_ mdec_ fxty_ ->
                if takeQuals (show nm_) /= modname
                then Nothing
                else Just (nm_,t_)
#if 0
              -- XXX can probably scrounge a Name up in the 3 unimplemented ones
--            ClassI dec_ ideclst_ -> error "makeNameType: ClassI unimplemented"
              ClassOpI nm_ t_ parentnm_ fxty_ ->
                if takeQuals (show nm_) /= modname
                then Nothing else Just (nm_,t_)
--            TyConI dec_ -> error "makeNameType: TyConI unimplemented"
--            FamilyI dec_ ideclst_ -> error "makeNameType: FamilyI unimplemented"
--            PrimTyConI nm_ arty_ unlifted_ -> error "makeNameType: PrimTyConI unimplemented"
              DataConI nm_ t_ parentnm_ fxty_ ->
                if takeQuals (show nm_) /= modname
                then Nothing else Just (nm_,t_)
              _ -> Nothing
#else
              _ -> Nothing
#endif
#else
    rnm@(VarI nm_ t_ mdec_ fxty_) <- reify nm
#endif
    if isNothing mnmt
    then do
      return $ Left nm
--    return $ Nothing
    else do
      let Just (nm_,t_) = mnmt
#if 0
      let snm_ = pprint nm_
      let st_ = pprint t_
      runIO $ putStrLn $ " ********* " ++ snm_ ++ "  " ++ st_
#endif
      return $ Right (Just nm_,t_)
--    return $ Just (nm_,t_)

-------------------------------------------------------------------------------

--makeNameType_types :: Either Name Name -> Q (Either Name (Maybe Name,Type))
  makeNameType_types :: Either Name Type -> Q (Either Name (Maybe Name,Type))
--makeNameType_types :: Either Name Type -> Q (Either Name (Name,Type))
--makeNameType_types :: Either Name Type -> Q (Maybe (Name,Type))

  makeNameType_types (Left _) = error "makeNameType_types: Left unexpected!"

#if 1

  makeNameType_types enm@(Right typaboo) = do
    return $ Right (Nothing,typaboo)

#else

  makeNameType_types enm@(Right nm) = do
    modname <- fmap loc_module qLocation
--- !_ <- trace "HERE-2" $ return ()
    rnm <- reify nm
    !_ <- trace ("<><><><> " ++ pprint rnm) $ return ()
    let mnmt
         = case rnm of
              VarI nm_ t_ mdec_ fxty_ -> error "makeNameType_types: VarI unexpected!"
--            ClassI dec_ ideclst_ -> error "makeNameType_types: ClassI unimplemented"
---           TyConI dec_ -> error "makeNameType_types: TyConI unimplemented"
--            FamilyI dec_ ideclst_ -> error "makeNameType_types: FamilyI unimplemented"
--            PrimTyConI nm_ arty_ unlifted_ -> error "makeNameType_types: PrimTyConI unimplemented"
--            DataConI nm_ t_ parentnm_ fxty_ -> error "makeNameType_types: DataConI unimplemented"
-- DataD Cxt Name [TyVarBndr] [Con] [Name]
-- NewtypeD Cxt Name [TyVarBndr] Con [Name]
-- TySynD Name [TyVarBndr] Type

... unfinished ...

              TyConI dec_ -> case dec_ of
                DataD cxt name tyvarbndrs cons name ->
                NewtypeD Cxt Name [TyVarBndr] Con [Name]
                TySynD Name [TyVarBndr] Type
              _ -> Nothing
    if isNothing mnmt
    then do
      return $ Left nm
--    return $ Nothing
    else do
      let Just (nm_,t_) = mnmt
#if 0
      let snm_ = pprint nm_
      let st_ = pprint t_
      runIO $ putStrLn $ " ********* " ++ snm_ ++ "  " ++ st_
#endif
      return $ Right (Just nm_,t_)
--    return $ Just (nm_,t_)

#endif

-------------------------------------------------------------------------------

  -- This is identical to produceSeqinjDecls, minus cruft,
  -- since wrote makeNameType instead...
  manifestSeqinjDecls :: Type -> [(Maybe Name,Type)] -> Q [[Dec]]
  manifestSeqinjDecls sidtyp nts = do

    mod <- thisModule
    modname <- fmap loc_module qLocation  -- really?? can't get this from mod?!

    reiannbad <- reifyAnnotations (AnnLookupModule mod) :: Q [SeqaidAnnIncludeList]
    if not $ null reiannbad
    then do
     error $ "seqaid: illegal SeqaidAnnIncludeList annotation"
    else do

     reiann <- reifyAnnotations (AnnLookupModule mod) :: Q [SeqaidAnnExclude]
--   runIO $ putStrLn $ "--------------\n" ++ show reiann ++ "---------\n"
--ValueAnnotation
     -- Collect existing ANN 's to initialise the lists of excluded name strings:
     let zlst' = map (\ (SeqaidAnnExclude s) -> s) reiann
     -- Make sure all the name strings fully-qualified:
     let zlst'' = map (\ s -> if elem '.' s then s else modname ++ ('.':s)) zlst'
     let zlst = zlst''

-- XXX I do confess I'm having a hard time following this...

     (injdecls,excorincnms) <- liftM fst $
       ( foldM
           ( \ y@((injdecls_, excorincnms_), yidx) x ->
               do
                  eideclst <- manifestSeqinjDecl' zlst yidx x
                  case eideclst of
                   Left nm -> return ((injdecls_, excorincnms_), yidx)
#if 1
                   Right d -> case fst x of
                               Nothing -> return ((d:injdecls_, excorincnms_), 1+yidx)
                               Just nm -> return ((d:injdecls_, nm:excorincnms_), 1+yidx)
#else
                   Right d -> let nm = fst x in
                              return ((d:injdecls_, nm:excorincnms_), 1+yidx)
#endif
           )
           (([],[]),0)
         :: [(Maybe Name,Type)] -> Q (([[Dec]],[Name]),Int) )  -- type up to here
---      :: [(Name,Type)] -> Q (([[Dec]],[Name]),Int) )  -- type up to here
           nts

--   runIO $ putStrLn $ " :|: injdecls =\n" ++ pprint injdecls
--   runIO $ putStrLn $ " :|: excorincnms =\n" ++ pprint excorincnms
--   error "STOP"

-- Get all the binds explicitly excluded by ANN pragmas already
-- present in the input source module:

-- Get all the binds excluded based on as-yet unsupported types:
--   let exp = LitE (StringL "Boo!")
     let ss = map pprint excorincnms

     let ss' = ss
--   let ss' = ss ++ zlst
--   runIO $ putStrLn $ " :|: ss' = " ++ intercalate "\n" ss'
--   runIO $ putStrLn $ " :|: zlst = " ++ intercalate "\n" zlst
--   runIO $ putStrLn $ " :|: ss = " ++ intercalate "\n" ss

     exp <- [e| SeqaidAnnIncludeList ss' |]
--   runIO $ putStrLn $ " :|: exp =\n" ++ pprint exp

     let pragma_decl = PragmaD (AnnP ModuleAnnotation exp)

     return ([pragma_decl] : injdecls)
--   manifestSeqinjDecls nts = liftM catMaybes $ zipWithM manifestSeqinjDecl' [0,1..] nts
   where
    manifestSeqinjDecl' :: [String] -> Int -> (Maybe Name,Type) -> Q (Either Name [Dec])
--  manifestSeqinjDecl' :: [String] -> Int -> (Name,Type) -> Q (Either Name [Dec])
    manifestSeqinjDecl' zlst idx (mnm,t) = do
#if 0
data Type = ForallT [TyVarBndr] Cxt Type --- <long comment elided>
          | AppT Type Type               --- @T a b@
          | SigT Type Kind               --- @t :: k@
          | VarT Name                    --- @a@
          | ConT Name                    --- @T@
          | PromotedT Name               --- @'T@
          -- See Note [Representing concrete syntax in types]
          | TupleT Int                   --- @(,), (,,), etc.@
          | UnboxedTupleT Int            --- @(#,#), (#,,#), etc.@
          | ArrowT                       --- @->@
          | ListT                        --- @[]@
          | PromotedTupleT Int           --- @'(), '(,), '(,,), etc.@
          | PromotedNilT                 --- @'[]@
          | PromotedConsT                --- @(':)@
          | StarT                        --- @*@
          | ConstraintT                  --- @Constraint@
          | LitT TyLit                   --- @0,1,2, etc.@
#endif
     let st = pprint t
     let nm = fromJust mnm
     let snm = pprint nm
#if 0
     runIO $ putStrLn $ "mnm = " ++ show mnm ++ "\nst = " ++ st
--   runIO $ putStrLn $ "snm = " ++ snm ++ "\nst = " ++ st
     runIO $ putStrLn $ "zlst = " ++ show zlst
--   error "HERE!"
#endif
     if isJust mnm && elem snm zlst
--   if elem snm zlst
     then do {- runIO (putStrLn "YAY!!!!!") >> -} return (Left nm)
     else do
#if ! EXCLUDE_POLYMORPHIC_TYPES
--- #if ! EXCLUDE_MULTIPARAM_TYPES
      let t2 = t
      do
#else
      mt2 <- case t of
              (ForallT _ _ _) -> do
               if isNothing mnm
               then return $ Just t
               else do
                firstwarnpassed <- runIO $ readIORef firstWarningPassed
                if firstwarnpassed
                then reportWarning $ "seqaid: omitting declaration from auto-harness:\n      " ++ snm ++ " :: " ++ beautify st ++ "\n    Polymorphic types not yet supported by the plugin."
                else reportWarning $ "seqaid: omitting declaration from auto-harness:\n      " ++ snm ++ " :: " ++ beautify st ++ "\n    Sorry, polymorphic types not yet supported by the plugin.\n    If you need this declaration to be included in the harness,\n    please manually instrument with \" seqaid $ \" at the front of the\n    RHS of its binding.  (For technical reasons, this warning will\n    still appear unless you also put\n      {-# ANN module (SeqaidAnnExclude \"" ++ dropQuals snm ++ "\") #-}\n    someplace in the same module; or just ignore the warning.)"
#if 0
                      ++ "  Pass seqaidDispatch a distinct, negative Int as\n    first argument.  (Negative keys are reserved for this eventuality.)"
#endif
                runIO $ modifyIORef' firstWarningPassed (const True)
                return Nothing
              _ -> return $ Just t
      if isNothing mt2 then return $ Left nm
      else do
       -- or is "resultType :: Type -> Type" in TH API?...
       let t2 = followArrows $ fromJust mt2  -- use result type
#endif
       (seqinj_dec:_) <- [d| seqinj = seqaidDispatch :: SiteID -> () -> () |]  -- inefficient
#if 0
       let (ValD (VarP vp1) (NormalB (SigE ae1 ( AppT (AppT ArrowT sidtyp) ( AppT (AppT ArrowT _) _))))) [])
            = seqinj_dec
#else
       let (ValD (VarP vp1) (NormalB (SigE ae1 (
                                                 AppT
                                                  (AppT ArrowT sidtyp)
                                                  ( AppT
                                                      (AppT ArrowT _)
                                                      _
                                                  )
                                               )
                                     )) [])
            = seqinj_dec
#endif
#if 0
                      ( AppT
                         (AppT ArrowT sidtyp)
                         ( AppT
                             (AppT ArrowT typ_)
                             typ_
                         )
                      )
#endif
       let vp1s = show vp1
       let (vp1s1,vp1s2) = break (=='_') vp1s
       let vp1s' = "seqinj_" ++ show idx
       vp1' <- newName vp1s'
#if 1
       t' <- {-trace "Boo-hoo" $-} makeSeqinjType Nothing sidtyp t2
       let seqinj_tdec = SigD vp1' t'
--     let seqinj_tdec = trace ("YES: "++show t') $ SigD vp1' t'
#else
       let seqinj_tdec
            = SigD vp1' (AppT (AppT ArrowT t2) t2)
#endif
-- > runQ [t| forall a. a -> a |]
-- ForallT [PlainTV a_2] [] (AppT (AppT ArrowT (VarT a_2)) (VarT a_2))
-- > runQ [t| forall a b. (a,b) -> (a,b) |]
-- ForallT [PlainTV a_0,PlainTV b_1] [] (AppT (AppT ArrowT (AppT (AppT (TupleT 2) (VarT a_0)) (VarT b_1))) (AppT (AppT (TupleT 2) (VarT a_0)) (VarT b_1)))
       let seqinj_fdec
            = ValD (VarP vp1') (NormalB ae1) []
       return $ Right [seqinj_tdec, seqinj_fdec]

-------------------------------------------------------------------------------

  -- Added this to correctly build a seqinj_[0-9]* type from
  -- a given forall type, also adding the necessary qualifiers:
  -- This is like the 3rd function cloned off of instancesToSeqinjDecl
  -- already, isn't it??  But this is the first to preserve (let alone
  -- focus on) the forall stuff...
  -- XXX This should be called from any places which are creating t -> t...
  -- XXX XXX XXX Forgot! Still need to make newName's -- the only
  -- type var Name that can be reused in here is Maybe Name argument...
  -- XXX Also, we are getting duplicate vars in our synthesised forall binders,
  -- simply need to nub.
-- XXX This is wretched at the moment:
--  When isNothing mn, assume tt is NOT yet in t -> t form, and do it.
--  When isJust mn, tt IS in t -> t form (but we have some other stuff to do).
  makeSeqinjType :: Maybe Name -> Type -> Type -> Q Type
  makeSeqinjType mn sidtyp tt@(ForallT tyvarbndr_lst ctx typ) = do
--   runIO $ putStrLn $ " >FORALL> " ++ pprint tt
     let n = fromJust mn
     let free_tvars_typ' = getFreeTVars typ
-- Next day: I don't like this approach; just send the class typevar
-- if there is one (Just vs. Nothing), but assure the rest of the
-- Type does not start with that var. The type arg should also
-- not yet have the duplication, obviously (i.e. t ==> (t -> t)) -- this
-- is part of the job of THIS function!
#if 1
     let free_tvars_typ = free_tvars_typ'
#else
     let free_tvars_typ
          | isNothing mb       = free_tvars_typ'
          | PlainTV n <- b     = filter (==(VarT n)) free_tvars_typ'
          | KindedTV n k <- b  = filter (==(VarT n)) free_tvars_typ'
#endif
#if 1
     let blah1 = map (\ (VarT n) -> show n) (free_tvars_typ :: [Type]) :: [String]
     let blah2 = nub blah1 :: [String]
     blah3 <- mapM newName (map (take 1) blah2) :: Q [Name]
--   blah3 <- mapM newName (take (length blah2) (repeat "a")) :: Q [Name]
--   blah3 <- mapM newName blah2 :: Q [Name]
     blah4 <- mapM (\ n -> return $ VarT n) blah3 :: Q [Type]
     let bind_tvars_typ = blah4
--   let new_tvars_typ = blah4
     let orig_tyvars = nub free_tvars_typ
     let fresh_tyvars = bind_tvars_typ
#else
     new_tvars_typ
      <- fmap (\ n -> return $ VarT n) $
         (( mapM newName $
         (( nub $
           (( map (\ (VarT n) -> show n) (free_tvars_typ :: [Type])) :: [String] ) ) :: [String] )
         :: Q [Name]))
--   new_tvars_typ <- mapM (\ n -> return $ VarT n) $ mapM newName $ nub $ map (\ (VarT n) -> show n) free_tvars_typ
#endif
     let binding = map bindTVars bind_tvars_typ
-- ForallT [TyVarBndr] Cxt Type
     let (AppT _ typ_) = typ  -- you can do this, but it does feel sloppy
                  -- to have pattern bindings which you know are inapplicable
                  -- except when those patterns arise (i.e. they should
                  -- be localised to branches of conditionals, except
                  -- conditional branching is such a pain with monads...
--   let (AppT (AppT ArrowT typ_) typ_) = typ
     let typ_' = substTyVars (orig_tyvars,fresh_tyvars) typ_
     let typ' | isNothing mn  -- it's not a class method signature
                  = let typ_ = substTyVars (orig_tyvars,fresh_tyvars) typ
                    in
                    ForallT
                      binding
                      (make_ctx (Just (orig_tyvars,fresh_tyvars)) bind_tvars_typ ctx)
                      ( {-trace "BOO-1" $-}
                      ( AppT
                         (AppT ArrowT sidtyp)
                         ( AppT
                             (AppT ArrowT typ_)
                             typ_
                         )
                      )
                      )
---                   (AppT (AppT ArrowT (AppT ArrowT sidtyp) typ_) typ_)
              | otherwise  -- then it's a class method signature
                  = let (AppT _ typ_) = typ
                        typ_' = substTyVars (orig_tyvars,fresh_tyvars) typ_
                    in
                    ForallT
                      binding
                      (make_ctx (Just (orig_tyvars,fresh_tyvars)) bind_tvars_typ ctx)
#if 0
                      (AppT (AppT ArrowT (VarT n))
                        (AppT (AppT ArrowT typ_') typ_')
                        )
#else
#if 0
                      ( trace "BOO-2" $
                      ( AppT
                         (AppT ArrowT (VarT n))
                         ( AppT
                             (AppT ArrowT sidtyp)
                             typ_'
                         )
                      )
                      )
#else
                      (AppT (AppT ArrowT (VarT n)) typ_')
#endif
#endif
     return typ'
  makeSeqinjType mn sidtyp tt@typ = do
     let n = fromJust mn
     let free_tvars_typ = getFreeTVars typ
     if null free_tvars_typ
     then do
--    runIO $ putStrLn $ " >OTHER:null> " ++ pprint tt
      let typ' | isNothing mn
               = ( AppT
                    (AppT ArrowT sidtyp)
                    ( AppT
                       (AppT ArrowT typ)
                       typ
                    )
                 )
               | otherwise
#if 0
               = AppT
                   (AppT ArrowT (VarT n))
                   (AppT (AppT ArrowT typ) typ)
#else
#if 0
-- > runQ [t| Int -> Bool -> Float |]
-- AppT (AppT ArrowT (ConT GHC.Types.Int)) (AppT (AppT ArrowT (ConT GHC.Types.Bool)) (ConT GHC.Types.Float))
-- > runQ [t| t1 -> t2 -> t3 |]  -- pseudo
-- AppT (AppT ArrowT t1) (AppT (AppT ArrowT t2) t3)
               = trace "BOO-3" $ ( AppT
                    (AppT ArrowT (VarT n))
                    ( AppT
                        (AppT ArrowT sidtyp)
                        typ
                    )
                 )
#else
               = (AppT (AppT ArrowT (VarT n)) typ)
#endif
#endif
      return typ'
     else do
#if 1
      error $ "makeSeqinjType: Nothing and free vars"
#else
      runIO $ putStrLn $ " >OTHER:non-null> " ++ pprint tt
      let bind_tvars_typ = map bindTVars free_tvars_typ
      let typ' = ForallT
                   bind_tvars_typ
                   (make_ctx (Just ([],[])) free_tvars_typ [])
                   (AppT (AppT ArrowT typ) typ)
      let typ' = AppT (AppT ArrowT typ) typ
      return typ'
#endif
--makeSeqinjType (Just n) tt@typ = do
--  error $ "makeSeqinjType: Just " ++ pprint n ++ " and typ not forall"

-------------------------------------------------------------------------------

  -- Humph, looks like I need SYB? I don't see utility functions
  -- for doing subsitutions inside general Type's.
  substTyVars :: ([Type],[Type]) -> Type -> Type
  substTyVars (orig,fresh) t = everywhere (mkT fg) t
   where
    fg :: Type -> Type
    fg (VarT n)
     | isNothing mfn  = error "substTyVars: lookup failed!"
     | otherwise      = VarT $ fromJust mfn
     where
      mfn = h n orig fresh
      h :: Name -> [Type] -> [Type] -> Maybe Name
      h n [] _ = Nothing
      h n ((VarT o):os) ((VarT f):fs)
-- XXX why am I never seeing this traceline?
       | n == o     = trace (show o ++ " ----->> " ++ show f) $ Just f
       | otherwise  = h n os fs
    fg x = {-trace (" %%% " ++ show x)-} x

-------------------------------------------------------------------------------

  make_ctx :: Maybe ([Type],[Type]) -> [Type] -> [Pred]-> [Pred]
  make_ctx mof free_tvars_typ ctx = ctx2
   where
    ctx2
     =    ctx'
#if SEQABLE_ONLY
       ++ map (\ v -> ClassP name_SOP_Generic [v]) free_tvars_typ
#else
#if NFDATAN_ONLY
       ++ map (\ v -> ClassP name_NFDataN [v]) free_tvars_typ
#else
       ++ map (\ v -> ClassP name_Typeable [v]) free_tvars_typ
       ++ map (\ v -> ClassP name_NFDataN [v]) free_tvars_typ
       ++ map (\ v -> ClassP name_NFData [v]) free_tvars_typ
       ++ map (\ v -> ClassP name_NFDataP [v]) free_tvars_typ
#endif
#endif
#if SHOW_CONSTRAINT
       ++ map (\ v -> ClassP name_Show [v]) free_tvars_typ
#endif
     where
      -- This is to avoid duplication (perhaps ironically...):
      j p | ClassP n ts <- p   = ClassP n $ map (substTyVars (orig,fresh)) ts
          | EqualP t1 t2 <- p  = EqualP ((substTyVars (orig,fresh)) t1) ((substTyVars (orig,fresh)) t1)
--        | EqualP t1 t2 <- p  = error "make_ctx: not ready for EqualP"
      ctx_ | isNothing mof  = ctx
           | otherwise      = map j ctx
      Just (orig,fresh) = mof  -- antipattern...
      !_ = trace (show ctx_) $ ()
      ctx' = (
               id
#if SEQABLE_ONLY
             . filter (\ (ClassP name ts) -> show name /= "Generic")
             . filter (\ (ClassP name ts) -> show name /= "Generics.SOP.Universe.Generic")
#if SHOW_TYPE
             . filter (\ (ClassP name ts) -> show name /= "Typeable")
#endif
#else
#if NFDATAN_ONLY
             . filter (\ (ClassP name ts) -> show name /= "NFDataN")
             . filter (\ (ClassP name ts) -> show name /= "Control.DeepSeq.Bounded.NFDataN.NFDataN")
#if SHOW_TYPE
-- (recently added; and untested; but I think is supposed to be here?)
             . filter (\ (ClassP name ts) -> show name /= "Typeable")
#endif
#else
             . filter (\ (ClassP name ts) -> show name /= "Typeable")
             . filter (\ (ClassP name ts) -> show name /= "NFDataN")
             . filter (\ (ClassP name ts) -> show name /= "NFData")
             . filter (\ (ClassP name ts) -> show name /= "NFDataP")
             . filter (\ (ClassP name ts) -> show name /= "Data.Typeable.Internal.Typeable")
             . filter (\ (ClassP name ts) -> show name /= "Control.DeepSeq.Bounded.NFDataN.NFDataN")
             . filter (\ (ClassP name ts) -> show name /= "Control.DeepSeq.NFData")
             . filter (\ (ClassP name ts) -> show name /= "Control.DeepSeq.Bounded.NFDataP.NFDataP")
#endif
#endif
#if SHOW_CONSTRAINT
             . filter (\ (ClassP name ts) -> show name /= "Show")
             . filter (\ (ClassP name ts) -> show name /= "GHC.Show.Show")
#endif
             )
             ctx_
      name_NFDataP = mkName "NFDataP"
      name_NFDataN = mkName "NFDataN"
      name_NFData = mkName "NFData"
      name_Typeable = mkName "Typeable"
      name_Show = mkName "Show"
      name_SOP_Generic = mkName "Generics.SOP.Universe.Generic"

-------------------------------------------------------------------------------

  showNTs :: [(Name,Type)] -> String
  showNTs nts = ss'
   where
    ss = map (\ (n,t) -> pprint n ++ " :: " ++ pprint t) nts
    ss' = intercalate "\n" ss

-------------------------------------------------------------------------------

  followArrows :: Type -> Type
  followArrows (AppT (AppT ArrowT t1) t2) = followArrows t2
---followArrows (ArrowT t1 t2) = followArrows t2
  followArrows t = t

-------------------------------------------------------------------------------

#if INJECT_DUMMY_CLASS_AND_INSTANCE_TO_BLOCK_DEAD_CODE_ELIMINATION

-- We have already run "dss <- manifestSeqinjDecls nts" so we
-- can assume full benefit of that information here.
--
-- What we need to build:
--
--  - a single class declaration
--     - which contains one method signature declaration per seqinj_[0-9]*
--       signature that was prepared by manifestSeqinjDecls
--
--          class SeqinjDummyClass a where
--            seqinj_class_0 :: a -> Int -> Int
--            ...
--
--  - and a single instance declaration (instancing this class)
--     - which contains one method definition declaration to correspond
--       with each signature in the class declaration
--
--          instance SeqinjDummyClass () where
--            seqinj_class_0 _ x = seqinj_0 x
--            ...
--
-- > runQ [d| class Blah a where blah :: a -> Int -> Int |]
-- [ClassD [] Blah_0 [PlainTV a_2] [] [SigD blah_1 (AppT (AppT ArrowT (VarT a_2)) (AppT (AppT ArrowT (ConT GHC.Types.Int)) (ConT GHC.Types.Int)))]]
--
-- > runQ [d| instance Blah () where blah _ x = seqinj_0 x |]
-- [InstanceD [] (AppT (ConT Ghci1.Blah) (TupleT 0)) [FunD Ghci1.blah [Clause [WildP,VarP x_0] (NormalB (AppE (VarE seqinj_0_1627392795) (VarE x_0))) []]]]
--
-- Notes:
--  - I don't think we want to try to use the (Name,Type) pairs.
--  - rather, use the [[Dec]] -- not all Name's end up producing
--    Decl, remember, so these lists are not parallel! (We could
--    return an elided nts which IS parallel, upstream, but we didn't.)

-- XXX I think I need nested forall in a case like:
--   class SeqinjDummyClass a where
--     seqinj_meth_0 :: a -> Blob b -> Blob b
-- This will become more explicit in TH land; Blob b will actually be
-- (forall b. <ctx> => Blob b). And we do NOT want
--     seqinj_meth_0 :: a -> (forall b. <ctx> => Blob b) -> (forall b. <ctx> => Blob b)
-- we want
--     seqinj_meth_0 :: forall b. <ctx> => a -> Blob b -> Blob b
-- Note that the "a" variable takes its ctx from the class declaration,
-- and in fact it does not get a forall at all [?? right?]
--   So we DON'T need nested forall here (although we would if had
-- multiple variables with different contexts)...

-- XXX Also remember, we probably don't need the top-level seqinj_[0-9]*'s
-- at all now, with the class/instance -- but when build the Map in plugin,
-- will have to make a change to read the signatures in the class rather
-- than as now from the top-level seqinj_[0-9]*'s...
-- LATER: This turned out to be not the case: The top-level seqinj_[0-9]*'s
-- seem to need to be retained in the plugin output.

  manifestDummyClassAndInstance :: Type -> [[Dec]] -> Q [Dec]
  manifestDummyClassAndInstance sidtyp dss = do
--manifestDummyClassAndInstance :: [(Name,Type)] -> [[Dec]] -> Q [Dec]
--manifestDummyClassAndInstance (nt:nts) (ds:dss) = do
    modname <- fmap loc_module qLocation
    let modname' = map (\x -> if x == '.' then '_' else x) modname
    an <- newName "a"
    (sigs,defs) <- liftM fst $
      ( foldM
          ( \ y@((sigs_, defs_), i) dec ->
              do
                 -- Prise apart the Dec, tagging values for later reference
                 let [tdec, fdec] = dec
                 let (SigD vp_s t_s) = tdec
                 let (ValD (VarP vp_v) (NormalB ae_v) []) = fdec
                 mn <- newName $ "seqinj_meth_" ++ show i
#if 1
#if 1
                 t_s' <- makeSeqinjType (Just an) sidtyp t_s
#else
-- XXX no.
                 let t_s'' = AppT (AppT ArrowT (VarT an)) t_s
                 t_s' <- makeSeqinjType (Just an) t_s''
#endif
#else
                 let t_s' = AppT (AppT ArrowT (VarT tv)) t_s
#endif
                 let s = SigD mn t_s'
                 vv <- newName "x"  -- no matter if we [shadow/whatever]
                 sid <- newName "sid"  -- no matter if we [shadow/whatever]
                 let d = FunD
                           mn
                           [ Clause
                               [WildP, VarP sid, VarP vv]
                               (NormalB
                                 (AppE
-- To really never even build them, there's some more changes
-- needed in this modules...
#if NO_TOP_LEVEL_SEQINJ_DUMMIES
                                   (AppE (VarE $ mkName "Seqaid.Runtime.seqaidDispatch") (VarE sid))
#else
                                   (AppE (VarE vp_v) (VarE sid))
#endif
                                   (VarE vv)
                                 )
                               )
                               []
                           ]
--- sigs = [SigD mn typ]
--- typ = (AppT (AppT ArrowT (VarT tv)) (AppT (AppT ArrowT (ConT GHC.Types.Int)) (ConT GHC.Types.Int)))
-- defs = [FunD mn [Clause [WildP,VarP vv] (NormalB (AppE (VarE seqinj_0_1627392795) (VarE vv))) []]]
                 return ((s:sigs_, d:defs_), -1+i)
          )
          (([],[]),-1+length dss)
        :: [[Dec]] -> Q (([Dec],[Dec]),Int) )  -- type up to here
          dss
    cn <- newName $ "SeqinjDummyClass_" ++ modname'
--  cn <- newName "SeqinjDummyClass"
    let cdec = ClassD [] cn [PlainTV an] [] sigs
    let idec = InstanceD [] (AppT (ConT cn) (TupleT 0)) defs
    return [cdec, idec]

#endif

-------------------------------------------------------------------------------

  -- These are only for cosmetic purposes in warning messages.

  -- Cloned from Core.hs.
  -- This will work fine on module names, but don't try to
  -- use it on (String-ified) types!... (See caveat in Core.hs.)
  -- XXX how about nameBase and nameModule? (Oh, but that's Name not String...)
  dropQuals :: String -> String
  dropQuals = reverse . takeWhile (/= '.') . reverse

  takeQuals :: String -> String
  takeQuals = reverse . drop 1 . dropWhile (/= '.') . reverse

  -- XXX VERY BAD INDEED!!!
  beautify :: String -> String
  beautify s = s_
   where
    marr1 = (s =~ "^forall ") :: MatchArray
    (a1,b1) = (marr1!0)
    marr2 = (s =~ "=> ") :: MatchArray
    (a2,b2) = (marr2!0)
    s_ | null $ indices marr1  = s
       | null $ indices marr2  = s
       | otherwise
          =   dropWhile (\x -> x==' '||x=='\t'||x=='\n')
            $ drop (a2+b2) s

-------------------------------------------------------------------------------

#if TRY_INJECT_NOINLINE_ON_REQUESTED_BINDS
  noinlineTH :: [String] -> Q [Dec]
--noinlineTH :: [Name] -> Q [Dec]
  noinlineTH nms = do
    mapM
      (\x -> do Just nm <- lookupValueName x
                return $ PragmaD $ InlineP nm NoInline FunLike AllPhases)
      nms
--  mapM (\x -> do { (Just nm) <- lookupValueName x ; return $ PragmaD $ InlineP nm NoInline FunLike AllPhases }) nms
--  mapM (\x -> (liftM fromJust) lookupValueName x >>= \nm -> PragmaD $ InlineP nm NoInline FunLike AllPhases) nms  -- oh whatever!!
--  return $ map (\x -> PragmaD $ InlineP x NoInline FunLike AllPhases) nms
#endif

-------------------------------------------------------------------------------