module Cryptol.TypeCheck.CheckModuleInstance (checkModuleInstance) where
import Data.Map ( Map )
import qualified Data.Map as Map
import Control.Monad(unless)
import Cryptol.Parser.Position(Located(..))
import qualified Cryptol.Parser.AST as P
import Cryptol.ModuleSystem.Name(Name,nameIdent,nameLoc)
import Cryptol.ModuleSystem.InstantiateModule(instantiateModule)
import Cryptol.TypeCheck.AST
import Cryptol.TypeCheck.Monad
import Cryptol.TypeCheck.Infer
import Cryptol.TypeCheck.Subst
import Cryptol.TypeCheck.Error
import Cryptol.Utils.PP
import Cryptol.Utils.Panic
checkModuleInstance :: Module ->
Module ->
InferM Module
checkModuleInstance func inst =
do tMap <- checkTyParams func inst
vMap <- checkValParams func tMap inst
(ctrs, m) <- instantiateModule func (mName inst) tMap vMap
let toG p = Goal { goal = thing p
, goalRange = srcRange p
, goalSource = CtModuleInstance (mName inst)
}
addGoals (map toG ctrs)
return Module { mName = mName m
, mExports = mExports m
, mImports = mImports inst ++ mImports m
, mTySyns = Map.union (mTySyns inst) (mTySyns m)
, mNewtypes = Map.union (mNewtypes inst) (mNewtypes m)
, mParamTypes = mParamTypes inst
, mParamConstraints = mParamConstraints inst
, mParamFuns = mParamFuns inst
, mDecls = mDecls inst ++ mDecls m
}
checkTyParams :: Module -> Module -> InferM (Map TParam Type)
checkTyParams func inst =
Map.fromList <$> mapM checkTParamDefined (Map.elems (mParamTypes func))
where
identMap f m = Map.fromList [ (f x, ts) | (x,ts) <- Map.toList m ]
tySyns = identMap nameIdent (mTySyns inst)
newTys = identMap nameIdent (mNewtypes inst)
tParams = Map.fromList [ (tpId x, x) | x0 <- Map.elems (mParamTypes inst)
, let x = mtpParam x0 ]
tpId x = case tpName x of
Just n -> nameIdent n
Nothing -> panic "inferModuleInstance.tpId" ["Missing name"]
checkTParamDefined tp0 =
let tp = mtpParam tp0
x = tpId tp
in case Map.lookup x tySyns of
Just ts -> checkTySynDef tp ts
Nothing ->
case Map.lookup x newTys of
Just nt -> checkNewTyDef tp nt
Nothing ->
case Map.lookup x tParams of
Just tp1 -> checkTP tp tp1
Nothing ->
do recordError $ ErrorMsg $
text "Missing definition for type parameter:" <+> pp x
return (tp, TVar (TVBound tp))
checkTySynDef tp ts =
do let k1 = kindOf tp
k2 = kindOf ts
unless (k1 == k2) (recordError (KindMismatch k1 k2))
let nm = tsName ts
src = CtPartialTypeFun (UserTyFun nm)
mapM_ (newGoal src) (tsConstraints ts)
return (tp, TUser nm [] (tsDef ts))
checkNewTyDef tp nt =
do let k1 = kindOf tp
k2 = kindOf nt
unless (k1 == k2) (recordError (KindMismatch k1 k2))
let nm = ntName nt
src = CtPartialTypeFun (UserTyFun nm)
mapM_ (newGoal src) (ntConstraints nt)
return (tp, TCon (TC (TCNewtype (UserTC nm k2))) [])
checkTP tp tp1 =
do let k1 = kindOf tp
k2 = kindOf tp1
unless (k1 == k2) (recordError (KindMismatch k1 k2))
return (tp, TVar (TVBound tp1))
checkValParams :: Module ->
Map TParam Type ->
Module ->
InferM (Map Name Expr)
checkValParams func tMap inst =
Map.fromList <$> mapM checkParam (Map.elems (mParamFuns func))
where
valMap = Map.fromList (defByParam ++ defByDef)
defByDef = [ (nameIdent (dName d), (dName d, dSignature d))
| dg <- mDecls inst, d <- groupDecls dg ]
defByParam = [ (nameIdent x, (x, mvpType s)) |
(x,s) <- Map.toList (mParamFuns inst) ]
su = listParamSubst (Map.toList tMap)
checkParam pr =
let x = mvpName pr
sP = mvpType pr
in
case Map.lookup (nameIdent x) valMap of
Just (n,sD) -> do e <- makeValParamDef n sD (apSubst su sP)
return (x,e)
Nothing -> do recordError $ ErrorMsg
$ text "Mising definition for value parameter"
<+> pp x
return (x, panic "checkValParams" ["Should not use this"])
makeValParamDef :: Name ->
Schema ->
Schema ->
InferM Expr
makeValParamDef x sDef pDef =
withVar x sDef $ do ~(DExpr e) <- dDefinition <$> checkSigB bnd (pDef,[])
return e
where
bnd = P.Bind { P.bName = loc x
, P.bParams = []
, P.bDef = loc (P.DExpr (P.EVar x))
, P.bSignature = Nothing
, P.bInfix = False
, P.bFixity = Nothing
, P.bPragmas = []
, P.bMono = False
, P.bDoc = Nothing
}
loc a = P.Located { P.srcRange = nameLoc x, P.thing = a }