{-| Module : Idris.Core.Evaluate Description : Evaluate Idris expressions. License : BSD3 Maintainer : The Idris Community. -} {-# LANGUAGE BangPatterns, DeriveGeneric, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-} {-# OPTIONS_GHC -fwarn-incomplete-patterns #-} {-# OPTIONS_GHC -fwarn-unused-imports #-} module Idris.Core.Evaluate(normalise, normaliseTrace, normaliseC, normaliseAll, normaliseBlocking, toValue, quoteTerm, rt_simplify, simplify, inlineSmall, specialise, unfold, convEq, convEq', Def(..), CaseInfo(..), CaseDefs(..), Accessibility(..), Injectivity, Totality(..), TTDecl, PReason(..), MetaInformation(..), Context, initContext, ctxtAlist, next_tvar, addToCtxt, setAccess, setInjective, setTotal, setRigCount, setMetaInformation, addCtxtDef, addTyDecl, addDatatype, addCasedef, simplifyCasedef, addOperator, lookupNames, lookupTyName, lookupTyNameExact, lookupTy, lookupTyExact, lookupP, lookupP_all, lookupDef, lookupNameDef, lookupDefExact, lookupDefAcc, lookupDefAccExact, lookupVal, mapDefCtxt, tcReducible, lookupTotalAccessibility, lookupTotal, lookupTotalExact, lookupInjectiveExact, lookupRigCount, lookupRigCountExact, lookupNameTotal, lookupMetaInformation, lookupTyEnv, isTCDict, isCanonical, isDConName, canBeDConName, isTConName, isConName, isFnName, conGuarded, Value(..), Quote(..), initEval, uniqueNameCtxt, uniqueBindersCtxt, definitions, visibleDefinitions, isUniverse, linearCheck, linearCheckArg) where import Idris.Core.CaseTree import Idris.Core.TT import Control.Monad.State import Data.List import Data.Maybe (listToMaybe) import GHC.Generics (Generic) import qualified Data.Map.Strict as Map data EvalState = ES { limited :: [(Name, Int)], nexthole :: Int, blocking :: Bool } deriving Show type Eval a = State EvalState a data EvalOpt = Spec | Simplify Bool -- ^ whether to expand lets or not | AtREPL | RunTT | Unfold deriving (Show, Eq) initEval = ES [] 0 False -- VALUES (as HOAS) --------------------------------------------------------- -- | A HOAS representation of values data Value = VP NameType Name Value | VV Int -- True for Bool indicates safe to reduce | VBind Bool Name (Binder Value) (Value -> Eval Value) -- For frozen let bindings when simplifying | VBLet RigCount Int Name Value Value Value | VApp Value Value | VType UExp | VUType Universe | VErased | VImpossible | VConstant Const | VProj Value Int -- | VLazy Env [Value] Term | VTmp Int canonical :: Value -> Bool canonical (VP (DCon _ _ _) _ _) = True canonical (VP (TCon _ _) _ _) = True canonical (VApp f a) = canonical f canonical (VConstant _) = True canonical (VType _) = True canonical (VUType _) = True canonical VErased = True canonical _ = False instance Show Value where show x = show $ evalState (quote 100 x) initEval instance Show (a -> b) where show x = "<>" -- THE EVALUATOR ------------------------------------------------------------ -- The environment is assumed to be "locally named" - i.e., not de Bruijn -- indexed. -- i.e. it's an intermediate environment that we have while type checking or -- while building a proof. -- | Normalise fully type checked terms (so, assume all names/let bindings resolved) normaliseC :: Context -> Env -> TT Name -> TT Name normaliseC ctxt env t = evalState (do val <- eval False ctxt [] (map finalEntry env) t [] quote 0 val) initEval -- | Normalise everything, whether abstract, private or public normaliseAll :: Context -> Env -> TT Name -> TT Name normaliseAll ctxt env t = evalState (do val <- eval False ctxt [] (map finalEntry env) t [AtREPL] quote 0 val) initEval -- | As normaliseAll, but with an explicit list of names *not* to reduce normaliseBlocking :: Context -> Env -> [Name] -> TT Name -> TT Name normaliseBlocking ctxt env blocked t = evalState (do val <- eval False ctxt (map (\n -> (n, 0)) blocked) (map finalEntry env) t [AtREPL] quote 0 val) initEval normalise :: Context -> Env -> TT Name -> TT Name normalise = normaliseTrace False normaliseTrace :: Bool -> Context -> Env -> TT Name -> TT Name normaliseTrace tr ctxt env t = evalState (do val <- eval tr ctxt [] (map finalEntry env) (finalise t) [] quote 0 val) initEval toValue :: Context -> Env -> TT Name -> Value toValue ctxt env t = evalState (eval False ctxt [] (map finalEntry env) t []) initEval quoteTerm :: Value -> TT Name quoteTerm val = evalState (quote 0 val) initEval -- Return a specialised name, and an updated list of reductions available, -- so that the caller can tell how much specialisation was achieved. specialise :: Context -> Env -> [(Name, Int)] -> TT Name -> (TT Name, [(Name, Int)]) specialise ctxt env limits t = let (tm, st) = runState (do val <- eval False ctxt [] (map finalEntry env) (finalise t) [Spec] quote 0 val) (initEval { limited = limits }) in (tm, limited st) -- | Like normalise, but we only reduce functions that are marked as okay to -- inline, and lets simplify :: Context -> Env -> TT Name -> TT Name simplify ctxt env t = evalState (do val <- eval False ctxt [(sUN "lazy", 0), (sUN "force", 0), (sUN "Force", 0), (sUN "assert_smaller", 0), (sUN "assert_total", 0), (sUN "par", 0), (sUN "prim__syntactic_eq", 0), (sUN "fork", 0)] (map finalEntry env) (finalise t) [Simplify True] quote 0 val) initEval -- | Like simplify, but we only reduce functions that are marked as okay to -- inline, and don't reduce lets inlineSmall :: Context -> Env -> TT Name -> TT Name inlineSmall ctxt env t = evalState (do val <- eval False ctxt [] (map finalEntry env) (finalise t) [Simplify False] quote 0 val) initEval -- | Simplify for run-time (i.e. basic inlining) rt_simplify :: Context -> Env -> TT Name -> TT Name rt_simplify ctxt env t = evalState (do val <- eval False ctxt [(sUN "lazy", 0), (sUN "force", 0), (sUN "Force", 0), (sUN "par", 0), (sUN "prim__syntactic_eq", 0), (sUN "prim_fork", 0)] (map finalEntry env) (finalise t) [RunTT] quote 0 val) initEval -- | Unfold the given names in a term, the given number of times in a stack. -- Preserves 'let'. -- This is primarily to support inlining of the given names, and can also -- help with partial evaluation by allowing a rescursive definition to be -- unfolded once only. -- Specifically used to unfold definitions using interfaces before going to -- the totality checker (otherwise mutually recursive definitions in -- implementations will not work...) unfold :: Context -> Env -> [(Name, Int)] -> TT Name -> TT Name unfold ctxt env ns t = evalState (do val <- eval False ctxt ns (map finalEntry env) (finalise t) [Unfold] quote 0 val) initEval -- unbindEnv env (quote 0 (eval ctxt (bindEnv env t))) finalEntry :: (Name, RigCount, Binder (TT Name)) -> (Name, RigCount, Binder (TT Name)) finalEntry (n, r, b) = (n, r, fmap finalise b) usable :: Bool -- specialising -> Bool -- unfolding only -> Int -- Reduction depth limit (when simplifying/at REPL) -> Name -> [(Name, Int)] -> Eval (Bool, [(Name, Int)]) -- usable _ _ ns@((MN 0 "STOP", _) : _) = return (False, ns) usable False uf depthlimit n [] = return (True, []) usable True uf depthlimit n ns = do ES ls num b <- get if b then return (False, ns) else case lookup n ls of Just 0 -> return (False, ns) Just i -> return (True, ns) _ -> return (False, ns) usable False uf depthlimit n ns = case lookup n ns of Just 0 -> return (False, ns) Just i -> return $ (True, (n, abs (i-1)) : filter (\ (n', _) -> n/=n') ns) _ -> return $ if uf then (False, ns) else (True, (n, depthlimit) : filter (\ (n', _) -> n/=n') ns) fnCount :: Int -> Name -> Eval () fnCount inc n = do ES ls num b <- get case lookup n ls of Just i -> do put $ ES ((n, (i - inc)) : filter (\ (n', _) -> n/=n') ls) num b _ -> return () setBlock :: Bool -> Eval () setBlock b = do ES ls num _ <- get put (ES ls num b) deduct = fnCount 1 reinstate = fnCount (-1) -- | Evaluate in a context of locally named things (i.e. not de Bruijn indexed, -- such as we might have during construction of a proof) -- The (Name, Int) pair in the arguments is the maximum depth of unfolding of -- a name. The corresponding pair in the state is the maximum number of -- unfoldings overall. eval :: Bool -> Context -> [(Name, Int)] -> Env -> TT Name -> [EvalOpt] -> Eval Value eval traceon ctxt ntimes genv tm opts = ev ntimes [] True [] tm where spec = Spec `elem` opts simpl = Simplify True `elem` opts || Simplify False `elem` opts simpl_inline = Simplify False `elem` opts runtime = RunTT `elem` opts atRepl = AtREPL `elem` opts unfold = Unfold `elem` opts noFree = all canonical . map snd -- returns 'True' if the function should block -- normal evaluation should return false blockSimplify (CaseInfo inl always dict) n stk | runtime = if always then False else not (inl || dict) || elem n stk | simpl = (not inl || elem n stk) || (n == sUN "prim__syntactic_eq") | otherwise = False getCases cd | simpl = cases_compiletime cd | runtime = cases_runtime cd | otherwise = cases_compiletime cd ev ntimes stk top env (P _ n ty) | Just (Let _ t v) <- lookupBinder n genv = ev ntimes stk top env v ev ntimes_in stk top env (P Ref n ty) = do let limit = if simpl then 100 else 10000 (u, ntimes) <- usable spec unfold limit n ntimes_in let red = u && (tcReducible n ctxt || spec || (atRepl && noFree env) || runtime || unfold || sUN "assert_total" `elem` stk) if red then do let val = lookupDefAccExact n (spec || unfold || (atRepl && noFree env) || runtime) ctxt case val of Just (Function _ tm, Public) -> ev ntimes (n:stk) True env tm Just (TyDecl nt ty, _) -> do vty <- ev ntimes stk True env ty return $ VP nt n vty Just (CaseOp ci _ _ _ _ cd, acc) | (acc == Public || acc == Hidden) && -- || sUN "assert_total" `elem` stk) && null (fst (cases_compiletime cd)) -> -- unoptimised version let (ns, tree) = getCases cd in if blockSimplify ci n stk then liftM (VP Ref n) (ev ntimes stk top env ty) else -- traceWhen runtime (show (n, ns, tree)) $ do c <- evCase ntimes n (n:stk) top env ns [] tree case c of (Nothing, _) -> liftM (VP Ref n) (ev ntimes stk top env ty) (Just v, _) -> return v _ -> liftM (VP Ref n) (ev ntimes stk top env ty) else liftM (VP Ref n) (ev ntimes stk top env ty) ev ntimes stk top env (P nt n ty) = liftM (VP nt n) (ev ntimes stk top env ty) ev ntimes stk top env (V i) | i < length env && i >= 0 = return $ snd (env !! i) | otherwise = return $ VV i ev ntimes stk top env (Bind n (Let c t v) sc) | (not (runtime || simpl_inline || unfold)) || occurrences n sc < 2 = do v' <- ev ntimes stk top env v --(finalise v) sc' <- ev ntimes stk top ((n, v') : env) sc wknV (-1) sc' | otherwise = do t' <- ev ntimes stk top env t v' <- ev ntimes stk top env v --(finalise v) -- use Tmp as a placeholder, then make it a variable reference -- again when evaluation finished hs <- get let vd = nexthole hs put (hs { nexthole = vd + 1 }) sc' <- ev ntimes stk top ((n, VP Bound (sMN vd "vlet") VErased) : env) sc return $ VBLet c vd n t' v' sc' ev ntimes stk top env (Bind n (NLet t v) sc) = do t' <- ev ntimes stk top env (finalise t) v' <- ev ntimes stk top env (finalise v) sc' <- ev ntimes stk top ((n, v') : env) sc return $ VBind True n (Let RigW t' v') (\x -> return sc') ev ntimes stk top env (Bind n b sc) = do b' <- vbind env b let n' = uniqueName n (map fstEnv genv ++ map fst env) return $ VBind True -- (vinstances 0 sc < 2) n' b' (\x -> ev ntimes stk False ((n', x):env) sc) where vbind env t = fmapMB (\tm -> ev ntimes stk top env (finalise tm)) t -- block reduction immediately under codata (and not forced) ev ntimes stk top env (App _ (App _ (App _ d@(P _ (UN dly) _) l@(P _ (UN lco) _)) t) arg) | dly == txt "Delay" && lco == txt "Infinite" && not (unfold || simpl) = do let (f, _) = unApply arg let ntimes' = case f of P _ fn _ -> (fn, 0) : ntimes _ -> ntimes when spec $ setBlock True d' <- ev ntimes' stk False env d l' <- ev ntimes' stk False env l t' <- ev ntimes' stk False env t arg' <- ev ntimes' stk False env arg when spec $ setBlock False evApply ntimes' stk top env [l',t',arg'] d' -- Treat "assert_total" specially, as long as it's defined! ev ntimes stk top env (App _ (App _ (P _ n@(UN at) _) _) arg) | Just (CaseOp _ _ _ _ _ _, _) <- lookupDefAccExact n (spec || (atRepl && noFree env)|| runtime) ctxt, at == txt "assert_total" && not (simpl || unfold) = ev ntimes (n : stk) top env arg ev ntimes stk top env (App _ f a) = do f' <- ev ntimes stk False env f a' <- ev ntimes stk False env a evApply ntimes stk top env [a'] f' ev ntimes stk top env (Proj t i) = do -- evaluate dictionaries if it means the projection works t' <- ev ntimes stk top env t -- tfull' <- reapply ntimes stk top env t' [] return (doProj t' (getValArgs t')) where doProj t' (VP (DCon _ _ _) _ _, args) | i >= 0 && i < length args = args!!i doProj t' _ = VProj t' i ev ntimes stk top env (Constant c) = return $ VConstant c ev ntimes stk top env Erased = return VErased ev ntimes stk top env Impossible = return VImpossible ev ntimes stk top env (Inferred tm) = ev ntimes stk top env tm ev ntimes stk top env (TType i) = return $ VType i ev ntimes stk top env (UType u) = return $ VUType u evApply ntimes stk top env args (VApp f a) = evApply ntimes stk top env (a:args) f evApply ntimes stk top env args f = apply ntimes stk top env f args apply ntimes stk top env (VBind True n (Lam _ t) sc) (a:as) = do a' <- sc a app <- apply ntimes stk top env a' as wknV 1 app apply ntimes_in stk top env f@(VP Ref n ty) args = do let limit = if simpl then 100 else 10000 (u, ntimes) <- usable spec unfold limit n ntimes_in let red = u && (tcReducible n ctxt || spec || (atRepl && noFree env) || unfold || runtime || sUN "assert_total" `elem` stk) if red then do let val = lookupDefAccExact n (spec || unfold || (atRepl && noFree env) || runtime) ctxt case val of Just (CaseOp ci _ _ _ _ cd, acc) | acc == Public || acc == Hidden -> -- unoptimised version let (ns, tree) = getCases cd in if blockSimplify ci n stk then return $ unload env (VP Ref n ty) args else -- traceWhen runtime (show (n, ns, tree)) $ do c <- evCase ntimes n (n:stk) top env ns args tree case c of (Nothing, _) -> return $ unload env (VP Ref n ty) args (Just v, rest) -> evApply ntimes stk top env rest v Just (Operator _ i op, _) -> if (i <= length args) then case op (take i args) of Nothing -> return $ unload env (VP Ref n ty) args Just v -> evApply ntimes stk top env (drop i args) v else return $ unload env (VP Ref n ty) args _ -> case args of [] -> return f _ -> return $ unload env f args else case args of (a : as) -> return $ unload env f (a:as) [] -> return f apply ntimes stk top env f (a:as) = return $ unload env f (a:as) apply ntimes stk top env f [] = return f -- specApply stk env f@(VP Ref n ty) args -- = case lookupCtxt n statics of -- [as] -> if or as -- then trace (show (n, map fst (filter (\ (_, s) -> s) (zip args as)))) $ -- return $ unload env f args -- else return $ unload env f args -- _ -> return $ unload env f args -- specApply stk env f args = return $ unload env f args unload :: [(Name, Value)] -> Value -> [Value] -> Value unload env f [] = f unload env f (a:as) = unload env (VApp f a) as evCase ntimes n stk top env ns args tree | length ns <= length args = do let args' = take (length ns) args let rest = drop (length ns) args when spec $ deduct n t <- evTree ntimes stk top env (zip ns args') tree when spec $ case t of Nothing -> reinstate n -- Blocked, count n again Just _ -> return () -- (zipWith (\n , t) -> (n, t)) ns args') tree return (t, rest) | otherwise = return (Nothing, args) evTree :: [(Name, Int)] -> [Name] -> Bool -> [(Name, Value)] -> [(Name, Value)] -> SC -> Eval (Maybe Value) evTree ntimes stk top env amap (UnmatchedCase str) = return Nothing evTree ntimes stk top env amap (STerm tm) = do let etm = pToVs (map fst amap) tm etm' <- ev ntimes stk (not (conHeaded tm)) (amap ++ env) etm return $ Just etm' evTree ntimes stk top env amap (ProjCase t alts) = do t' <- ev ntimes stk top env t doCase ntimes stk top env amap t' alts evTree ntimes stk top env amap (Case _ n alts) = case lookup n amap of Just v -> doCase ntimes stk top env amap v alts _ -> return Nothing evTree ntimes stk top env amap ImpossibleCase = return Nothing doCase ntimes stk top env amap v alts = do c <- chooseAlt env v (getValArgs v) alts amap case c of Just (altmap, sc) -> evTree ntimes stk top env altmap sc _ -> do c' <- chooseAlt' ntimes stk env v (getValArgs v) alts amap case c' of Just (altmap, sc) -> evTree ntimes stk top env altmap sc _ -> return Nothing conHeaded tm@(App _ _ _) | (P (DCon _ _ _) _ _, args) <- unApply tm = True conHeaded t = False chooseAlt' ntimes stk env _ (f, args) alts amap = do f' <- apply ntimes stk True env f args chooseAlt env f' (getValArgs f') alts amap chooseAlt :: [(Name, Value)] -> Value -> (Value, [Value]) -> [CaseAlt] -> [(Name, Value)] -> Eval (Maybe ([(Name, Value)], SC)) chooseAlt env _ (VP (DCon i a _) _ _, args) alts amap | Just (ns, sc) <- findTag i alts = return $ Just (updateAmap (zip ns args) amap, sc) | Just v <- findDefault alts = return $ Just (amap, v) chooseAlt env _ (VP (TCon i a) _ _, args) alts amap | Just (ns, sc) <- findTag i alts = return $ Just (updateAmap (zip ns args) amap, sc) | Just v <- findDefault alts = return $ Just (amap, v) chooseAlt env _ (VConstant c, []) alts amap | Just v <- findConst c alts = return $ Just (amap, v) | Just (n', sub, sc) <- findSuc c alts = return $ Just (updateAmap [(n',sub)] amap, sc) | Just v <- findDefault alts = return $ Just (amap, v) chooseAlt env _ (VP _ n _, args) alts amap | Just (ns, sc) <- findFn n alts = return $ Just (updateAmap (zip ns args) amap, sc) chooseAlt env _ (VBind _ _ (Pi _ i s k) t, []) alts amap | Just (ns, sc) <- findFn (sUN "->") alts = do t' <- t (VV 0) -- we know it's not in scope or it's not a pattern return $ Just (updateAmap (zip ns [s, t']) amap, sc) chooseAlt _ _ _ alts amap | Just v <- findDefault alts = if (any fnCase alts) then return $ Just (amap, v) else return Nothing | otherwise = return Nothing fnCase (FnCase _ _ _) = True fnCase _ = False -- Replace old variable names in the map with new matches -- (This is possibly unnecessary since we make unique names and don't -- allow repeated variables...?) updateAmap newm amap = newm ++ filter (\ (x, _) -> not (elem x (map fst newm))) amap findTag i [] = Nothing findTag i (ConCase n j ns sc : xs) | i == j = Just (ns, sc) findTag i (_ : xs) = findTag i xs findFn fn [] = Nothing findFn fn (FnCase n ns sc : xs) | fn == n = Just (ns, sc) findFn fn (_ : xs) = findFn fn xs findDefault [] = Nothing findDefault (DefaultCase sc : xs) = Just sc findDefault (_ : xs) = findDefault xs findSuc c [] = Nothing findSuc (BI val) (SucCase n sc : _) | val /= 0 = Just (n, VConstant (BI (val - 1)), sc) findSuc c (_ : xs) = findSuc c xs findConst c [] = Nothing findConst c (ConstCase c' v : xs) | c == c' = Just v findConst (AType (ATInt ITNative)) (ConCase n 1 [] v : xs) = Just v findConst (AType ATFloat) (ConCase n 2 [] v : xs) = Just v findConst (AType (ATInt ITChar)) (ConCase n 3 [] v : xs) = Just v findConst StrType (ConCase n 4 [] v : xs) = Just v findConst (AType (ATInt ITBig)) (ConCase n 6 [] v : xs) = Just v findConst (AType (ATInt (ITFixed ity))) (ConCase n tag [] v : xs) | tag == 7 + fromEnum ity = Just v findConst c (_ : xs) = findConst c xs getValArgs tm = getValArgs' tm [] getValArgs' (VApp f a) as = getValArgs' f (a:as) getValArgs' f as = (f, as) -- tmpToV i vd (VLetHole j) | vd == j = return $ VV i -- tmpToV i vd (VP nt n v) = liftM (VP nt n) (tmpToV i vd v) -- tmpToV i vd (VBind n b sc) = do b' <- fmapMB (tmpToV i vd) b -- let sc' = \x -> do x' <- sc x -- tmpToV (i + 1) vd x' -- return (VBind n b' sc') -- tmpToV i vd (VApp f a) = liftM2 VApp (tmpToV i vd f) (tmpToV i vd a) -- tmpToV i vd x = return x instance Eq Value where (==) x y = getTT x == getTT y where getTT v = evalState (quote 0 v) initEval class Quote a where quote :: Int -> a -> Eval (TT Name) instance Quote Value where quote i (VP nt n v) = liftM (P nt n) (quote i v) quote i (VV x) = return $ V x quote i (VBind _ n b sc) = do sc' <- sc (VTmp i) b' <- quoteB b liftM (Bind n b') (quote (i+1) sc') where quoteB t = fmapMB (quote i) t quote i (VBLet c vd n t v sc) = do sc' <- quote i sc t' <- quote i t v' <- quote i v let sc'' = pToV (sMN vd "vlet") (addBinder sc') return (Bind n (Let c t' v') sc'') quote i (VApp f a) = liftM2 (App MaybeHoles) (quote i f) (quote i a) quote i (VType u) = return (TType u) quote i (VUType u) = return (UType u) quote i VErased = return Erased quote i VImpossible = return Impossible quote i (VProj v j) = do v' <- quote i v return (Proj v' j) quote i (VConstant c) = return $ Constant c quote i (VTmp x) = return $ V (i - x - 1) wknV :: Int -> Value -> Eval Value wknV i (VV x) | x >= i = return $ VV (x - 1) wknV i (VBind red n b sc) = do b' <- fmapMB (wknV i) b return $ VBind red n b' (\x -> do x' <- sc x wknV (i + 1) x') wknV i (VApp f a) = liftM2 VApp (wknV i f) (wknV i a) wknV i t = return t isUniverse :: Term -> Bool isUniverse (TType _) = True isUniverse (UType _) = True isUniverse _ = False isUsableUniverse :: Term -> Bool isUsableUniverse (UType NullType) = False isUsableUniverse x = isUniverse x convEq' ctxt hs x y = evalStateT (convEq ctxt hs x y) (0, []) convEq :: Context -> [Name] -> TT Name -> TT Name -> StateT UCs TC Bool convEq ctxt holes topx topy = ceq [] topx topy where ceq :: [(Name, Name)] -> TT Name -> TT Name -> StateT UCs TC Bool ceq ps (P xt x _) (P yt y _) | x `elem` holes || y `elem` holes = return True | x == y || (x, y) `elem` ps || (y,x) `elem` ps = return True | otherwise = sameDefs ps x y ceq ps (Bind n (PVar _ t) sc) y = ceq ps sc y ceq ps x (Bind n (PVar _ t) sc) = ceq ps x sc ceq ps (Bind n (PVTy t) sc) y = ceq ps sc y ceq ps x (Bind n (PVTy t) sc) = ceq ps x sc ceq ps (V x) (V y) = return (x == y) ceq ps (V x) (P _ y _) | x >= 0 && length ps > x = return (fst (ps!!x) == y) | otherwise = return False ceq ps (P _ x _) (V y) | y >= 0 && length ps > y = return (x == snd (ps!!y)) | otherwise = return False ceq ps (Bind n xb xs) (Bind n' yb ys) = liftM2 (&&) (ceqB ps xb yb) (ceq ((n,n'):ps) xs ys) where ceqB ps (Let c v t) (Let c' v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t') ceqB ps (Guess v t) (Guess v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t') ceqB ps (Pi r i v t) (Pi r' i' v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t') ceqB ps b b' = ceq ps (binderTy b) (binderTy b') ceq ps x (Bind n (Lam _ t) (App _ y (V 0))) = ceq ps x (substV (P Bound n t) y) ceq ps (Bind n (Lam _ t) (App _ x (V 0))) y = ceq ps (substV (P Bound n t) x) y ceq ps x (Bind n (Lam _ t) (App _ y (P Bound n' _))) | n == n' = ceq ps x y ceq ps (Bind n (Lam _ t) (App _ x (P Bound n' _))) y | n == n' = ceq ps x y -- Special case for 'case' blocks - size of scope causes complications, -- we only want to check the blocks themselves are valid and identical -- in the current scope. So, just check the bodies, and the additional -- arguments the case blocks are applied to. ceq ps x@(App _ _ _) y@(App _ _ _) | (P _ cx _, xargs) <- unApply x, (P _ cy _, yargs) <- unApply y, caseName cx && caseName cy = sameCase ps cx cy xargs yargs ceq ps (App _ fx ax) (App _ fy ay) = liftM2 (&&) (ceq ps fx fy) (ceq ps ax ay) ceq ps (Constant x) (Constant y) = return (x == y) ceq ps (TType x) (TType y) | x == y = return True ceq ps (TType (UVal 0)) (TType y) = return True ceq ps (TType x) (TType y) = do (v, cs) <- get put (v, ULE x y : cs) return True ceq ps (UType AllTypes) x = return (isUsableUniverse x) ceq ps x (UType AllTypes) = return (isUsableUniverse x) ceq ps (UType u) (UType v) = return (u == v) ceq ps Erased _ = return True ceq ps _ Erased = return True ceq ps x y = return False caseeq ps (Case _ n cs) (Case _ n' cs') = caseeqA ((n,n'):ps) cs cs' where caseeqA ps (ConCase x i as sc : rest) (ConCase x' i' as' sc' : rest') = do q1 <- caseeq (zip as as' ++ ps) sc sc' q2 <- caseeqA ps rest rest' return $ x == x' && i == i' && q1 && q2 caseeqA ps (ConstCase x sc : rest) (ConstCase x' sc' : rest') = do q1 <- caseeq ps sc sc' q2 <- caseeqA ps rest rest' return $ x == x' && q1 && q2 caseeqA ps (DefaultCase sc : rest) (DefaultCase sc' : rest') = liftM2 (&&) (caseeq ps sc sc') (caseeqA ps rest rest') caseeqA ps [] [] = return True caseeqA ps _ _ = return False caseeq ps (STerm x) (STerm y) = ceq ps x y caseeq ps (UnmatchedCase _) (UnmatchedCase _) = return True caseeq ps _ _ = return False sameDefs ps x y = case (lookupDef x ctxt, lookupDef y ctxt) of ([Function _ xdef], [Function _ ydef]) -> ceq ((x,y):ps) xdef ydef ([CaseOp _ _ _ _ _ xd], [CaseOp _ _ _ _ _ yd]) -> let (_, xdef) = cases_compiletime xd (_, ydef) = cases_compiletime yd in caseeq ((x,y):ps) xdef ydef _ -> return False sameCase :: [(Name, Name)] -> Name -> Name -> [Term] -> [Term] -> StateT UCs TC Bool sameCase ps x y xargs yargs = case (lookupDef x ctxt, lookupDef y ctxt) of ([Function _ xdef], [Function _ ydef]) -> ceq ((x,y):ps) xdef ydef ([CaseOp _ _ _ _ _ xd], [CaseOp _ _ _ _ _ yd]) -> let (xin, xdef) = cases_compiletime xd (yin, ydef) = cases_compiletime yd in do liftM2 (&&) (do ok <- zipWithM (ceq ps) (drop (length xin) xargs) (drop (length yin) yargs) return (and ok)) (caseeq ((x,y):ps) xdef ydef) _ -> return False -- CONTEXTS ----------------------------------------------------------------- {-| A definition is either a simple function (just an expression with a type), a constant, which could be a data or type constructor, an axiom or as an yet undefined function, or an Operator. An Operator is a function which explains how to reduce. A CaseOp is a function defined by a simple case tree -} data Def = Function !Type !Term | TyDecl NameType !Type | Operator Type Int ([Value] -> Maybe Value) | CaseOp CaseInfo !Type ![(Type, Bool)] -- argument types, whether canonical ![Either Term (Term, Term)] -- original definition ![([Name], Term, Term)] -- simplified for totality check definition !CaseDefs deriving Generic -- [Name] SC -- Compile time case definition -- [Name] SC -- Run time cae definitions data CaseDefs = CaseDefs { cases_compiletime :: !([Name], SC), cases_runtime :: !([Name], SC) } deriving Generic data CaseInfo = CaseInfo { case_inlinable :: Bool, -- decided by machine case_alwaysinline :: Bool, -- decided by %inline flag tc_dictionary :: Bool } deriving Generic {-! deriving instance Binary Def !-} {-! deriving instance Binary CaseInfo !-} {-! deriving instance Binary CaseDefs !-} instance Show Def where show (Function ty tm) = "Function: " ++ show (ty, tm) show (TyDecl nt ty) = "TyDecl: " ++ show nt ++ " " ++ show ty show (Operator ty _ _) = "Operator: " ++ show ty show (CaseOp (CaseInfo inlc inla inlr) ty atys ps_in ps cd) = let (ns, sc) = cases_compiletime cd (ns', sc') = cases_runtime cd in "Case: " ++ show ty ++ " " ++ show ps ++ "\n" ++ "COMPILE TIME:\n\n" ++ show ns ++ " " ++ show sc ++ "\n\n" ++ "RUN TIME:\n\n" ++ show ns' ++ " " ++ show sc' ++ "\n\n" ++ if inlc then "Inlinable" else "Not inlinable" ++ if inla then " Aggressively\n" else "\n" ------- -- Hidden => Programs can't access the name at all -- Public => Programs can access the name and use at will -- Frozen => Programs can access the name, which doesn't reduce -- Private => Programs can't access the name, doesn't reduce internally data Accessibility = Hidden | Public | Frozen | Private deriving (Eq, Ord, Generic) instance Show Accessibility where show Public = "public export" show Frozen = "export" show Private = "private" show Hidden = "hidden" type Injectivity = Bool -- | The result of totality checking data Totality = Total [Int] -- ^ well-founded arguments | Productive -- ^ productive | Partial PReason | Unchecked | Generated deriving (Eq, Generic) -- | Reasons why a function may not be total data PReason = Other [Name] | Itself | NotCovering | NotPositive | UseUndef Name | ExternalIO | BelieveMe | Mutual [Name] | NotProductive deriving (Show, Eq, Generic) instance Show Totality where show (Total args)= "Total" -- ++ show args ++ " decreasing arguments" show Productive = "Productive" -- ++ show args ++ " decreasing arguments" show Unchecked = "not yet checked for totality" show (Partial Itself) = "possibly not total as it is not well founded" show (Partial NotCovering) = "not total as there are missing cases" show (Partial NotPositive) = "not strictly positive" show (Partial ExternalIO) = "an external IO primitive" show (Partial NotProductive) = "not productive" show (Partial BelieveMe) = "not total due to use of believe_me in proof" show (Partial (Other ns)) = "possibly not total due to: " ++ showSep ", " (map show ns) show (Partial (Mutual ns)) = "possibly not total due to recursive path " ++ showSep " --> " (map show ns) show (Partial (UseUndef n)) = "possibly not total because it uses the undefined name " ++ show n show Generated = "auto-generated" {-! deriving instance Binary Accessibility !-} {-! deriving instance Binary Totality !-} {-! deriving instance Binary PReason !-} -- Possible attached meta-information for a definition in context data MetaInformation = EmptyMI -- ^ No meta-information | DataMI [Int] -- ^ Meta information for a data declaration with position of parameters deriving (Eq, Show, Generic) -- | Contexts used for global definitions and for proof state. They contain -- universe constraints and existing definitions. -- Also store maximum RigCount of the name (can't bind a name at multiplicity -- 1 in a RigW, for example) data Context = MkContext { next_tvar :: Int, definitions :: Ctxt TTDecl } deriving (Show, Generic) type TTDecl = (Def, RigCount, Injectivity, Accessibility, Totality, MetaInformation) -- | The initial empty context initContext = MkContext 0 emptyContext mapDefCtxt :: (Def -> Def) -> Context -> Context mapDefCtxt f (MkContext t !defs) = MkContext t (mapCtxt f' defs) where f' (!d, r, i, a, t, m) = f' (f d, r, i, a, t, m) -- | Get the definitions from a context ctxtAlist :: Context -> [(Name, Def)] ctxtAlist ctxt = map (\(n, (d, r, i, a, t, m)) -> (n, d)) $ toAlist (definitions ctxt) veval ctxt env t = evalState (eval False ctxt [] env t []) initEval addToCtxt :: Name -> Term -> Type -> Context -> Context addToCtxt n tm ty uctxt = let ctxt = definitions uctxt !ctxt' = addDef n (Function ty tm, RigW, False, Public, Unchecked, EmptyMI) ctxt in uctxt { definitions = ctxt' } setAccess :: Name -> Accessibility -> Context -> Context setAccess n a uctxt = let ctxt = definitions uctxt !ctxt' = updateDef n (\ (d, r, i, _, t, m) -> (d, r, i, a, t, m)) ctxt in uctxt { definitions = ctxt' } setInjective :: Name -> Injectivity -> Context -> Context setInjective n i uctxt = let ctxt = definitions uctxt !ctxt' = updateDef n (\ (d, r, _, a, t, m) -> (d, r, i, a, t, m)) ctxt in uctxt { definitions = ctxt' } setTotal :: Name -> Totality -> Context -> Context setTotal n t uctxt = let ctxt = definitions uctxt !ctxt' = updateDef n (\ (d, r, i, a, _, m) -> (d, r, i, a, t, m)) ctxt in uctxt { definitions = ctxt' } setRigCount :: Name -> RigCount -> Context -> Context setRigCount n rc uctxt = let ctxt = definitions uctxt !ctxt' = updateDef n (\ (d, _, i, a, t, m) -> (d, rc, i, a, t, m)) ctxt in uctxt { definitions = ctxt' } setMetaInformation :: Name -> MetaInformation -> Context -> Context setMetaInformation n m uctxt = let ctxt = definitions uctxt !ctxt' = updateDef n (\ (d, r, i, a, t, _) -> (d, r, i, a, t, m)) ctxt in uctxt { definitions = ctxt' } addCtxtDef :: Name -> Def -> Context -> Context addCtxtDef n d c = let ctxt = definitions c !ctxt' = addDef n (d, RigW, False, Public, Unchecked, EmptyMI) $! ctxt in c { definitions = ctxt' } addTyDecl :: Name -> NameType -> Type -> Context -> Context addTyDecl n nt ty uctxt = let ctxt = definitions uctxt !ctxt' = addDef n (TyDecl nt ty, RigW, False, Public, Unchecked, EmptyMI) ctxt in uctxt { definitions = ctxt' } addDatatype :: Datatype Name -> Context -> Context addDatatype (Data n tag ty unique cons) uctxt = let ctxt = definitions uctxt ty' = normalise uctxt [] ty !ctxt' = addCons 0 cons (addDef n (TyDecl (TCon tag (arity ty')) ty, RigW, True, Public, Unchecked, EmptyMI) ctxt) in uctxt { definitions = ctxt' } where addCons tag [] ctxt = ctxt addCons tag ((n, ty) : cons) ctxt = let ty' = normalise uctxt [] ty in addCons (tag+1) cons (addDef n (TyDecl (DCon tag (arity ty') unique) ty, RigW, True, Public, Unchecked, EmptyMI) ctxt) -- FIXME: Too many arguments! Refactor all these Bools. -- -- Issue #1724 on the issue tracker. -- https://github.com/idris-lang/Idris-dev/issues/1724 addCasedef :: Name -> ErasureInfo -> CaseInfo -> Bool -> SC -> -- default case Bool -> Bool -> [(Type, Bool)] -> -- argument types, whether canonical [Int] -> -- inaccessible arguments [Either Term (Term, Term)] -> [([Name], Term, Term)] -> -- compile time [([Name], Term, Term)] -> -- run time Type -> Context -> TC Context addCasedef n ei ci@(CaseInfo inline alwaysInline tcdict) tcase covering reflect asserted argtys inacc ps_in ps_ct ps_rt ty uctxt = do let ctxt = definitions uctxt access = case lookupDefAcc n False uctxt of [(_, acc)] -> acc _ -> Public compileTime <- simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_ct ei runtime <- simpleCase tcase covering reflect RunTime emptyFC inacc argtys ps_rt ei ctxt' <- case (compileTime, runtime) of ( CaseDef args_ct sc_ct _, CaseDef args_rt sc_rt _) -> let inl = alwaysInline -- tcdict inlc = (inl || small n args_rt sc_rt) && (not asserted) cdef = CaseDefs (args_ct, sc_ct) (args_rt, sc_rt) op = (CaseOp (ci { case_inlinable = inlc }) ty argtys ps_in ps_ct cdef, RigW, False, access, Unchecked, EmptyMI) in return $ addDef n op ctxt -- other -> tfail (Msg $ "Error adding case def: " ++ show other) return uctxt { definitions = ctxt' } -- simplify a definition by unfolding interface methods -- We need this for totality checking, because functions which use interfaces -- in an implementation definition themselves need to have the implementation -- inlined or it'll be treated as a higher order function that will potentially -- loop. simplifyCasedef :: Name -> [Name] -> [[Name]] -> ErasureInfo -> Context -> TC Context simplifyCasedef n ufnames umethss ei uctxt = do let ctxt = definitions uctxt ctxt' <- case lookupCtxt n ctxt of [(CaseOp ci ty atys [] ps _, rc, inj, acc, tot, metainf)] -> return ctxt -- nothing to simplify (or already done...) [(CaseOp ci ty atys ps_in ps cd, rc, inj, acc, tot, metainf)] -> do let ps_in' = map simpl ps_in pdef = map debind ps_in' CaseDef args sc _ <- simpleCase False (STerm Erased) False CompileTime emptyFC [] atys pdef ei return $ addDef n (CaseOp ci ty atys ps_in' ps (cd { cases_compiletime = (args, sc) }), rc, inj, acc, tot, metainf) ctxt _ -> return ctxt return uctxt { definitions = ctxt' } where depat acc (Bind n (PVar _ t) sc) = depat (n : acc) (instantiate (P Bound n t) sc) depat acc x = (acc, x) debind (Right (x, y)) = let (vs, x') = depat [] x (_, y') = depat [] y in (vs, x', y') debind (Left x) = let (vs, x') = depat [] x in (vs, x', Impossible) simpl (Right (x, y)) = if null ufnames then Right (x, y) else Right (x, unfold uctxt [] (map (\n -> (n, 1)) (uns y)) y) simpl t = t -- Unfold the given name, interface methdods, and any function which uses it as -- an argument directly. This is specifically for finding applications of -- interface dictionaries and inlining them both for totality checking and for -- a small performance gain. uns tm = getNamesToUnfold ufnames umethss tm getNamesToUnfold :: [Name] -> [[Name]] -> Term -> [Name] getNamesToUnfold inames ms tm = nub $ inames ++ getNames Nothing tm ++ concat ms where getNames under fn@(App _ _ _) | (f, args) <- unApply fn = let under' = case f of P _ fn _ -> Just fn _ -> Nothing in getNames under f ++ concatMap (getNames under') args getNames (Just under) (P _ ref _) = if ref `elem` inames then [under] else [] getNames under (Bind n (Let c t v) sc) = getNames Nothing t ++ getNames Nothing v ++ getNames Nothing sc getNames under (Bind n b sc) = getNames Nothing (binderTy b) ++ getNames Nothing sc getNames _ _ = [] addOperator :: Name -> Type -> Int -> ([Value] -> Maybe Value) -> Context -> Context addOperator n ty a op uctxt = let ctxt = definitions uctxt ctxt' = addDef n (Operator ty a op, RigW, False, Public, Unchecked, EmptyMI) ctxt in uctxt { definitions = ctxt' } tfst (a, _, _, _, _, _) = a lookupNames :: Name -> Context -> [Name] lookupNames n ctxt = let ns = lookupCtxtName n (definitions ctxt) in map fst ns -- | Get the list of pairs of fully-qualified names and their types that match some name lookupTyName :: Name -> Context -> [(Name, Type)] lookupTyName n ctxt = do (name, def) <- lookupCtxtName n (definitions ctxt) ty <- case tfst def of (Function ty _) -> return ty (TyDecl _ ty) -> return ty (Operator ty _ _) -> return ty (CaseOp _ ty _ _ _ _) -> return ty return (name, ty) -- | Get the pair of a fully-qualified name and its type, if there is a unique one matching the name used as a key. lookupTyNameExact :: Name -> Context -> Maybe (Name, Type) lookupTyNameExact n ctxt = listToMaybe [ (nm, v) | (nm, v) <- lookupTyName n ctxt, nm == n ] -- | Get the types that match some name lookupTy :: Name -> Context -> [Type] lookupTy n ctxt = map snd (lookupTyName n ctxt) -- | Get the single type that matches some name precisely lookupTyExact :: Name -> Context -> Maybe Type lookupTyExact n ctxt = fmap snd (lookupTyNameExact n ctxt) -- | Return true if the given type is a concrete type familyor primitive -- False it it's a function to compute a type or a variable isCanonical :: Type -> Context -> Bool isCanonical t ctxt = case unApply t of (P _ n _, _) -> isConName n ctxt (Constant _, _) -> True _ -> False isConName :: Name -> Context -> Bool isConName n ctxt = isTConName n ctxt || isDConName n ctxt isTConName :: Name -> Context -> Bool isTConName n ctxt = case lookupDefExact n ctxt of Just (TyDecl (TCon _ _) _) -> True _ -> False -- | Check whether a resolved name is certainly a data constructor isDConName :: Name -> Context -> Bool isDConName n ctxt = case lookupDefExact n ctxt of Just (TyDecl (DCon _ _ _) _) -> True _ -> False -- | Check whether any overloading of a name is a data constructor canBeDConName :: Name -> Context -> Bool canBeDConName n ctxt = or $ do def <- lookupCtxt n (definitions ctxt) case tfst def of (TyDecl (DCon _ _ _) _) -> return True _ -> return False isFnName :: Name -> Context -> Bool isFnName n ctxt = case lookupDefExact n ctxt of Just (Function _ _) -> True Just (Operator _ _ _) -> True Just (CaseOp _ _ _ _ _ _) -> True _ -> False isTCDict :: Name -> Context -> Bool isTCDict n ctxt = case lookupDefExact n ctxt of Just (Function _ _) -> False Just (Operator _ _ _) -> False Just (CaseOp ci _ _ _ _ _) -> tc_dictionary ci _ -> False -- Is the name guarded by constructors in the term? -- We assume the term is normalised, so no looking under 'let' for example. conGuarded :: Context -> Name -> Term -> Bool conGuarded ctxt n tm = guarded n tm where guarded n (P _ n' _) = n == n' guarded n ap@(App _ _ _) | (P _ f _, as) <- unApply ap, isConName f ctxt = any (guarded n) as guarded _ _ = False visibleDefinitions :: Context -> Ctxt TTDecl visibleDefinitions ctxt = Map.filter (\m -> length m > 0) . Map.map onlyVisible . definitions $ ctxt where onlyVisible = Map.filter visible visible (_def, _rigCount, _injectivity, accessibility, _totality, _metaInformation) = accessibility `notElem` [Hidden, Private] lookupP :: Name -> Context -> [Term] lookupP = lookupP_all False False lookupP_all :: Bool -> Bool -> Name -> Context -> [Term] lookupP_all all exact n ctxt = do (n', def) <- names p <- case def of (Function ty tm, _, inj, a, _, _) -> return (P Ref n' ty, a) (TyDecl nt ty, _, _, a, _, _) -> return (P nt n' ty, a) (CaseOp _ ty _ _ _ _, _, inj, a, _, _) -> return (P Ref n' ty, a) (Operator ty _ _, _, inj, a, _, _) -> return (P Ref n' ty, a) case snd p of Hidden -> if all then return (fst p) else [] Private -> if all then return (fst p) else [] _ -> return (fst p) where names = let ns = lookupCtxtName n (definitions ctxt) in if exact then filter (\ (n', d) -> n' == n) ns else ns lookupDefExact :: Name -> Context -> Maybe Def lookupDefExact n ctxt = tfst <$> lookupCtxtExact n (definitions ctxt) lookupDef :: Name -> Context -> [Def] lookupDef n ctxt = tfst <$> lookupCtxt n (definitions ctxt) lookupNameDef :: Name -> Context -> [(Name, Def)] lookupNameDef n ctxt = mapSnd tfst $ lookupCtxtName n (definitions ctxt) where mapSnd f [] = [] mapSnd f ((x,y):xys) = (x, f y) : mapSnd f xys lookupDefAcc :: Name -> Bool -> Context -> [(Def, Accessibility)] lookupDefAcc n mkpublic ctxt = map mkp $ lookupCtxt n (definitions ctxt) -- io_bind a special case for REPL prettiness where mkp (d, _, inj, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_pure")) then (d, Public) else (d, a) lookupTotalAccessibility :: Name -> Context -> [(Totality,Accessibility)] lookupTotalAccessibility n ctxt = fmap unpack $ lookupCtxt n (definitions ctxt) where unpack ((_,_,_,a,t,_)) = (t,a) lookupDefAccExact :: Name -> Bool -> Context -> Maybe (Def, Accessibility) lookupDefAccExact n mkpublic ctxt = fmap mkp $ lookupCtxtExact n (definitions ctxt) -- io_bind a special case for REPL prettiness where mkp (d, _, inj, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_pure")) then (d, Public) else (d, a) lookupTotal :: Name -> Context -> [Totality] lookupTotal n ctxt = map mkt $ lookupCtxt n (definitions ctxt) where mkt (d, _, inj, a, t, m) = t lookupTotalExact :: Name -> Context -> Maybe Totality lookupTotalExact n ctxt = fmap mkt $ lookupCtxtExact n (definitions ctxt) where mkt (d, _, inj, a, t, m) = t lookupRigCount :: Name -> Context -> [Totality] lookupRigCount n ctxt = map mkt $ lookupCtxt n (definitions ctxt) where mkt (d, _, inj, a, t, m) = t lookupRigCountExact :: Name -> Context -> Maybe RigCount lookupRigCountExact n ctxt = fmap mkt $ lookupCtxtExact n (definitions ctxt) where mkt (d, rc, inj, a, t, m) = rc lookupInjectiveExact :: Name -> Context -> Maybe Injectivity lookupInjectiveExact n ctxt = fmap mkt $ lookupCtxtExact n (definitions ctxt) where mkt (d, _, inj, a, t, m) = inj -- Assume type is at least in whnfArgs form linearCheck :: Context -> Type -> TC () linearCheck ctxt t = checkArgs t where checkArgs (Bind n (Pi RigW _ ty _) sc) = do linearCheckArg ctxt ty checkArgs (substV (P Bound n Erased) sc) checkArgs (Bind n (Pi _ _ _ _) sc) = checkArgs (substV (P Bound n Erased) sc) checkArgs _ = return () linearCheckArg :: Context -> Type -> TC () linearCheckArg ctxt ty = mapM_ checkNameOK (allTTNames ty) where checkNameOK f = case lookupRigCountExact f ctxt of Just Rig1 -> tfail $ Msg $ show f ++ " can only appear in a linear binding" _ -> return () -- Check if a name is reducible in the type checker. Partial definitions -- are not reducible (so treated as a constant) tcReducible :: Name -> Context -> Bool tcReducible n ctxt = case lookupTotalExact n ctxt of Nothing -> True Just (Partial _) -> False _ -> True lookupMetaInformation :: Name -> Context -> [MetaInformation] lookupMetaInformation n ctxt = map mkm $ lookupCtxt n (definitions ctxt) where mkm (d, _, inj, a, t, m) = m lookupNameTotal :: Name -> Context -> [(Name, Totality)] lookupNameTotal n = map (\(n, (_, _, _, _, t, _)) -> (n, t)) . lookupCtxtName n . definitions lookupVal :: Name -> Context -> [Value] lookupVal n ctxt = do def <- lookupCtxt n (definitions ctxt) case tfst def of (Function _ htm) -> return (veval ctxt [] htm) (TyDecl nt ty) -> return (VP nt n (veval ctxt [] ty)) _ -> [] lookupTyEnv :: Name -> Env -> Maybe (Int, RigCount, Type) lookupTyEnv n env = li n 0 env where li n i [] = Nothing li n i ((x, r, b): xs) | n == x = Just (i, r, binderTy b) | otherwise = li n (i+1) xs -- | Create a unique name given context and other existing names uniqueNameCtxt :: Context -> Name -> [Name] -> Name uniqueNameCtxt ctxt n hs | n `elem` hs = uniqueNameCtxt ctxt (nextName n) hs | [_] <- lookupTy n ctxt = uniqueNameCtxt ctxt (nextName n) hs | otherwise = n uniqueBindersCtxt :: Context -> [Name] -> TT Name -> TT Name uniqueBindersCtxt ctxt ns (Bind n b sc) = let n' = uniqueNameCtxt ctxt n ns in Bind n' (fmap (uniqueBindersCtxt ctxt (n':ns)) b) (uniqueBindersCtxt ctxt ns sc) uniqueBindersCtxt ctxt ns (App s f a) = App s (uniqueBindersCtxt ctxt ns f) (uniqueBindersCtxt ctxt ns a) uniqueBindersCtxt ctxt ns t = t