{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Clash.GHC.LoadModules
( loadModules
, ghcLibDir
, setWantedLanguageExtensions
)
where
#ifndef USE_GHC_PATHS
#ifndef TOOL_VERSION_ghc
#error TOOL_VERSION_ghc undefined
#endif
#endif
import Clash.Annotations.Primitive (HDL, PrimitiveGuard)
import Clash.Annotations.TopEntity (TopEntity (..))
import Clash.Primitives.Types (UnresolvedPrimitive)
import Clash.Util (ClashException(..), pkgIdFromTypeable)
import qualified Clash.Util.Interpolate as I
import Control.Arrow (first, second)
import Control.DeepSeq (deepseq)
import Control.Exception (SomeException, throw)
import Control.Monad (forM)
#if MIN_VERSION_ghc(8,6,0)
import Control.Exception (throwIO)
#endif
import Control.Monad.IO.Class (liftIO)
import Data.Char (isDigit)
import Data.Generics.Uniplate.DataOnly (transform)
import Data.Data (Data)
import Data.Typeable (Typeable)
import Data.List (foldl', nub)
import Data.Maybe (catMaybes, listToMaybe, fromMaybe)
import qualified Data.Text as Text
import qualified Data.Time.Clock as Clock
import Language.Haskell.TH.Syntax (lift)
import GHC.Stack (HasCallStack)
#ifdef USE_GHC_PATHS
import GHC.Paths (libdir)
#else
import System.Exit (ExitCode (..))
import System.IO (hGetLine)
import System.IO.Error (tryIOError)
import System.Process (runInteractiveCommand,
waitForProcess)
#endif
import qualified Annotations
import qualified CoreFVs
import qualified CoreSyn
import qualified Digraph
#if MIN_VERSION_ghc(8,6,0)
import qualified DynamicLoading
#endif
import DynFlags (GeneralFlag (..))
import qualified DynFlags
import qualified Exception
import qualified GHC
import qualified HscMain
import qualified HscTypes
import qualified MonadUtils
import qualified Panic
import qualified GhcPlugins (deserializeWithData, installedUnitIdString)
import qualified TcRnMonad
import qualified TcRnTypes
import qualified TidyPgm
import qualified Unique
import qualified UniqFM
import qualified FamInst
import qualified FamInstEnv
import qualified GHC.LanguageExtensions as LangExt
import qualified Name
import qualified OccName
import Outputable (ppr)
import qualified Outputable
import qualified UniqSet
import Util (OverridingBool)
import qualified Var
import Clash.GHC.GHC2Core (modNameM, qualifiedNameString')
import Clash.GHC.LoadInterfaceFiles
(loadExternalExprs, getUnresolvedPrimitives, loadExternalBinders,
LoadedBinders(..))
import Clash.GHCi.Common (checkMonoLocalBindsMod)
import Clash.Util (curLoc, noSrcSpan, reportTimeDiff
,wantedLanguageExtensions, unwantedLanguageExtensions)
import Clash.Annotations.BitRepresentation.Internal
(DataRepr', dataReprAnnToDataRepr')
ghcLibDir :: IO FilePath
#ifdef USE_GHC_PATHS
ghcLibDir = return libdir
#else
ghcLibDir = do
(libDirM,exitCode) <- getProcessOutput $ "ghc-" ++ TOOL_VERSION_ghc ++ " --print-libdir"
case exitCode of
ExitSuccess -> case libDirM of
Just libDir -> return libDir
Nothing -> Panic.pgmError noGHC
ExitFailure i -> case i of
127 -> Panic.pgmError noGHC
i' -> Panic.pgmError $ "Calling GHC failed with error code: " ++ show i'
where
noGHC = "Clash needs the GHC compiler it was built with, ghc-" ++ TOOL_VERSION_ghc ++
", but it was not found. Make sure its location is in your PATH variable."
getProcessOutput :: String -> IO (Maybe String, ExitCode)
getProcessOutput command =
do (_, pOut, _, handle) <- runInteractiveCommand command
exitCode <- waitForProcess handle
output <- either (const Nothing) Just <$> tryIOError (hGetLine pOut)
return (output, exitCode)
#endif
loadExternalModule
:: (HasCallStack, GHC.GhcMonad m)
=> HDL
-> String
-> m (Either
SomeException
( [CoreSyn.CoreBndr]
, FamInstEnv.FamInstEnv
, GHC.ModuleName
, LoadedBinders
, [CoreSyn.CoreBind]
) )
loadExternalModule hdl modName0 = Exception.gtry $ do
let modName1 = GHC.mkModuleName modName0
foundMod <- GHC.findModule modName1 Nothing
let errMsg = "Internal error: found module, but could not load it"
modInfo <- fromMaybe (error errMsg) <$> (GHC.getModuleInfo foundMod)
tyThings <- catMaybes <$> mapM GHC.lookupGlobalName (GHC.modInfoExports modInfo)
let rootIds = [id_ | GHC.AnId id_ <- tyThings]
loaded <- loadExternalBinders hdl rootIds
let allBinders = makeRecursiveGroups (lbBinders loaded)
return (rootIds, FamInstEnv.emptyFamInstEnv, modName1, loaded, allBinders)
setupGhc
:: GHC.GhcMonad m
=> OverridingBool
-> Maybe GHC.DynFlags
-> [FilePath]
-> m ()
setupGhc useColor dflagsM idirs = do
dflags <-
case dflagsM of
Just df -> return df
Nothing -> do
#if MIN_VERSION_ghc(8,6,0)
df <- do
df <- GHC.getSessionDynFlags
_ <- GHC.setSessionDynFlags df {DynFlags.pkgDatabase = Nothing}
GHC.getSessionDynFlags
#else
df <- GHC.getSessionDynFlags
#endif
let df1 = setWantedLanguageExtensions df
ghcTyLitNormPlugin = GHC.mkModuleName "GHC.TypeLits.Normalise"
ghcTyLitExtrPlugin = GHC.mkModuleName "GHC.TypeLits.Extra.Solver"
ghcTyLitKNPlugin = GHC.mkModuleName "GHC.TypeLits.KnownNat.Solver"
dfPlug = df1 { DynFlags.pluginModNames = nub $
ghcTyLitNormPlugin : ghcTyLitExtrPlugin :
ghcTyLitKNPlugin : DynFlags.pluginModNames df1
, DynFlags.useColor = useColor
, DynFlags.importPaths = idirs
}
return dfPlug
let dflags1 = dflags
{ DynFlags.optLevel = 2
, DynFlags.ghcMode = GHC.CompManager
, DynFlags.ghcLink = GHC.LinkInMemory
, DynFlags.hscTarget
= if DynFlags.rtsIsProfiled
then DynFlags.HscNothing
else DynFlags.defaultObjectTarget $
#if !MIN_VERSION_ghc(8,10,0)
DynFlags.targetPlatform
#endif
dflags
, DynFlags.reductionDepth = 1000
}
let dflags2 = unwantedOptimizationFlags dflags1
ghcDynamic = case lookup "GHC Dynamic" (DynFlags.compilerInfo dflags) of
Just "YES" -> True
_ -> False
dflags3 = if ghcDynamic then DynFlags.gopt_set dflags2 DynFlags.Opt_BuildDynamicToo
else dflags2
#if MIN_VERSION_ghc(8,6,0)
hscenv <- GHC.getSession
dflags4 <- MonadUtils.liftIO (DynamicLoading.initializePlugins hscenv dflags3)
_ <- GHC.setSessionDynFlags dflags4
#else
_ <- GHC.setSessionDynFlags dflags3
#endif
return ()
loadLocalModule
:: GHC.GhcMonad m
=> HDL
-> String
-> m ( [CoreSyn.CoreBndr]
, FamInstEnv.FamInstEnv
, GHC.ModuleName
, LoadedBinders
, [CoreSyn.CoreBind]
)
loadLocalModule hdl modName = do
target <- GHC.guessTarget modName Nothing
GHC.setTargets [target]
modGraph <- GHC.depanal [] False
#if MIN_VERSION_ghc(8,4,1)
let modGraph' = GHC.mapMG disableOptimizationsFlags modGraph
#else
let modGraph' = map disableOptimizationsFlags modGraph
#endif
modGraph2 = Digraph.flattenSCCs (GHC.topSortModuleGraph True modGraph' Nothing)
liftIO $ mapM_ checkMonoLocalBindsMod modGraph2
tidiedMods <- forM modGraph2 $ \m -> do
oldDFlags <- GHC.getSessionDynFlags
pMod <- parseModule m
_ <- GHC.setSessionDynFlags (GHC.ms_hspp_opts (GHC.pm_mod_summary pMod))
tcMod <- GHC.typecheckModule (removeStrictnessAnnotations pMod)
tcMod' <- GHC.loadModule tcMod
dsMod <- fmap GHC.coreModule $ GHC.desugarModule tcMod'
hsc_env <- GHC.getSession
#if MIN_VERSION_ghc(8,4,1)
simpl_guts <- MonadUtils.liftIO $ HscMain.hscSimplify hsc_env [] dsMod
#else
simpl_guts <- MonadUtils.liftIO $ HscMain.hscSimplify hsc_env dsMod
#endif
checkForInvalidPrelude simpl_guts
(tidy_guts,_) <- MonadUtils.liftIO $ TidyPgm.tidyProgram hsc_env simpl_guts
let pgm = HscTypes.cg_binds tidy_guts
let modFamInstEnv = TcRnTypes.tcg_fam_inst_env $ fst $ GHC.tm_internals_ tcMod
_ <- GHC.setSessionDynFlags oldDFlags
return (pgm,modFamInstEnv)
let (binders,modFamInstEnvs) = unzip tidiedMods
binderIds = map fst (CoreSyn.flattenBinds (concat binders))
plusFamInst f1 f2 = FamInstEnv.extendFamInstEnvList f1 (FamInstEnv.famInstEnvElts f2)
modFamInstEnvs' = foldl' plusFamInst FamInstEnv.emptyFamInstEnv modFamInstEnvs
rootModule = GHC.ms_mod_name . last $ modGraph2
let rootIds = map fst . CoreSyn.flattenBinds $ last binders
loaded0 <- loadExternalExprs hdl (UniqSet.mkUniqSet binderIds) (concat binders)
localPrims <- findPrimitiveAnnotations hdl binderIds
let loaded1 = loaded0{lbPrims=lbPrims loaded0 ++ localPrims}
let allBinders = concat binders ++ makeRecursiveGroups (lbBinders loaded0)
pure (rootIds, modFamInstEnvs', rootModule, loaded1, allBinders)
loadModules
:: OverridingBool
-> HDL
-> String
-> Maybe (DynFlags.DynFlags)
-> [FilePath]
-> IO ( [CoreSyn.CoreBind]
, [(CoreSyn.CoreBndr,Int)]
, [CoreSyn.CoreBndr]
, FamInstEnv.FamInstEnvs
, [( CoreSyn.CoreBndr
, Maybe TopEntity
, Maybe CoreSyn.CoreBndr)]
, [Either UnresolvedPrimitive FilePath]
, [DataRepr']
, [(Text.Text, PrimitiveGuard ())]
)
loadModules useColor hdl modName dflagsM idirs = do
libDir <- MonadUtils.liftIO ghcLibDir
startTime <- Clock.getCurrentTime
GHC.runGhc (Just libDir) $ do
setupGhc useColor ((\d -> d{GHC.mainFunIs=Nothing}) <$> dflagsM) idirs
(rootIds, modFamInstEnvs, rootModule, LoadedBinders{..}, allBinders) <-
loadExternalModule hdl modName >>= \case
Left _loadExternalErr -> loadLocalModule hdl modName
Right res -> pure res
let allBinderIds = map fst (CoreSyn.flattenBinds allBinders)
modTime <- startTime `deepseq` length allBinderIds `seq` MonadUtils.liftIO Clock.getCurrentTime
let modStartDiff = reportTimeDiff modTime startTime
MonadUtils.liftIO $ putStrLn $ "GHC: Parsing and optimising modules took: " ++ modStartDiff
extTime <- modTime `deepseq` length lbUnlocatable `deepseq` MonadUtils.liftIO Clock.getCurrentTime
let extModDiff = reportTimeDiff extTime modTime
MonadUtils.liftIO $ putStrLn $ "GHC: Loading external modules from interface files took: " ++ extModDiff
hscEnv <- GHC.getSession
#if MIN_VERSION_ghc(8,6,0)
famInstEnvs <- do
(msgs, m) <- TcRnMonad.liftIO $ TcRnMonad.initTcInteractive hscEnv FamInst.tcGetFamInstEnvs
case m of
Nothing -> TcRnMonad.liftIO $ throwIO (HscTypes.mkSrcErr (snd msgs))
Just x -> return x
#else
famInstEnvs <- TcRnMonad.liftIO $ TcRnMonad.initTcForLookup hscEnv FamInst.tcGetFamInstEnvs
#endif
allSyn <- map (second Just) <$> findSynthesizeAnnotations allBinderIds
topSyn <- map (second Just) <$> findSynthesizeAnnotations rootIds
benchAnn <- findTestBenchAnnotations rootIds
reprs' <- findCustomReprAnnotations
primGuards <- findPrimitiveGuardAnnotations allBinderIds
let topEntityName = fromMaybe "topEntity" (GHC.mainFunIs =<< dflagsM)
varNameString = OccName.occNameString . Name.nameOccName . Var.varName
topEntities = filter ((==topEntityName) . varNameString) rootIds
benches = filter ((== "testBench") . varNameString) rootIds
mergeBench (x,y) = (x,y,lookup x benchAnn)
allSyn' = map mergeBench allSyn
topEntities' <-
case (topEntities, topSyn) of
([], []) ->
let modName1 = Outputable.showSDocUnsafe (ppr rootModule) in
if topEntityName /= "topEntity" then
Panic.pgmError [I.i|
No top-level function called '#{topEntityName}' found. Did you
forget to export it?
|]
else
Panic.pgmError [I.i|
No top-level function called 'topEntity' found, nor a function with
a 'Synthesize' annotation in module #{modName1}. Did you forget to
export them?
For more information on 'Synthesize' annotations, check out the
documentation of "Clash.Annotations.TopEntity".
|]
([], _) ->
return allSyn'
([x], _) ->
case lookup x topSyn of
Nothing ->
case lookup x benchAnn of
Nothing -> return ((x,Nothing,listToMaybe benches):allSyn')
Just y -> return ((x,Nothing,Just y):allSyn')
Just _ ->
return allSyn'
(_, _) ->
Panic.pgmError $ $(curLoc) ++ "Multiple 'topEntities' found."
let reprs1 = lbReprs ++ reprs'
annTime <-
extTime
`deepseq` length topEntities'
`deepseq` lbPrims
`deepseq` reprs1
`deepseq` primGuards
`deepseq` MonadUtils.liftIO Clock.getCurrentTime
let annExtDiff = reportTimeDiff annTime extTime
MonadUtils.liftIO $ putStrLn $ "GHC: Parsing annotations took: " ++ annExtDiff
return ( allBinders
, lbClassOps
, lbUnlocatable
, (fst famInstEnvs, modFamInstEnvs)
, topEntities'
, lbPrims
, reprs1
, primGuards
)
makeRecursiveGroups
:: [(CoreSyn.CoreBndr,CoreSyn.CoreExpr)]
-> [CoreSyn.CoreBind]
makeRecursiveGroups
= map makeBind
. Digraph.stronglyConnCompFromEdgedVerticesUniq
. map makeNode
where
makeNode
:: (CoreSyn.CoreBndr,CoreSyn.CoreExpr)
-> Digraph.Node Unique.Unique (CoreSyn.CoreBndr,CoreSyn.CoreExpr)
makeNode (b,e) =
#if MIN_VERSION_ghc(8,4,1)
Digraph.DigraphNode
(b,e)
(Var.varUnique b)
(UniqSet.nonDetKeysUniqSet (CoreFVs.exprFreeIds e))
#else
((b,e)
,Var.varUnique b
,UniqSet.nonDetKeysUniqSet (CoreFVs.exprFreeIds e))
#endif
makeBind
:: Digraph.SCC (CoreSyn.CoreBndr,CoreSyn.CoreExpr)
-> CoreSyn.CoreBind
makeBind (Digraph.AcyclicSCC (b,e)) = CoreSyn.NonRec b e
makeBind (Digraph.CyclicSCC bs) = CoreSyn.Rec bs
errOnDuplicateAnnotations
:: String
-> [CoreSyn.CoreBndr]
-> [[a]]
-> [(CoreSyn.CoreBndr, a)]
errOnDuplicateAnnotations nm bndrs anns =
go (zip bndrs anns)
where
go
:: [(CoreSyn.CoreBndr, [a])]
-> [(CoreSyn.CoreBndr, a)]
go [] = []
go ((_, []):ps) = go ps
go ((b, [p]):ps) = (b, p) : (go ps)
go ((b, _):_) =
Panic.pgmError $ "The following value has multiple "
++ "'" ++ nm ++ "' annotations: "
++ Outputable.showSDocUnsafe (ppr b)
findAnnotationsByTargets
:: GHC.GhcMonad m
=> Typeable a
=> Data a
=> [Annotations.AnnTarget Name.Name]
-> m [[a]]
findAnnotationsByTargets targets =
mapM (GHC.findGlobalAnns GhcPlugins.deserializeWithData) targets
findAllModuleAnnotations
:: GHC.GhcMonad m
=> Data a
=> Typeable a
=> m [a]
findAllModuleAnnotations = do
hsc_env <- GHC.getSession
ann_env <- liftIO $ HscTypes.prepareAnnotations hsc_env Nothing
return $ concat
$ UniqFM.nonDetEltsUFM
$ Annotations.deserializeAnns GhcPlugins.deserializeWithData ann_env
findNamedAnnotations
:: GHC.GhcMonad m
=> Data a
=> Typeable a
=> [CoreSyn.CoreBndr]
-> m [[a]]
findNamedAnnotations bndrs =
findAnnotationsByTargets (map (Annotations.NamedTarget . Var.varName) bndrs)
findPrimitiveGuardAnnotations
:: GHC.GhcMonad m
=> [CoreSyn.CoreBndr]
-> m [(Text.Text, (PrimitiveGuard ()))]
findPrimitiveGuardAnnotations bndrs = do
anns0 <- findNamedAnnotations bndrs
let anns1 = errOnDuplicateAnnotations "PrimitiveGuard" bndrs anns0
pure (map (first (qualifiedNameString' . Var.varName)) anns1)
findCustomReprAnnotations
:: GHC.GhcMonad m
=> m [DataRepr']
findCustomReprAnnotations =
map dataReprAnnToDataRepr' <$> findAllModuleAnnotations
findSynthesizeAnnotations
:: GHC.GhcMonad m
=> [CoreSyn.CoreBndr]
-> m [(CoreSyn.CoreBndr, TopEntity)]
findSynthesizeAnnotations bndrs = do
anns <- findNamedAnnotations bndrs
pure (errOnDuplicateAnnotations "Synthesize" bndrs (map (filter isSyn) anns))
where
isSyn (Synthesize {}) = True
isSyn _ = False
findTestBenchAnnotations
:: GHC.GhcMonad m
=> [CoreSyn.CoreBndr]
-> m [(CoreSyn.CoreBndr,CoreSyn.CoreBndr)]
findTestBenchAnnotations bndrs = do
anns0 <- findNamedAnnotations bndrs
let anns1 = map (filter isTB) anns0
anns2 = errOnDuplicateAnnotations "TestBench" bndrs anns1
return (map (second findTB) anns2)
where
isTB (TestBench {}) = True
isTB _ = False
findTB :: TopEntity -> CoreSyn.CoreBndr
findTB (TestBench tb) = case listToMaybe (filter (eqNm tb) bndrs) of
Just tb' -> tb'
Nothing -> Panic.pgmError $
"TestBench named: " ++ show tb ++ " not found"
findTB _ = Panic.pgmError "Unexpected Synthesize"
eqNm thNm bndr = Text.pack (show thNm) == qualNm
where
bndrNm = Var.varName bndr
qualNm = maybe occName (\modName -> modName `Text.append` ('.' `Text.cons` occName)) (modNameM bndrNm)
occName = Text.pack (OccName.occNameString (Name.nameOccName bndrNm))
findPrimitiveAnnotations
:: GHC.GhcMonad m
=> HDL
-> [CoreSyn.CoreBndr]
-> m [Either UnresolvedPrimitive FilePath]
findPrimitiveAnnotations hdl bndrs = do
let
annTargets =
map
(fmap Annotations.ModuleTarget . Name.nameModule_maybe)
(map Var.varName bndrs)
let
targets =
(catMaybes annTargets) ++
(map (Annotations.NamedTarget . Var.varName) bndrs)
anns <- findAnnotationsByTargets targets
concat <$>
mapM (getUnresolvedPrimitives hdl)
(concat $ zipWith (\t -> map ((,) t)) targets anns)
parseModule :: GHC.GhcMonad m => GHC.ModSummary -> m GHC.ParsedModule
parseModule modSum = do
(GHC.ParsedModule pmModSum pmParsedSource extraSrc anns) <-
GHC.parseModule modSum
return (GHC.ParsedModule
(disableOptimizationsFlags pmModSum)
pmParsedSource extraSrc anns)
disableOptimizationsFlags :: GHC.ModSummary -> GHC.ModSummary
disableOptimizationsFlags ms@(GHC.ModSummary {..})
= ms {GHC.ms_hspp_opts = dflags}
where
dflags = unwantedOptimizationFlags (ms_hspp_opts
{ DynFlags.optLevel = 2
, DynFlags.reductionDepth = 1000
})
unwantedOptimizationFlags :: GHC.DynFlags -> GHC.DynFlags
unwantedOptimizationFlags df =
foldl' DynFlags.xopt_unset
(foldl' DynFlags.gopt_unset df unwanted) unwantedLang
where
unwanted = [ Opt_LiberateCase
, Opt_SpecConstr
, Opt_IgnoreAsserts
, Opt_DoEtaReduction
, Opt_UnboxStrictFields
, Opt_UnboxSmallStrictFields
#if !MIN_VERSION_ghc(8,6,0)
, Opt_Vectorise
, Opt_VectorisationAvoidance
#endif
, Opt_RegsGraph
, Opt_RegsGraph
, Opt_PedanticBottoms
, Opt_LlvmTBAA
, Opt_CmmSink
, Opt_CmmElimCommonBlocks
, Opt_OmitYields
, Opt_IgnoreInterfacePragmas
, Opt_OmitInterfacePragmas
, Opt_IrrefutableTuples
, Opt_Loopification
, Opt_CprAnal
, Opt_FullLaziness
]
unwantedLang = [ LangExt.Strict
, LangExt.StrictData
]
setWantedLanguageExtensions :: GHC.DynFlags -> GHC.DynFlags
setWantedLanguageExtensions df =
foldl' DynFlags.gopt_set
(foldl' DynFlags.xopt_unset
(foldl' DynFlags.xopt_set df wantedLanguageExtensions) unwantedLanguageExtensions)
wantedOptimizations
where
wantedOptimizations =
[ Opt_CSE
, Opt_Specialise
, Opt_DoLambdaEtaExpansion
, Opt_CaseMerge
, Opt_DictsCheap
, Opt_ExposeAllUnfoldings
, Opt_ForceRecomp
, Opt_EnableRewriteRules
, Opt_SimplPreInlining
, Opt_StaticArgumentTransformation
, Opt_FloatIn
, Opt_DictsStrict
, Opt_DmdTxDictSel
, Opt_Strictness
, Opt_SpecialiseAggressively
, Opt_CrossModuleSpecialise
]
removeStrictnessAnnotations ::
GHC.ParsedModule
-> GHC.ParsedModule
removeStrictnessAnnotations pm =
pm {GHC.pm_parsed_source = fmap rmPS (GHC.pm_parsed_source pm)}
where
rmPS hsm = hsm {GHC.hsmodDecls = (fmap . fmap) rmHSD (GHC.hsmodDecls hsm)}
#if MIN_VERSION_ghc(8,6,0)
rmHSD (GHC.TyClD x tyClDecl) = GHC.TyClD x (rmTyClD tyClDecl)
#else
rmHSD (GHC.TyClD tyClDecl) = GHC.TyClD (rmTyClD tyClDecl)
#endif
rmHSD hsd = hsd
rmTyClD dc@(GHC.DataDecl {}) = dc {GHC.tcdDataDefn = rmDataDefn (GHC.tcdDataDefn dc)}
rmTyClD tyClD = tyClD
rmDataDefn hdf = hdf {GHC.dd_cons = (fmap . fmap) rmCD (GHC.dd_cons hdf)}
#if MIN_VERSION_ghc(8,6,0)
rmCD gadt@(GHC.ConDeclGADT {}) = gadt {GHC.con_res_ty = rmHsType (GHC.con_res_ty gadt)
,GHC.con_args = rmConDetails (GHC.con_args gadt)
}
rmCD h98@(GHC.ConDeclH98 {}) = h98 {GHC.con_args = rmConDetails (GHC.con_args h98)}
rmCD xcon = xcon
#else
rmCD gadt@(GHC.ConDeclGADT {}) = gadt {GHC.con_type = rmSigType (GHC.con_type gadt)}
rmCD h98@(GHC.ConDeclH98 {}) = h98 {GHC.con_details = rmConDetails (GHC.con_details h98)}
#endif
#if !MIN_VERSION_ghc(8,6,0)
rmSigType hsIB = hsIB {GHC.hsib_body = rmHsType (GHC.hsib_body hsIB)}
#endif
rmConDetails (GHC.PrefixCon args) = GHC.PrefixCon (fmap rmHsType args)
rmConDetails (GHC.RecCon rec) = GHC.RecCon ((fmap . fmap . fmap) rmConDeclF rec)
rmConDetails (GHC.InfixCon l r) = GHC.InfixCon (rmHsType l) (rmHsType r)
rmHsType = transform go
where
#if MIN_VERSION_ghc(8,6,0)
go (GHC.unLoc -> GHC.HsBangTy _ _ ty) = ty
#else
go (GHC.unLoc -> GHC.HsBangTy _ ty) = ty
#endif
go ty = ty
rmConDeclF cdf = cdf {GHC.cd_fld_type = rmHsType (GHC.cd_fld_type cdf)}
preludePkgId :: String
preludePkgId = $(lift $ pkgIdFromTypeable (undefined :: TopEntity))
checkForInvalidPrelude :: Monad m => HscTypes.ModGuts -> m ()
checkForInvalidPrelude guts =
case filter isWrongPrelude pkgIds of
[] -> return ()
(x:_) -> throw (ClashException noSrcSpan (msgWrongPrelude x) Nothing)
where
pkgs = HscTypes.dep_pkgs . HscTypes.mg_deps $ guts
pkgIds = map (GhcPlugins.installedUnitIdString . fst) pkgs
prelude = "clash-prelude-"
isPrelude pkg = case splitAt (length prelude) pkg of
(x,y:_) | x == prelude && isDigit y -> True
_ -> False
isWrongPrelude pkg = isPrelude pkg && pkg /= preludePkgId
msgWrongPrelude pkg = unlines ["Clash only works with the exact clash-prelude it was built with."
,"Clash was built with: " ++ preludePkgId
,"So can't run with: " ++ pkg
]