ghc-justdoit-0.1: GHC/JustDoIt/Plugin.hs
{-# LANGUAGE CPP, TupleSections #-}
module GHC.JustDoIt.Plugin ( plugin )
where
-- external
import Data.Maybe
import Control.Monad
-- GHC API
import Module (mkModuleName)
import OccName (mkTcOcc)
import Plugins (Plugin (..), defaultPlugin)
import TcEvidence
import TcPluginM
import TcRnTypes
import Class
import CoreUtils
import MkCore
import TyCon
import Type
import CoreSyn
import GHC.JustDoIt.Solver
plugin :: Plugin
plugin = defaultPlugin { tcPlugin = const (Just jdiPlugin) }
jdiPlugin :: TcPlugin
jdiPlugin =
TcPlugin { tcPluginInit = lookupJDITyCon
, tcPluginSolve = solveJDI
, tcPluginStop = const (return ())
}
lookupJDITyCon :: TcPluginM Class
lookupJDITyCon = do
Found _ md <- findImportedModule jdiModule Nothing
jdiTcNm <- lookupOrig md (mkTcOcc "JustDoIt")
tcLookupClass jdiTcNm
where
jdiModule = mkModuleName "GHC.JustDoIt"
wrap :: Class -> CoreExpr -> EvTerm
wrap cls = EvExpr . appDc
where
tyCon = classTyCon cls
dc = tyConSingleDataCon tyCon
appDc x = mkCoreConApps dc [Type (exprType x), x]
findClassConstraint :: Class -> Ct -> Maybe (Ct, Type)
findClassConstraint cls ct = do
(cls', [t]) <- getClassPredTys_maybe (ctPred ct)
guard (cls' == cls)
return (ct, t)
solveJDI :: Class -- ^ JDI's TyCon
-> [Ct] -- ^ [G]iven constraints
-> [Ct] -- ^ [D]erived constraints
-> [Ct] -- ^ [W]anted constraints
-> TcPluginM TcPluginResult
solveJDI jdiCls _ _ wanteds =
return $! case result of
Left x -> TcPluginContradiction [x]
Right solved -> TcPluginOk solved []
where
our_wanteds = mapMaybe (findClassConstraint jdiCls) wanteds
result = partitionMaybe (fmap (wrap jdiCls) . solve) our_wanteds
partitionMaybe :: (b -> Maybe c) -> [(a,b)] -> Either a [(c,a)]
partitionMaybe _ [] = Right []
partitionMaybe f ((k,v):xs) = case f v of
Nothing -> Left k
Just y -> ((y,k):) <$> partitionMaybe f xs