module GF.Compile.TypeCheck.ConcreteNew( checkLType, inferLType ) where import GF.Grammar hiding (Env, VGen, VApp, VRecType) import GF.Grammar.Lookup import GF.Grammar.Predef import GF.Grammar.Lockfield import GF.Compile.Compute.ConcreteNew1 import GF.Compile.TypeCheck.Primitives import GF.Infra.CheckM --import GF.Infra.UseIO import GF.Data.Operations import Control.Applicative(Applicative(..)) import Control.Monad(ap) import GF.Text.Pretty import Data.List (nub, (\\), tails) import qualified Data.IntMap as IntMap --import GF.Grammar.Parser --import System.IO --import Debug.Trace checkLType :: SourceGrammar -> Term -> Type -> Check (Term, Type) checkLType gr t ty = runTcM $ do t <- checkSigma gr [] t (eval gr [] ty) t <- zonkTerm t return (t,ty) inferLType :: SourceGrammar -> Term -> Check (Term, Type) inferLType gr t = runTcM $ do (t,ty) <- inferSigma gr [] t t <- zonkTerm t ty <- zonkTerm (value2term gr [] ty) return (t,ty) inferSigma :: SourceGrammar -> Scope -> Term -> TcM (Term,Sigma) inferSigma gr scope t = do -- GEN1 (t,ty) <- tcRho gr scope t Nothing env_tvs <- getMetaVars gr (scopeTypes scope) res_tvs <- getMetaVars gr [(scope,ty)] let forall_tvs = res_tvs \\ env_tvs quantify gr scope t forall_tvs ty checkSigma :: SourceGrammar -> Scope -> Term -> Sigma -> TcM Term checkSigma gr scope t sigma = do -- GEN2 (abs, scope, t, rho) <- skolemise id gr scope t sigma let skol_tvs = [] (t,rho) <- tcRho gr scope t (Just rho) esc_tvs <- getFreeVars gr ((scope,sigma) : scopeTypes scope) let bad_tvs = filter (`elem` esc_tvs) skol_tvs if null bad_tvs then return (abs t) else tcError (pp "Type not polymorphic enough") tcRho :: SourceGrammar -> Scope -> Term -> Maybe Rho -> TcM (Term, Rho) tcRho gr scope t@(EInt _) mb_ty = instSigma gr scope t (eval gr [] typeInt) mb_ty tcRho gr scope t@(EFloat _) mb_ty = instSigma gr scope t (eval gr [] typeFloat) mb_ty tcRho gr scope t@(K _) mb_ty = instSigma gr scope t (eval gr [] typeStr) mb_ty tcRho gr scope t@(Empty) mb_ty = instSigma gr scope t (eval gr [] typeStr) mb_ty tcRho gr scope t@(Vr v) mb_ty = do -- VAR case lookup v scope of Just v_sigma -> instSigma gr scope t v_sigma mb_ty Nothing -> tcError ("Unknown variable" <+> v) tcRho gr scope t@(Q id) mb_ty | elem (fst id) [cPredef,cPredefAbs] = case typPredefined (snd id) of Just ty -> instSigma gr scope t (eval gr [] ty) mb_ty Nothing -> tcError (pp "unknown in Predef:" <+> ppQIdent Qualified id) | otherwise = do case lookupResType gr id of Ok ty -> instSigma gr scope t (eval gr [] ty) mb_ty Bad err -> tcError (pp err) tcRho gr scope t@(QC id) mb_ty = do case lookupResType gr id of Ok ty -> instSigma gr scope t (eval gr [] ty) mb_ty Bad err -> tcError (pp err) tcRho gr scope (App fun arg) mb_ty = do -- APP (fun,fun_ty) <- tcRho gr scope fun Nothing (arg_ty, res_ty) <- unifyFun gr scope (eval gr (scopeEnv scope) arg) fun_ty arg <- checkSigma gr scope arg arg_ty instSigma gr scope (App fun arg) res_ty mb_ty tcRho gr scope (Abs bt var body) Nothing = do -- ABS1 i <- newMeta (eval gr [] typeType) (body,body_ty) <- tcRho gr ((var,VMeta i (scopeEnv scope) []):scope) body Nothing return (Abs bt var body, (VClosure (scopeEnv scope) (Prod bt identW (Meta i) (value2term gr (scopeVars scope) body_ty)))) tcRho gr scope (Abs bt var body) (Just ty) = do -- ABS2 (var_ty, body_ty) <- unifyFun gr scope (VGen (length scope) []) ty (body, body_ty) <- tcRho gr ((var,var_ty):scope) body (Just body_ty) return (Abs bt var body,ty) tcRho gr scope (Let (var, (mb_ann_ty, rhs)) body) mb_ty = do -- LET (rhs,var_ty) <- case mb_ann_ty of Nothing -> inferSigma gr scope rhs Just ann_ty -> do (ann_ty, _) <- tcRho gr scope ann_ty (Just (eval gr [] typeType)) let v_ann_ty = eval gr (scopeEnv scope) ann_ty rhs <- checkSigma gr scope rhs v_ann_ty return (rhs, v_ann_ty) (body, body_ty) <- tcRho gr ((var,var_ty):scope) body mb_ty return (Let (var, (Just (value2term gr (scopeVars scope) var_ty), rhs)) body, body_ty) tcRho gr scope (Typed body ann_ty) mb_ty = do -- ANNOT (ann_ty, _) <- tcRho gr scope ann_ty (Just (eval gr [] typeType)) let v_ann_ty = eval gr (scopeEnv scope) ann_ty body <- checkSigma gr scope body v_ann_ty instSigma gr scope (Typed body ann_ty) v_ann_ty mb_ty tcRho gr scope (FV ts) mb_ty = do case ts of [] -> do i <- newMeta (eval gr [] typeType) instSigma gr scope (FV []) (VMeta i (scopeEnv scope) []) mb_ty (t:ts) -> do (t,ty) <- tcRho gr scope t mb_ty let go [] ty = return ([],ty) go (t:ts) ty = do (t, ty) <- tcRho gr scope t (Just ty) (ts,ty) <- go ts ty return (t:ts,ty) (ts,ty) <- go ts ty return (FV (t:ts), ty) tcRho gr scope t@(Sort s) mb_ty = do instSigma gr scope t (eval gr [] typeType) mb_ty tcRho gr scope t@(RecType rs) mb_ty = do mapM_ (\(l,ty) -> tcRho gr scope ty (Just (eval gr [] typeType))) rs instSigma gr scope t (eval gr [] typeType) mb_ty tcRho gr scope t@(Table p res) mb_ty = do (p, p_ty) <- tcRho gr scope p (Just (eval gr [] typePType)) (res,res_ty) <- tcRho gr scope res Nothing subsCheckRho gr scope t res_ty (eval gr [] typeType) instSigma gr scope (Table p res) res_ty mb_ty tcRho gr scope (Prod bt x ty1 ty2) mb_ty = do (ty1,ty1_ty) <- tcRho gr scope ty1 (Just (eval gr [] typeType)) (ty2,ty2_ty) <- tcRho gr ((x,eval gr (scopeEnv scope) ty1):scope) ty2 (Just (eval gr [] typeType)) instSigma gr scope (Prod bt x ty1 ty2) (eval gr [] typeType) mb_ty tcRho gr scope (S t p) mb_ty = do p_ty <- fmap Meta $ newMeta (eval gr [] typePType) res_ty <- fmap Meta $ newMeta (eval gr [] typeType) let t_ty = eval gr (scopeEnv scope) (Table p_ty res_ty) (t,t_ty) <- tcRho gr scope t (Just t_ty) p <- checkSigma gr scope p (eval gr (scopeEnv scope) p_ty) instSigma gr scope (S t p) (eval gr (scopeEnv scope) res_ty) mb_ty tcRho gr scope (T tt ps) mb_ty = do p_ty <- case tt of TRaw -> fmap Meta $ newMeta (eval gr [] typePType) TTyped ty -> do (ty, _) <- tcRho gr scope ty (Just (eval gr [] typeType)) return ty res_ty <- fmap Meta $ newMeta (eval gr [] typeType) ps <- mapM (tcCase gr scope (eval gr (scopeEnv scope) p_ty) (eval gr (scopeEnv scope) res_ty)) ps instSigma gr scope (T (TTyped p_ty) ps) (eval gr (scopeEnv scope) (Table p_ty res_ty)) mb_ty tcRho gr scope t@(R rs) mb_ty = do lttys <- case mb_ty of Nothing -> inferRecFields gr scope rs Just ty -> case ty of VRecType ltys -> checkRecFields gr scope rs ltys VMeta _ _ _ -> inferRecFields gr scope rs _ -> tcError ("Record type is inferred but:" $$ nest 2 (ppTerm Unqualified 0 (value2term gr (scopeVars scope) ty)) $$ "is expected in the expresion:" $$ nest 2 (ppTerm Unqualified 0 t)) return (R [(l, (Just (value2term gr (scopeVars scope) ty), t)) | (l,t,ty) <- lttys], VRecType [(l, ty) | (l,t,ty) <- lttys] ) tcRho gr scope (P t l) mb_ty = do x_ty <- case mb_ty of Just ty -> return ty Nothing -> do i <- newMeta (eval gr [] typeType) return (VMeta i (scopeEnv scope) []) (t,t_ty) <- tcRho gr scope t (Just (VRecType [(l,x_ty)])) return (P t l,x_ty) tcRho gr scope (C t1 t2) mb_ty = do (t1,t1_ty) <- tcRho gr scope t1 (Just (eval gr [] typeStr)) (t2,t2_ty) <- tcRho gr scope t2 (Just (eval gr [] typeStr)) instSigma gr scope (C t1 t2) (eval gr [] typeStr) mb_ty tcRho gr scope (Glue t1 t2) mb_ty = do (t1,t1_ty) <- tcRho gr scope t1 (Just (eval gr [] typeStr)) (t2,t2_ty) <- tcRho gr scope t2 (Just (eval gr [] typeStr)) instSigma gr scope (Glue t1 t2) (eval gr [] typeStr) mb_ty tcRho gr scope t@(ExtR t1 t2) mb_ty = do (t1,t1_ty) <- tcRho gr scope t1 Nothing (t2,t2_ty) <- tcRho gr scope t2 Nothing case (t1_ty,t2_ty) of (VSort s1,VSort s2) | s1 == cType && s2 == cType -> instSigma gr scope (ExtR t1 t2) (VSort cType) mb_ty (VRecType rs1, VRecType rs2) | otherwise -> do tcWarn (pp "bbbb") instSigma gr scope (ExtR t1 t2) (VRecType (rs1 ++ rs2)) mb_ty _ -> tcError ("Cannot type check" <+> ppTerm Unqualified 0 t) tcRho gr scope (ELin cat t) mb_ty = do -- this could be done earlier, i.e. in the parser tcRho gr scope (ExtR t (R [(lockLabel cat,(Just (RecType []),R []))])) mb_ty tcRho gr scope (ELincat cat t) mb_ty = do -- this could be done earlier, i.e. in the parser tcRho gr scope (ExtR t (RecType [(lockLabel cat,RecType [])])) mb_ty tcRho gr scope (Alts t ss) mb_ty = do (t,_) <- tcRho gr scope t (Just (eval gr [] typeStr)) ss <- flip mapM ss $ \(t1,t2) -> do (t1,_) <- tcRho gr scope t1 (Just (eval gr [] typeStr)) (t2,_) <- tcRho gr scope t2 (Just (eval gr [] typeStrs)) return (t1,t2) instSigma gr scope (Alts t ss) (eval gr [] typeStr) mb_ty tcRho gr scope (Strs ss) mb_ty = do ss <- flip mapM ss $ \t -> do (t,_) <- tcRho gr scope t (Just (eval gr [] typeStr)) return t instSigma gr scope (Strs ss) (eval gr [] typeStrs) mb_ty tcRho gr scope t _ = error ("tcRho "++show t) tcCase gr scope p_ty res_ty (p,t) = do scope <- tcPatt gr scope p p_ty (t,res_ty) <- tcRho gr scope t (Just res_ty) return (p,t) tcPatt gr scope PW ty0 = return scope tcPatt gr scope (PV x) ty0 = return ((x,ty0):scope) tcPatt gr scope (PP c ps) ty0 = case lookupResType gr c of Ok ty -> do let go scope ty [] = return (scope,ty) go scope ty (p:ps) = do (arg_ty,res_ty) <- unifyFun gr scope (VGen (length scope) []) ty scope <- tcPatt gr scope p arg_ty go scope res_ty ps (scope,ty) <- go scope (eval gr [] ty) ps unify gr scope ty0 ty return scope Bad err -> tcError (pp err) tcPatt gr scope (PString s) ty0 = do unify gr scope ty0 (eval gr [] typeStr) return scope tcPatt gr scope PChar ty0 = do unify gr scope ty0 (eval gr [] typeStr) return scope tcPatt gr scope (PSeq p1 p2) ty0 = do unify gr scope ty0 (eval gr [] typeStr) scope <- tcPatt gr scope p1 (eval gr [] typeStr) scope <- tcPatt gr scope p2 (eval gr [] typeStr) return scope tcPatt gr scope (PAs x p) ty0 = do tcPatt gr ((x,ty0):scope) p ty0 tcPatt gr scope (PR rs) ty0 = do let go scope [] = return (scope,[]) go scope ((l,p):rs) = do i <- newMeta (eval gr [] typePType) let ty = VMeta i (scopeEnv scope) [] scope <- tcPatt gr scope p ty (scope,rs) <- go scope rs return (scope,(l,ty) : rs) (scope',rs) <- go scope rs unify gr scope ty0 (VRecType rs) return scope' tcPatt gr scope (PAlt p1 p2) ty0 = do tcPatt gr scope p1 ty0 tcPatt gr scope p2 ty0 return scope tcPatt gr scope p ty = unimplemented ("tcPatt "++show p) inferRecFields gr scope rs = mapM (\(l,r) -> tcRecField gr scope l r Nothing) rs checkRecFields gr scope [] ltys | null ltys = return [] | otherwise = tcError ("Missing fields:" <+> hsep (map fst ltys)) checkRecFields gr scope ((l,t):lts) ltys = case takeIt l ltys of (Just ty,ltys) -> do ltty <- tcRecField gr scope l t (Just ty) lttys <- checkRecFields gr scope lts ltys return (ltty : lttys) (Nothing,ltys) -> do tcWarn ("Discarded field:" <+> l) ltty <- tcRecField gr scope l t Nothing lttys <- checkRecFields gr scope lts ltys return lttys -- ignore the field where takeIt l1 [] = (Nothing, []) takeIt l1 (lty@(l2,ty):ltys) | l1 == l2 = (Just ty,ltys) | otherwise = let (mb_ty,ltys') = takeIt l1 ltys in (mb_ty,lty:ltys') tcRecField gr scope l (mb_ann_ty,t) mb_ty = do (t,ty) <- case mb_ann_ty of Just ann_ty -> do (ann_ty, _) <- tcRho gr scope ann_ty (Just (eval gr [] typeType)) let v_ann_ty = eval gr (scopeEnv scope) ann_ty t <- checkSigma gr scope t v_ann_ty instSigma gr scope t v_ann_ty mb_ty Nothing -> tcRho gr scope t mb_ty return (l,t,ty) -- | Invariant: if the third argument is (Just rho), -- then rho is in weak-prenex form instSigma :: SourceGrammar -> Scope -> Term -> Sigma -> Maybe Rho -> TcM (Term, Rho) instSigma gr scope t ty1 Nothing = instantiate gr t ty1 -- INST1 instSigma gr scope t ty1 (Just ty2) = do -- INST2 t <- subsCheckRho gr scope t ty1 ty2 return (t,ty2) -- | (subsCheck scope args off exp) checks that -- 'off' is at least as polymorphic as 'args -> exp' subsCheck :: SourceGrammar -> Scope -> Term -> Sigma -> Sigma -> TcM Term subsCheck gr scope t sigma1 sigma2 = do -- DEEP-SKOL (abs, scope, t, rho2) <- skolemise id gr scope t sigma2 let skol_tvs = [] t <- subsCheckRho gr scope t sigma1 rho2 esc_tvs <- getFreeVars gr [(scope,sigma1),(scope,sigma2)] let bad_tvs = filter (`elem` esc_tvs) skol_tvs if null bad_tvs then return (abs t) else tcError (vcat [pp "Subsumption check failed:", nest 2 (ppTerm Unqualified 0 (value2term gr (scopeVars scope) sigma1)), pp "is not as polymorphic as", nest 2 (ppTerm Unqualified 0 (value2term gr (scopeVars scope) sigma2))]) -- | Invariant: the second argument is in weak-prenex form subsCheckRho :: SourceGrammar -> Scope -> Term -> Sigma -> Rho -> TcM Term subsCheckRho gr scope t sigma1@(VClosure env (Prod Implicit _ _ _)) rho2 = do -- Rule SPEC (t,rho1) <- instantiate gr t sigma1 subsCheckRho gr scope t rho1 rho2 subsCheckRho gr scope t rho1 (VClosure env (Prod Explicit _ a2 r2)) = do -- Rule FUN (a1,r1) <- unifyFun gr scope (VGen (length scope) []) rho1 subsCheckFun gr scope t a1 r1 (eval gr env a2) (eval gr env r2) subsCheckRho gr scope t (VClosure env (Prod Explicit _ a1 r1)) rho2 = do -- Rule FUN (a2,r2) <- unifyFun gr scope (VGen (length scope) []) rho2 subsCheckFun gr scope t (eval gr env a1) (eval gr env r1) a2 r2 subsCheckRho gr scope t (VSort s1) (VSort s2) | s1 == cPType && s2 == cType = return t subsCheckRho gr scope t tau1 tau2 = do -- Rule MONO unify gr scope tau1 tau2 -- Revert to ordinary unification return t subsCheckFun :: SourceGrammar -> Scope -> Term -> Sigma -> Rho -> Sigma -> Rho -> TcM Term subsCheckFun gr scope t a1 r1 a2 r2 = do let v = newVar scope vt <- subsCheck gr scope (Vr v) a2 a1 t <- subsCheckRho gr ((v,eval gr [] typeType):scope) (App t vt) r1 r2 ; return (Abs Explicit v t) ----------------------------------------------------------------------- -- Unification ----------------------------------------------------------------------- unifyFun :: SourceGrammar -> Scope -> Value -> Rho -> TcM (Sigma, Rho) unifyFun gr scope arg_v (VClosure env (Prod Explicit x arg res)) | x /= identW = return (eval gr env arg,eval gr ((x,arg_v):env) res) | otherwise = return (eval gr env arg,eval gr env res) unifyFun gr scope arg_v tau = do arg_ty <- newMeta (eval gr [] typeType) res_ty <- newMeta (eval gr [] typeType) unify gr scope tau (VClosure [] (Prod Explicit identW (Meta arg_ty) (Meta res_ty))) return (VMeta arg_ty [] [], VMeta res_ty [] []) unify gr scope (VApp f1 vs1) (VApp f2 vs2) | f1 == f2 = sequence_ (zipWith (unify gr scope) vs1 vs2) unify gr scope (VSort s1) (VSort s2) | s1 == s2 = return () unify gr scope (VGen i vs1) (VGen j vs2) | i == j = sequence_ (zipWith (unify gr scope) vs1 vs2) unify gr scope (VMeta i env1 vs1) (VMeta j env2 vs2) | i == j = sequence_ (zipWith (unify gr scope) vs1 vs2) | otherwise = do mv <- getMeta j case mv of Bound t2 -> unify gr scope (VMeta i env1 vs1) (apply gr env2 t2 vs2) Unbound _ -> setMeta i (Bound (Meta j)) unify gr scope (VMeta i env vs) v = unifyVar gr scope i env vs v unify gr scope v (VMeta i env vs) = unifyVar gr scope i env vs v unify gr scope (VTblType p1 res1) (VTblType p2 res2) = do unify gr scope p1 p2 unify gr scope res1 res2 unify gr scope (VRecType rs1) (VRecType rs2) = do sequence_ [unify gr scope ty1 ty2 | (l,ty1) <- rs1, Just ty2 <- [lookup l rs2]] unify gr scope v1 v2 = do t1 <- zonkTerm (value2term gr (scopeVars scope) v1) t2 <- zonkTerm (value2term gr (scopeVars scope) v2) tcError ("Cannot unify types:" <+> (ppTerm Unqualified 0 t1 $$ ppTerm Unqualified 0 t2)) -- | Invariant: tv1 is a flexible type variable unifyVar :: SourceGrammar -> Scope -> MetaId -> Env -> [Value] -> Tau -> TcM () unifyVar gr scope i env vs ty2 = do -- Check whether i is bound mv <- getMeta i case mv of Bound ty1 -> unify gr scope (apply gr env ty1 vs) ty2 Unbound _ -> do let ty2' = value2term gr (scopeVars scope) ty2 ms2 <- getMetaVars gr [(scope,ty2)] if i `elem` ms2 then tcError ("Occurs check for" <+> ppMeta i <+> "in:" $$ nest 2 (ppTerm Unqualified 0 ty2')) else setMeta i (Bound ty2') ----------------------------------------------------------------------- -- Instantiation and quantification ----------------------------------------------------------------------- -- | Instantiate the topmost for-alls of the argument type -- with metavariables instantiate :: SourceGrammar -> Term -> Sigma -> TcM (Term,Rho) instantiate gr t (VClosure env (Prod Implicit x ty1 ty2)) = do i <- newMeta (eval gr env ty1) instantiate gr (App t (ImplArg (Meta i))) (eval gr ((x,VMeta i [] []):env) ty2) instantiate gr t ty = do return (t,ty) skolemise f gr scope t (VClosure env (Prod Implicit x arg_ty res_ty)) -- Rule PRPOLY | x /= identW = let (y,body) = case t of Abs Implicit y body -> (y, body) body -> (newVar scope, body) in skolemise (f . Abs Implicit y) gr ((y,eval gr env arg_ty):scope) body (eval gr ((x,VGen (length scope) []):env) res_ty) skolemise f gr scope t (VClosure env (Prod Explicit x arg_ty res_ty)) -- Rule PRFUN | x /= identW = let (y,body) = case t of Abs Explicit y body -> (y, body) body -> let y = newVar scope in (y, App body (Vr y)) in skolemise (f . Abs Explicit y) gr ((y,eval gr env arg_ty):scope) body (eval gr ((x,VGen (length scope) []):env) res_ty) skolemise f gr scope t ty -- Rule PRMONO = return (f, scope, t, ty) -- | Quantify over the specified type variables (all flexible) quantify :: SourceGrammar -> Scope -> Term -> [MetaId] -> Rho -> TcM (Term,Sigma) quantify gr scope t tvs ty0 = do mapM_ bind (tvs `zip` new_bndrs) -- 'bind' is just a cunning way ty <- zonkTerm ty -- of doing the substitution return (foldr (Abs Implicit) t new_bndrs ,eval gr [] (foldr (\v ty -> Prod Implicit v typeType ty) ty new_bndrs) ) where ty = value2term gr (scopeVars scope) ty0 used_bndrs = nub (bndrs ty) -- Avoid quantified type variables in use new_bndrs = take (length tvs) (allBinders \\ used_bndrs) bind (i, name) = setMeta i (Bound (Vr name)) bndrs (Prod _ x t1 t2) = [x] ++ bndrs t1 ++ bndrs t2 bndrs _ = [] allBinders :: [Ident] -- a,b,..z, a1, b1,... z1, a2, b2,... allBinders = [ identS [x] | x <- ['a'..'z'] ] ++ [ identS (x : show i) | i <- [1 :: Integer ..], x <- ['a'..'z']] ----------------------------------------------------------------------- -- The Monad ----------------------------------------------------------------------- type Scope = [(Ident,Value)] type Sigma = Value type Rho = Value -- No top-level ForAll type Tau = Value -- No ForAlls anywhere data MetaValue = Unbound Sigma | Bound Term type MetaStore = IntMap.IntMap MetaValue data TcResult a = TcOk a MetaStore [Message] | TcFail [Message] -- First msg is error, the rest are warnings? newtype TcM a = TcM {unTcM :: MetaStore -> [Message] -> TcResult a} instance Monad TcM where return x = TcM (\ms msgs -> TcOk x ms msgs) f >>= g = TcM (\ms msgs -> case unTcM f ms msgs of TcOk x ms msgs -> unTcM (g x) ms msgs TcFail msgs -> TcFail msgs) fail = tcError . pp instance Applicative TcM where pure = return (<*>) = ap instance Functor TcM where fmap f g = TcM (\ms msgs -> case unTcM g ms msgs of TcOk x ms msgs -> TcOk (f x) ms msgs TcFail msgs -> TcFail msgs) tcError :: Message -> TcM a tcError msg = TcM (\ms msgs -> TcFail (msg : msgs)) tcWarn :: Message -> TcM () tcWarn msg = TcM (\ms msgs -> TcOk () ms (("Warning:" <+> msg) : msgs)) unimplemented str = fail ("Unimplemented: "++str) runTcM :: TcM a -> Check a runTcM f = case unTcM f IntMap.empty [] of TcOk x _ msgs -> do checkWarnings msgs; return x TcFail (msg:msgs) -> do checkWarnings msgs; checkError msg newMeta :: Sigma -> TcM MetaId newMeta ty = TcM (\ms msgs -> let i = IntMap.size ms in TcOk i (IntMap.insert i (Unbound ty) ms) msgs) getMeta :: MetaId -> TcM MetaValue getMeta i = TcM (\ms msgs -> case IntMap.lookup i ms of Just mv -> TcOk mv ms msgs Nothing -> TcFail (("Unknown metavariable" <+> ppMeta i) : msgs)) setMeta :: MetaId -> MetaValue -> TcM () setMeta i mv = TcM (\ms msgs -> TcOk () (IntMap.insert i mv ms) msgs) newVar :: Scope -> Ident newVar scope = head [x | i <- [1..], let x = identS ('v':show i), isFree scope x] where isFree [] x = True isFree ((y,_):scope) x = x /= y && isFree scope x scopeEnv scope = zipWith (\(x,ty) i -> (x,VGen i [])) (reverse scope) [0..] scopeVars scope = map fst scope scopeTypes scope = zipWith (\(_,ty) scope -> (scope,ty)) scope (tails scope) -- | This function takes account of zonking, and returns a set -- (no duplicates) of unbound meta-type variables getMetaVars :: SourceGrammar -> [(Scope,Sigma)] -> TcM [MetaId] getMetaVars gr sc_tys = do tys <- mapM (\(scope,ty) -> zonkTerm (value2term gr (scopeVars scope) ty)) sc_tys return (foldr go [] tys) where -- Get the MetaIds from a term; no duplicates in result go (Vr tv) acc = acc go (Meta i) acc | i `elem` acc = acc | otherwise = i : acc go (Q _) acc = acc go (QC _) acc = acc go (Sort _) acc = acc go (Prod _ _ arg res) acc = go arg (go res acc) go (Table p t) acc = go p (go t acc) go (RecType rs) acc = foldl (\acc (l,ty) -> go ty acc) acc rs go t acc = error ("go "++show t) -- | This function takes account of zonking, and returns a set -- (no duplicates) of free type variables getFreeVars :: SourceGrammar -> [(Scope,Sigma)] -> TcM [Ident] getFreeVars gr sc_tys = do tys <- mapM (\(scope,ty) -> zonkTerm (value2term gr (scopeVars scope) ty)) sc_tys return (foldr (go []) [] tys) where go bound (Vr tv) acc | tv `elem` bound = acc | tv `elem` acc = acc | otherwise = tv : acc go bound (Meta _) acc = acc go bound (Q _) acc = acc go bound (QC _) acc = acc go bound (Prod _ x arg res) acc = go bound arg (go (x : bound) res acc) go bound (RecType rs) acc = foldl (\acc (l,ty) -> go bound ty acc) acc rs go bound (Table p t) acc = go bound p (go bound t acc) -- | Eliminate any substitutions in a term zonkTerm :: Term -> TcM Term zonkTerm (Meta i) = do mv <- getMeta i case mv of Unbound _ -> return (Meta i) Bound t -> do t <- zonkTerm t setMeta i (Bound t) -- "Short out" multiple hops return t zonkTerm t = composOp zonkTerm t