ghc-justdoit-0.1.0.2: GHC/JustDoIt/Plugin.hs
{-# LANGUAGE CPP, TupleSections #-}
module GHC.JustDoIt.Plugin ( plugin ) where
-- external
import Data.Maybe
import Control.Monad
-- GHC API
import GHC.Unit.Module.Name (mkModuleName)
import GHC.Plugins hiding (TcPlugin)
import GHC.Tc.Types
import GHC.Tc.Types.Constraint
import GHC.Tc.Plugin
import GHC.Core.Class
import GHC.Tc.Types.Evidence
import GHC.Core.Predicate
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