module HERMIT.Dictionary.GHC
(
externals
, loadLemmaLibraryT
, LemmaLibrary
, substR
, dynFlagsT
, arityOf
, lintExprT
, lintModuleT
, occurAnalyseR
, occurAnalyseChangedR
, occurAnalyseExprChangedR
, occurAnalyseAndDezombifyR
, dezombifyR
, buildDictionary
, buildDictionaryT
, buildTypeable
) where
import qualified Bag
import qualified CoreLint
import Control.Arrow
import Control.Monad.IO.Class
import Data.Char (isSpace)
import Data.List (mapAccumL)
import qualified Data.Map as M
import Data.String
import HERMIT.Core
import HERMIT.Context
import HERMIT.External
import HERMIT.GHC
import HERMIT.Kure
import HERMIT.Lemma
import HERMIT.Monad
import HERMIT.Name
externals :: [External]
externals =
[ external "deshadow-prog" (promoteProgR deShadowProgR :: RewriteH LCore)
[ "Deshadow a program." ] .+ Deep
, external "dezombify" (promoteExprR dezombifyR :: RewriteH LCore)
[ "Zap the occurrence information in the current identifer if it is a zombie."] .+ Shallow
, external "occurrence-analysis" (occurrenceAnalysisR :: RewriteH LCore)
[ "Perform dependency analysis on all sub-expressions; simplifying and updating identifer info."] .+ Deep
, external "lint-expr" (promoteExprT lintExprT :: TransformH LCoreTC String)
[ "Runs GHC's Core Lint, which typechecks the current expression."
, "Note: this can miss several things that a whole-module core lint will find."
, "For instance, running this on the RHS of a binding, the type of the RHS will"
, "not be checked against the type of the binding. Running on the whole let expression"
, "will catch that however."] .+ Deep .+ Debug .+ Query
, external "lint-module" (promoteModGutsT lintModuleT :: TransformH LCoreTC String)
[ "Runs GHC's Core Lint, which typechecks the current module."] .+ Deep .+ Debug .+ Query
, external "load-lemma-library" (loadLemmaLibraryT :: HermitName -> TransformH LCore ())
[ "Dynamically load a library of lemmas." ]
]
substR :: MonadCatch m => Var -> CoreExpr -> Rewrite c m Core
substR v e = setFailMsg "Can only perform substitution on expressions, case alternatives or programs." $
promoteExprR (arr $ substCoreExpr v e) <+ promoteProgR (substTopBindR v e) <+ promoteAltR (arr $ substCoreAlt v e)
substTopBindR :: Monad m => Var -> CoreExpr -> Rewrite c m CoreProg
substTopBindR v e = contextfreeT $ \ p -> do
let emptySub = emptySubst
return $ bindsToProg $ snd (mapAccumL substBind (extendSubst emptySub v e) (progToBinds p))
deShadowProgR :: Monad m => Rewrite c m CoreProg
deShadowProgR = arr (bindsToProg . deShadowBinds . progToBinds)
arityOf :: ReadBindings c => c -> Id -> Int
arityOf c i =
case lookupHermitBinding i c of
Nothing -> idArity i
Just b -> runKureM exprArity
(const 0)
(hermitBindingExpr b)
lintModuleT :: TransformH ModGuts String
lintModuleT =
do dynFlags <- dynFlagsT
bnds <- arr mg_binds
let (warns, errs) = CoreLint.lintCoreBindings [] bnds
dumpSDocs endMsg = Bag.foldBag (\ d r -> d ++ ('\n':r)) (showSDoc dynFlags) endMsg
if Bag.isEmptyBag errs
then return $ dumpSDocs "Core Lint Passed" warns
else fail $ "Core Lint Failed:\n" ++ dumpSDocs "" errs
lintExprT :: (BoundVars c, Monad m, HasDynFlags m) => Transform c m CoreExpr String
lintExprT = transform $ \ c e -> do
dflags <- getDynFlags
maybe (return "Core Lint Passed") (fail . showSDoc dflags)
$ CoreLint.lintExpr (varSetElems $ boundVars c) e
dynFlagsT :: HasDynFlags m => Transform c m a DynFlags
dynFlagsT = constT getDynFlags
dezombifyR :: (ExtendPath c Crumb, Monad m) => Rewrite c m CoreExpr
dezombifyR = varR (acceptR isDeadBinder >>^ zapVarOccInfo)
occurAnalyseR :: (AddBindings c, ExtendPath c Crumb, ReadPath c Crumb, HasEmptyContext c, MonadCatch m, Walker c u, Injection CoreExpr u) => Rewrite c m u
occurAnalyseR = let r = promoteExprR (arr occurAnalyseExpr_NoBinderSwap)
go = r <+ anyR go
in tryR go
occurAnalyseExprChangedR :: MonadCatch m => Rewrite c m CoreExpr
occurAnalyseExprChangedR = changedByR exprSyntaxEq (arr occurAnalyseExpr_NoBinderSwap)
occurAnalyseChangedR :: (AddBindings c, ExtendPath c Crumb, ReadPath c Crumb, HasEmptyContext c, MonadCatch m) => Rewrite c m LCore
occurAnalyseChangedR = changedByR lcoreSyntaxEq occurAnalyseR
occurAnalyseAndDezombifyR :: (AddBindings c, ExtendPath c Crumb, ReadPath c Crumb, HasEmptyContext c, MonadCatch m, Walker c u, Injection CoreExpr u) => Rewrite c m u
occurAnalyseAndDezombifyR = allbuR (tryR $ promoteExprR dezombifyR) >>> occurAnalyseR
occurrenceAnalysisR :: (AddBindings c, ExtendPath c Crumb, ReadPath c Crumb, HasEmptyContext c, MonadCatch m, Walker c LCore) => Rewrite c m LCore
occurrenceAnalysisR = occurAnalyseAndDezombifyR
buildTypeable :: (HasDynFlags m, HasHermitMEnv m, HasHscEnv m, MonadIO m) => Type -> m (Id, [CoreBind])
buildTypeable ty = do
evar <- runTcM $ do
cls <- tcLookupClass typeableClassName
let predTy = mkClassPred cls [typeKind ty, ty]
newWantedEvVar predTy
buildDictionary evar
buildDictionary :: (HasDynFlags m, HasHermitMEnv m, HasHscEnv m, MonadIO m) => Id -> m (Id, [CoreBind])
buildDictionary evar = do
(i, bs) <- runTcM $ do
loc <- getCtLoc $ GivenOrigin UnkSkol
let predTy = varType evar
nonC = mkNonCanonical $ CtWanted { ctev_pred = predTy, ctev_evar = evar, ctev_loc = loc }
wCs = mkFlatWC [nonC]
(wCs', bnds) <- solveWantedsTcM wCs
return (evar, bnds)
bnds <- runDsM $ dsEvBinds bs
return (i,bnds)
buildDictionaryT :: (HasDynFlags m, HasHermitMEnv m, HasHscEnv m, MonadCatch m, MonadIO m, MonadUnique m)
=> Transform c m Type CoreExpr
buildDictionaryT = prefixFailMsg "buildDictionaryT failed: " $ contextfreeT $ \ ty -> do
dflags <- getDynFlags
binder <- newIdH ("$d" ++ zEncodeString (filter (not . isSpace) (showPpr dflags ty))) ty
(i,bnds) <- buildDictionary binder
guardMsg (notNull bnds) "no dictionary bindings generated."
return $ case bnds of
[NonRec v e] | i == v -> e
_ -> mkCoreLets bnds (varToCoreExpr i)
type LemmaLibrary = TransformH () Lemmas
loadLemmaLibraryT :: HermitName -> TransformH x ()
loadLemmaLibraryT nm = contextonlyT $ \ c -> do
hscEnv <- getHscEnv
comp <- liftAndCatchIO $ loadLemmaLibrary hscEnv nm
m' <- applyT comp c ()
m <- getLemmas
putLemmas $ m' `M.union` m
loadLemmaLibrary :: HscEnv -> HermitName -> IO LemmaLibrary
loadLemmaLibrary hscEnv hnm = do
name <- lookupHermitNameForPlugins hscEnv varNS hnm
lib_tycon_name <- lookupHermitNameForPlugins hscEnv tyConClassNS $ fromString "HERMIT.Dictionary.GHC.LemmaLibrary"
lib_tycon <- forceLoadTyCon hscEnv lib_tycon_name
mb_v <- getValueSafely hscEnv name $ mkTyConTy lib_tycon
let dflags = hsc_dflags hscEnv
maybe (fail $ showSDoc dflags $ hsep
[ ptext (sLit "The value"), ppr name
, ptext (sLit "did not have the type")
, ppr lib_tycon, ptext (sLit "as required.")])
return mb_v
lookupHermitNameForPlugins :: HscEnv -> NameSpace -> HermitName -> IO Name
lookupHermitNameForPlugins hscEnv ns hnm = do
modName <- maybe (fail "name must be fully qualified with module name.") return (hnModuleName hnm)
let dflags = hsc_dflags hscEnv
rdrName = toRdrName ns hnm
mbName <- lookupRdrNameInModuleForPlugins hscEnv modName rdrName
maybe (fail $ showSDoc dflags $ hsep
[ ptext (sLit "The module"), ppr modName
, ptext (sLit "did not export the name")
, ppr rdrName ])
return mbName