1{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances,
4module Idris.Core.Evaluate(normalise, normaliseTrace, normaliseC, normaliseAll,
5 rt_simplify, simplify, specialise, hnf, convEq, convEq',
6 Def(..), CaseInfo(..), CaseDefs(..),
7 Accessibility(..), Totality(..), PReason(..), MetaInformation(..),
8 Context, initContext, ctxtAlist, next_tvar,
9 addToCtxt, setAccess, setTotal, setMetaInformation, addCtxtDef, addTyDecl,
10 addDatatype, addCasedef, simplifyCasedef, addOperator,
11 lookupNames, lookupTyName, lookupTyNameExact, lookupTy, lookupTyExact,
12 lookupP, lookupP_all, lookupDef, lookupNameDef, lookupDefExact, lookupDefAcc, lookupDefAccExact, lookupVal,
14 lookupTotal, lookupNameTotal, lookupMetaInformation, lookupTyEnv, isTCDict, isDConName, canBeDConName, isTConName, isConName, isFnName,
15 Value(..), Quote(..), initEval, uniqueNameCtxt, uniqueBindersCtxt, definitions,
19import Control.Applicative hiding (Const)
20import Control.Monad.State -- not Strict!
21import qualified Data.Binary as B
22import Data.Binary hiding (get, put)
25import Idris.Core.CaseTree
27data EvalState = ES { limited :: [(Name, Int)],
32type Eval a = State EvalState a
41initEval = ES [] 0 False
43-- VALUES (as HOAS) ---------------------------------------------------------
44-- | A HOAS representation of values
45data Value = VP NameType Name Value
47 -- True for Bool indicates safe to reduce
48 | VBind Bool Name (Binder Value) (Value -> Eval Value)
49 -- For frozen let bindings when simplifying
50 | VBLet Int Name Value Value Value
58-- | VLazy Env [Value] Term
61instance Show Value where
62 show x = show $ evalState (quote 100 x) initEval
64instance Show (a -> b) where
67-- THE EVALUATOR ------------------------------------------------------------
69-- The environment is assumed to be "locally named" - i.e., not de Bruijn
71-- i.e. it's an intermediate environment that we have while type checking or
72-- while building a proof.
74-- | Normalise fully type checked terms (so, assume all names/let bindings resolved)
75normaliseC :: Context -> Env -> TT Name -> TT Name
77 = evalState (do val <- eval False ctxt [] env t []
80normaliseAll :: Context -> Env -> TT Name -> TT Name
81normaliseAll ctxt env t
82 = evalState (do val <- eval False ctxt [] env t [AtREPL]
85normalise :: Context -> Env -> TT Name -> TT Name
86normalise = normaliseTrace False
88normaliseTrace :: Bool -> Context -> Env -> TT Name -> TT Name
89normaliseTrace tr ctxt env t
90 = evalState (do val <- eval tr ctxt [] (map finalEntry env) (finalise t) []
93-- Return a specialised name, and an updated list of reductions available,
94-- so that the caller can tell how much specialisation was achieved.
95specialise :: Context -> Env -> [(Name, Int)] -> TT Name ->
96 (TT Name, [(Name, Int)])
97specialise ctxt env limits t
99 runState (do val <- eval False ctxt []
100 (map finalEntry env) (finalise t)
102 quote 0 val) (initEval { limited = limits }) in
105-- | Like normalise, but we only reduce functions that are marked as okay to
106-- inline (and probably shouldn't reduce lets?)
107-- 20130908: now only used to reduce for totality checking. Inlining should
110simplify :: Context -> Env -> TT Name -> TT Name
112 = evalState (do val <- eval False ctxt [(sUN "lazy", 0),
115 (sUN "assert_smaller", 0),
116 (sUN "assert_total", 0),
118 (sUN "prim__syntactic_eq", 0),
120 (map finalEntry env) (finalise t)
122 quote 0 val) initEval
124-- | Simplify for run-time (i.e. basic inlining)
125rt_simplify :: Context -> Env -> TT Name -> TT Name
126rt_simplify ctxt env t
127 = evalState (do val <- eval False ctxt [(sUN "lazy", 0),
131 (sUN "prim__syntactic_eq", 0),
132 (sUN "prim_fork", 0)]
133 (map finalEntry env) (finalise t)
135 quote 0 val) initEval
137-- | Reduce a term to head normal form
138hnf :: Context -> Env -> TT Name -> TT Name
140 = evalState (do val <- eval False ctxt []
143 quote 0 val) initEval
146-- unbindEnv env (quote 0 (eval ctxt (bindEnv env t)))
148finalEntry :: (Name, Binder (TT Name)) -> (Name, Binder (TT Name))
149finalEntry (n, b) = (n, fmap finalise b)
151bindEnv :: EnvTT n -> TT n -> TT n
153bindEnv ((n, Let t v):bs) tm = Bind n (NLet t v) (bindEnv bs tm)
154bindEnv ((n, b):bs) tm = Bind n b (bindEnv bs tm)
156unbindEnv :: EnvTT n -> TT n -> TT n
158unbindEnv (_:bs) (Bind n b sc) = unbindEnv bs sc
160usable :: Bool -- specialising
161 -> Name -> [(Name, Int)] -> Eval (Bool, [(Name, Int)])
162-- usable _ _ ns@((MN 0 "STOP", _) : _) = return (False, ns)
163usable False n [] = return (True, [])
165 = do ES ls num b <- get
166 if b then return (False, ns)
167 else case lookup n ls of
168 Just 0 -> return (False, ns)
169 Just i -> return (True, ns)
170 _ -> return (False, ns)
172 = case lookup n ns of
173 Just 0 -> return (False, ns)
174 Just i -> return $ (True, (n, abs (i-1)) : filter (\ (n', _) -> n/=n') ns)
175 _ -> return $ (True, (n, 100) : filter (\ (n', _) -> n/=n') ns)
178fnCount :: Int -> Name -> Eval ()
180 = do ES ls num b <- get
182 Just i -> do put $ ES ((n, (i - inc)) :
183 filter (\ (n', _) -> n/=n') ls) num b
186setBlock :: Bool -> Eval ()
187setBlock b = do ES ls num _ <- get
191reinstate = fnCount (-1)
193-- | Evaluate in a context of locally named things (i.e. not de Bruijn indexed,
194-- such as we might have during construction of a proof)
196-- The (Name, Int) pair in the arguments is the maximum depth of unfolding of
197-- a name. The corresponding pair in the state is the maximum number of
198-- unfoldings overall.
200eval :: Bool -> Context -> [(Name, Int)] -> Env -> TT Name ->
201 [EvalOpt] -> Eval Value
202eval traceon ctxt ntimes genv tm opts = ev ntimes [] True [] tm where
203 spec = Spec `elem` opts
204 simpl = Simplify `elem` opts
205 runtime = RunTT `elem` opts
206 atRepl = AtREPL `elem` opts
207 hnf = HNF `elem` opts
209 -- returns 'True' if the function should block
210 -- normal evaluation should return false
211 blockSimplify (CaseInfo inl always dict) n stk
213 = if always then False
214 else not (inl || dict) || elem n stk
215 | Simplify `elem` opts
216 = (not (inl || dict) || elem n stk)
217 || (n == sUN "prim__syntactic_eq")
220 getCases cd | simpl = cases_totcheck cd
221 | runtime = cases_runtime cd
222 | otherwise = cases_compiletime cd
224 ev ntimes stk top env (P _ n ty)
225 | Just (Let t v) <- lookup n genv = ev ntimes stk top env v
226 ev ntimes_in stk top env (P Ref n ty)
227 | not top && hnf = liftM (VP Ref n) (ev ntimes stk top env ty)
229 = do (u, ntimes) <- usable spec n ntimes_in
231 do let val = lookupDefAcc n (spec || atRepl) ctxt
233 [(Function _ tm, _)] | sUN "assert_total" `elem` stk ->
234 ev ntimes (n:stk) True env tm
235 [(Function _ tm, Public)] ->
236 ev ntimes (n:stk) True env tm
237 [(Function _ tm, Hidden)] ->
238 ev ntimes (n:stk) True env tm
239 [(TyDecl nt ty, _)] -> do vty <- ev ntimes stk True env ty
241 [(CaseOp ci _ _ _ _ cd, acc)]
242 | (acc /= Frozen || sUN "assert_total" `elem` stk) &&
243 null (fst (cases_totcheck cd)) -> -- unoptimised version
244 let (ns, tree) = getCases cd in
245 if blockSimplify ci n stk
246 then liftM (VP Ref n) (ev ntimes stk top env ty)
247 else -- traceWhen runtime (show (n, ns, tree)) $
248 do c <- evCase ntimes n (n:stk) top env ns [] tree
250 (Nothing, _) -> liftM (VP Ref n) (ev ntimes stk top env ty)
251 (Just v, _) -> return v
252 _ -> liftM (VP Ref n) (ev ntimes stk top env ty)
253 else liftM (VP Ref n) (ev ntimes stk top env ty)
254 ev ntimes stk top env (P nt n ty)
255 = liftM (VP nt n) (ev ntimes stk top env ty)
256 ev ntimes stk top env (V i)
257 | i < length env && i >= 0 = return $ snd (env !! i)
258 | otherwise = return $ VV i
259 ev ntimes stk top env (Bind n (Let t v) sc)
260 | not runtime || occurrences n sc < 2
261 = do v' <- ev ntimes stk top env v --(finalise v)
262 sc' <- ev ntimes stk top ((n, v') : env) sc
265 = do t' <- ev ntimes stk top env t
266 v' <- ev ntimes stk top env v --(finalise v)
267 -- use Tmp as a placeholder, then make it a variable reference
268 -- again when evaluation finished
271 put (hs { nexthole = vd + 1 })
272 sc' <- ev ntimes stk top ((n, VP Bound (sMN vd "vlet") VErased) : env) sc
273 return $ VBLet vd n t' v' sc'
274 ev ntimes stk top env (Bind n (NLet t v) sc)
275 = do t' <- ev ntimes stk top env (finalise t)
276 v' <- ev ntimes stk top env (finalise v)
277 sc' <- ev ntimes stk top ((n, v') : env) sc
278 return $ VBind True n (Let t' v') (\x -> return sc')
279 ev ntimes stk top env (Bind n b sc)
280 = do b' <- vbind env b
281 let n' = uniqueName n (map fst genv ++ map fst env)
282 return $ VBind True -- (vinstances 0 sc < 2)
283 n' b' (\x -> ev ntimes stk False ((n', x):env) sc)
285 = fmapMB (\tm -> ev ntimes stk top env (finalise tm)) t
286 -- block reduction immediately under codata (and not forced)
287 ev ntimes stk top env
288 (App (App (App d@(P _ (UN dly) _) l@(P _ (UN lco) _)) t) arg)
289 | dly == txt "Delay" && lco == txt "LazyCodata" && not (simpl || atRepl)
290 = do let (f, _) = unApply arg
291 let ntimes' = case f of
292 P _ fn _ -> (fn, 0) : ntimes
294 when spec $ setBlock True
295 d' <- ev ntimes' stk False env d
296 l' <- ev ntimes' stk False env l
297 t' <- ev ntimes' stk False env t
298 arg' <- ev ntimes' stk False env arg
299 when spec $ setBlock False
300 evApply ntimes' stk top env [l',t',arg'] d'
301 -- Treat "assert_total" specially, as long as it's defined!
302 ev ntimes stk top env (App (App (P _ n@(UN at) _) _) arg)
303 | [(CaseOp _ _ _ _ _ _, _)] <- lookupDefAcc n (spec || atRepl) ctxt,
304 at == txt "assert_total" && not simpl
305 = ev ntimes (n : stk) top env arg
306 ev ntimes stk top env (App f a)
307 = do f' <- ev ntimes stk False env f
308 a' <- ev ntimes stk False env a
309 evApply ntimes stk top env [a'] f'
310 ev ntimes stk top env (Proj t i)
311 = do -- evaluate dictionaries if it means the projection works
312 t' <- ev ntimes stk top env t
313-- tfull' <- reapply ntimes stk top env t' []
314 return (doProj t' (getValArgs t'))
315 where doProj t' (VP (DCon _ _ _) _ _, args)
316 | i >= 0 && i < length args = args!!i
317 doProj t' _ = VProj t' i
319 ev ntimes stk top env (Constant c) = return $ VConstant c
320 ev ntimes stk top env Erased = return VErased
321 ev ntimes stk top env Impossible = return VImpossible
322 ev ntimes stk top env (TType i) = return $ VType i
323 ev ntimes stk top env (UType u) = return $ VUType u
325 evApply ntimes stk top env args (VApp f a)
326 = evApply ntimes stk top env (a:args) f
327 evApply ntimes stk top env args f
328 = apply ntimes stk top env f args
330 reapply ntimes stk top env f@(VP Ref n ty) args
331 = let val = lookupDefAcc n (spec || atRepl) ctxt in
333 [(CaseOp ci _ _ _ _ cd, acc)] ->
334 let (ns, tree) = getCases cd in
335 do c <- evCase ntimes n (n:stk) top env ns args tree
337 (Nothing, _) -> return $ unload env (VP Ref n ty) args
338 (Just v, rest) -> evApply ntimes stk top env rest v
340 (a : as) -> return $ unload env f (a : as)
342 reapply ntimes stk top env (VApp f a) args
343 = reapply ntimes stk top env f (a : args)
344 reapply ntimes stk top env v args = return v
346 apply ntimes stk top env (VBind True n (Lam t) sc) (a:as)
348 app <- apply ntimes stk top env a' as
350 apply ntimes_in stk top env f@(VP Ref n ty) args
351 | not top && hnf = case args of
353 _ -> return $ unload env f args
355 = do (u, ntimes) <- usable spec n ntimes_in
357 do let val = lookupDefAcc n (spec || atRepl) ctxt
359 [(CaseOp ci _ _ _ _ cd, acc)]
360 | acc /= Frozen || sUN "assert_total" `elem` stk ->
361 -- unoptimised version
362 let (ns, tree) = getCases cd in
363 if blockSimplify ci n stk
364 then return $ unload env (VP Ref n ty) args
365 else -- traceWhen runtime (show (n, ns, tree)) $
366 do c <- evCase ntimes n (n:stk) top env ns args tree
368 (Nothing, _) -> return $ unload env (VP Ref n ty) args
369 (Just v, rest) -> evApply ntimes stk top env rest v
370 [(Operator _ i op, _)] ->
371 if (i <= length args)
372 then case op (take i args) of
373 Nothing -> return $ unload env (VP Ref n ty) args
374 Just v -> evApply ntimes stk top env (drop i args) v
375 else return $ unload env (VP Ref n ty) args
378 _ -> return $ unload env f args
380 (a : as) -> return $ unload env f (a:as)
382 apply ntimes stk top env f (a:as) = return $ unload env f (a:as)
383 apply ntimes stk top env f [] = return f
385-- specApply stk env f@(VP Ref n ty) args
386-- = case lookupCtxt n statics of
388-- then trace (show (n, map fst (filter (\ (_, s) -> s) (zip args as)))) $
389-- return $ unload env f args
390-- else return $ unload env f args
391-- _ -> return $ unload env f args
392-- specApply stk env f args = return $ unload env f args
394 unload :: [(Name, Value)] -> Value -> [Value] -> Value
396 unload env f (a:as) = unload env (VApp f a) as
398 evCase ntimes n stk top env ns args tree
399 | length ns <= length args
400 = do let args' = take (length ns) args
401 let rest = drop (length ns) args
403 t <- evTree ntimes stk top env (zip ns args') tree
404 when spec $ case t of
405 Nothing -> reinstate n -- Blocked, count n again
407-- (zipWith (\n , t) -> (n, t)) ns args') tree
409 | otherwise = return (Nothing, args)
411 evTree :: [(Name, Int)] -> [Name] -> Bool ->
412 [(Name, Value)] -> [(Name, Value)] -> SC -> Eval (Maybe Value)
413 evTree ntimes stk top env amap (UnmatchedCase str) = return Nothing
414 evTree ntimes stk top env amap (STerm tm)
415 = do let etm = pToVs (map fst amap) tm
416 etm' <- ev ntimes stk (not (conHeaded tm))
419 evTree ntimes stk top env amap (ProjCase t alts)
420 = do t' <- ev ntimes stk top env t
421 doCase ntimes stk top env amap t' alts
422 evTree ntimes stk top env amap (Case _ n alts)
423 = case lookup n amap of
424 Just v -> doCase ntimes stk top env amap v alts
426 evTree ntimes stk top env amap ImpossibleCase = return Nothing
428 doCase ntimes stk top env amap v alts =
429 do c <- chooseAlt env v (getValArgs v) alts amap
431 Just (altmap, sc) -> evTree ntimes stk top env altmap sc
432 _ -> do c' <- chooseAlt' ntimes stk env v (getValArgs v) alts amap
434 Just (altmap, sc) -> evTree ntimes stk top env altmap sc
437 conHeaded tm@(App _ _)
438 | (P (DCon _ _ _) _ _, args) <- unApply tm = True
441 chooseAlt' ntimes stk env _ (f, args) alts amap
442 = do f' <- apply ntimes stk True env f args
443 chooseAlt env f' (getValArgs f')
446 chooseAlt :: [(Name, Value)] -> Value -> (Value, [Value]) -> [CaseAlt] ->
448 Eval (Maybe ([(Name, Value)], SC))
449 chooseAlt env _ (VP (DCon i a _) _ _, args) alts amap
450 | Just (ns, sc) <- findTag i alts = return $ Just (updateAmap (zip ns args) amap, sc)
451 | Just v <- findDefault alts = return $ Just (amap, v)
452 chooseAlt env _ (VP (TCon i a) _ _, args) alts amap
453 | Just (ns, sc) <- findTag i alts
454 = return $ Just (updateAmap (zip ns args) amap, sc)
455 | Just v <- findDefault alts = return $ Just (amap, v)
456 chooseAlt env _ (VConstant c, []) alts amap
457 | Just v <- findConst c alts = return $ Just (amap, v)
458 | Just (n', sub, sc) <- findSuc c alts
459 = return $ Just (updateAmap [(n',sub)] amap, sc)
460 | Just v <- findDefault alts = return $ Just (amap, v)
461 chooseAlt env _ (VP _ n _, args) alts amap
462 | Just (ns, sc) <- findFn n alts = return $ Just (updateAmap (zip ns args) amap, sc)
463 chooseAlt env _ (VBind _ _ (Pi i s k) t, []) alts amap
464 | Just (ns, sc) <- findFn (sUN "->") alts
465 = do t' <- t (VV 0) -- we know it's not in scope or it's not a pattern
466 return $ Just (updateAmap (zip ns [s, t']) amap, sc)
467 chooseAlt _ _ _ alts amap
468 | Just v <- findDefault alts
469 = if (any fnCase alts)
470 then return $ Just (amap, v)
472 | otherwise = return Nothing
474 fnCase (FnCase _ _ _) = True
477 -- Replace old variable names in the map with new matches
478 -- (This is possibly unnecessary since we make unique names and don't
479 -- allow repeated variables...?)
481 = newm ++ filter (\ (x, _) -> not (elem x (map fst newm))) amap
482 findTag i [] = Nothing
483 findTag i (ConCase n j ns sc : xs) | i == j = Just (ns, sc)
484 findTag i (_ : xs) = findTag i xs
486 findFn fn [] = Nothing
487 findFn fn (FnCase n ns sc : xs) | fn == n = Just (ns, sc)
488 findFn fn (_ : xs) = findFn fn xs
490 findDefault [] = Nothing
491 findDefault (DefaultCase sc : xs) = Just sc
492 findDefault (_ : xs) = findDefault xs
494 findSuc c [] = Nothing
495 findSuc (BI val) (SucCase n sc : _)
496 | val /= 0 = Just (n, VConstant (BI (val - 1)), sc)
497 findSuc c (_ : xs) = findSuc c xs
499 findConst c [] = Nothing
500 findConst c (ConstCase c' v : xs) | c == c' = Just v
501 findConst (AType (ATInt ITNative)) (ConCase n 1 [] v : xs) = Just v
502 findConst (AType ATFloat) (ConCase n 2 [] v : xs) = Just v
503 findConst (AType (ATInt ITChar)) (ConCase n 3 [] v : xs) = Just v
504 findConst StrType (ConCase n 4 [] v : xs) = Just v
505 findConst (AType (ATInt ITBig)) (ConCase n 6 [] v : xs) = Just v
506 findConst (AType (ATInt (ITFixed ity))) (ConCase n tag [] v : xs)
507 | tag == 7 + fromEnum ity = Just v
508 findConst c (_ : xs) = findConst c xs
510 getValArgs tm = getValArgs' tm []
511 getValArgs' (VApp f a) as = getValArgs' f (a:as)
512 getValArgs' f as = (f, as)
514-- tmpToV i vd (VLetHole j) | vd == j = return $ VV i
515-- tmpToV i vd (VP nt n v) = liftM (VP nt n) (tmpToV i vd v)
516-- tmpToV i vd (VBind n b sc) = do b' <- fmapMB (tmpToV i vd) b
517-- let sc' = \x -> do x' <- sc x
518-- tmpToV (i + 1) vd x'
519-- return (VBind n b' sc')
520-- tmpToV i vd (VApp f a) = liftM2 VApp (tmpToV i vd f) (tmpToV i vd a)
521-- tmpToV i vd x = return x
523instance Eq Value where
524 (==) x y = getTT x == getTT y
525 where getTT v = evalState (quote 0 v) initEval
528 quote :: Int -> a -> Eval (TT Name)
530instance Quote Value where
531 quote i (VP nt n v) = liftM (P nt n) (quote i v)
532 quote i (VV x) = return $ V x
533 quote i (VBind _ n b sc) = do sc' <- sc (VTmp i)
535 liftM (Bind n b') (quote (i+1) sc')
536 where quoteB t = fmapMB (quote i) t
537 quote i (VBLet vd n t v sc)
538 = do sc' <- quote i sc
541 let sc'' = pToV (sMN vd "vlet") (addBinder sc')
542 return (Bind n (Let t' v') sc'')
543 quote i (VApp f a) = liftM2 App (quote i f) (quote i a)
544 quote i (VType u) = return $ TType u
545 quote i (VUType u) = return $ UType u
546 quote i VErased = return $ Erased
547 quote i VImpossible = return $ Impossible
548 quote i (VProj v j) = do v' <- quote i v
550 quote i (VConstant c) = return $ Constant c
551 quote i (VTmp x) = return $ V (i - x - 1)
553wknV :: Int -> Value -> Eval Value
554wknV i (VV x) | x >= i = return $ VV (x - 1)
555wknV i (VBind red n b sc) = do b' <- fmapMB (wknV i) b
556 return $ VBind red n b' (\x -> do x' <- sc x
558wknV i (VApp f a) = liftM2 VApp (wknV i f) (wknV i a)
561isUniverse :: Term -> Bool
562isUniverse (TType _) = True
563isUniverse (UType _) = True
566isUsableUniverse :: Term -> Bool
567isUsableUniverse (UType NullType) = False
568isUsableUniverse x = isUniverse x
570convEq' ctxt hs x y = evalStateT (convEq ctxt hs x y) (0, [])
572convEq :: Context -> [Name] -> TT Name -> TT Name -> StateT UCs TC Bool
573convEq ctxt holes topx topy = ceq [] topx topy where
574 ceq :: [(Name, Name)] -> TT Name -> TT Name -> StateT UCs TC Bool
575 ceq ps (P xt x _) (P yt y _)
576 | x `elem` holes || y `elem` holes = return True
577 | x == y || (x, y) `elem` ps || (y,x) `elem` ps = return True
578 | otherwise = sameDefs ps x y
579 ceq ps x (Bind n (Lam t) (App y (V 0)))
580 = ceq ps x (substV (P Bound n t) y)
581 ceq ps (Bind n (Lam t) (App x (V 0))) y
582 = ceq ps (substV (P Bound n t) x) y
583 ceq ps x (Bind n (Lam t) (App y (P Bound n' _)))
584 | n == n' = ceq ps x y
585 ceq ps (Bind n (Lam t) (App x (P Bound n' _))) y
586 | n == n' = ceq ps x y
588 ceq ps (Bind n (PVar t) sc) y = ceq ps sc y
589 ceq ps x (Bind n (PVar t) sc) = ceq ps x sc
590 ceq ps (Bind n (PVTy t) sc) y = ceq ps sc y
591 ceq ps x (Bind n (PVTy t) sc) = ceq ps x sc
593 ceq ps (V x) (V y) = return (x == y)
594 ceq ps (V x) (P _ y _)
595 | x >= 0 && length ps > x = return (fst (ps!!x) == y)
596 | otherwise = return False
597 ceq ps (P _ x _) (V y)
598 | y >= 0 && length ps > y = return (x == snd (ps!!y))
599 | otherwise = return False
600 ceq ps (Bind n xb xs) (Bind n' yb ys)
601 = liftM2 (&&) (ceqB ps xb yb) (ceq ((n,n'):ps) xs ys)
603 ceqB ps (Let v t) (Let v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t')
604 ceqB ps (Guess v t) (Guess v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t')
605 ceqB ps (Pi i v t) (Pi i' v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t')
606 ceqB ps b b' = ceq ps (binderTy b) (binderTy b')
607 ceq ps (App fx ax) (App fy ay) = liftM2 (&&) (ceq ps fx fy) (ceq ps ax ay)
608 ceq ps (Constant x) (Constant y) = return (x == y)
609 ceq ps (TType x) (TType y) = do (v, cs) <- get
610 put (v, ULE x y : cs)
612 ceq ps (UType AllTypes) x = return (isUsableUniverse x)
613 ceq ps x (UType AllTypes) = return (isUsableUniverse x)
614 ceq ps (UType u) (UType v) = return (u == v)
615 ceq ps Erased _ = return True
616 ceq ps _ Erased = return True
617 ceq ps x y = return False
619 caseeq ps (Case _ n cs) (Case _ n' cs') = caseeqA ((n,n'):ps) cs cs'
621 caseeqA ps (ConCase x i as sc : rest) (ConCase x' i' as' sc' : rest')
622 = do q1 <- caseeq (zip as as' ++ ps) sc sc'
623 q2 <- caseeqA ps rest rest'
624 return $ x == x' && i == i' && q1 && q2
625 caseeqA ps (ConstCase x sc : rest) (ConstCase x' sc' : rest')
626 = do q1 <- caseeq ps sc sc'
627 q2 <- caseeqA ps rest rest'
628 return $ x == x' && q1 && q2
629 caseeqA ps (DefaultCase sc : rest) (DefaultCase sc' : rest')
630 = liftM2 (&&) (caseeq ps sc sc') (caseeqA ps rest rest')
631 caseeqA ps [] [] = return True
632 caseeqA ps _ _ = return False
633 caseeq ps (STerm x) (STerm y) = ceq ps x y
634 caseeq ps (UnmatchedCase _) (UnmatchedCase _) = return True
635 caseeq ps _ _ = return False
637 sameDefs ps x y = case (lookupDef x ctxt, lookupDef y ctxt) of
638 ([Function _ xdef], [Function _ ydef])
639 -> ceq ((x,y):ps) xdef ydef
640 ([CaseOp _ _ _ _ _ xd],
641 [CaseOp _ _ _ _ _ yd])
642 -> let (_, xdef) = cases_compiletime xd
643 (_, ydef) = cases_compiletime yd in
644 caseeq ((x,y):ps) xdef ydef
647-- SPECIALISATION -----------------------------------------------------------
648-- We need too much control to be able to do this by tweaking the main
651spec :: Context -> Ctxt [Bool] -> Env -> TT Name -> Eval (TT Name)
652spec ctxt statics genv tm = error "spec undefined"
654-- CONTEXTS -----------------------------------------------------------------
656{-| A definition is either a simple function (just an expression with a type),
657 a constant, which could be a data or type constructor, an axiom or as an
658 yet undefined function, or an Operator.
659 An Operator is a function which explains how to reduce.
660 A CaseOp is a function defined by a simple case tree -}
662data Def = Function !Type !Term
663 | TyDecl NameType !Type
664 | Operator Type Int ([Value] -> Maybe Value)
667 ![Type] -- argument types
668 ![Either Term (Term, Term)] -- original definition
669 ![([Name], Term, Term)] -- simplified for totality check definition
671-- [Name] SC -- Compile time case definition
672-- [Name] SC -- Run time cae definitions
674data CaseDefs = CaseDefs {
675 cases_totcheck :: !([Name], SC),
676 cases_compiletime :: !([Name], SC),
677 cases_inlined :: !([Name], SC),
678 cases_runtime :: !([Name], SC)
681data CaseInfo = CaseInfo {
682 case_inlinable :: Bool, -- decided by machine
683 case_alwaysinline :: Bool, -- decided by %inline flag
684 tc_dictionary :: Bool
688deriving instance Binary Def
691deriving instance Binary CaseInfo
694deriving instance Binary CaseDefs
697deriving instance NFData Def
700deriving instance NFData CaseInfo
703deriving instance NFData CaseDefs
706instance Show Def where
707 show (Function ty tm) = "Function: " ++ show (ty, tm)
708 show (TyDecl nt ty) = "TyDecl: " ++ show nt ++ " " ++ show ty
709 show (Operator ty _ _) = "Operator: " ++ show ty
710 show (CaseOp (CaseInfo inlc inla inlr) ty atys ps_in ps cd)
711 = let (ns, sc) = cases_compiletime cd
712 (ns_t, sc_t) = cases_totcheck cd
713 (ns', sc') = cases_runtime cd in
714 "Case: " ++ show ty ++ " " ++ show ps ++ "\n" ++
715 "TOTALITY CHECK TIME:\n\n" ++
716 show ns_t ++ " " ++ show sc_t ++ "\n\n" ++
717 "COMPILE TIME:\n\n" ++
718 show ns ++ " " ++ show sc ++ "\n\n" ++
720 show ns' ++ " " ++ show sc' ++ "\n\n" ++
721 if inlc then "Inlinable" else "Not inlinable" ++
722 if inla then " Aggressively\n" else "\n"
726-- Frozen => doesn't reduce
727-- Hidden => doesn't reduce and invisible to type checker
729data Accessibility = Public | Frozen | Hidden
732deriving instance NFData Accessibility
735-- | The result of totality checking
736data Totality = Total [Int] -- ^ well-founded arguments
737 | Productive -- ^ productive
742deriving instance NFData Totality
745-- | Reasons why a function may not be total
746data PReason = Other [Name] | Itself | NotCovering | NotPositive | UseUndef Name
747 | ExternalIO | BelieveMe | Mutual [Name] | NotProductive
750deriving instance NFData PReason
753instance Show Totality where
754 show (Total args)= "Total" -- ++ show args ++ " decreasing arguments"
755 show Productive = "Productive" -- ++ show args ++ " decreasing arguments"
756 show Unchecked = "not yet checked for totality"
757 show (Partial Itself) = "possibly not total as it is not well founded"
758 show (Partial NotCovering) = "not total as there are missing cases"
759 show (Partial NotPositive) = "not strictly positive"
760 show (Partial ExternalIO) = "an external IO primitive"
761 show (Partial NotProductive) = "not productive"
762 show (Partial BelieveMe) = "not total due to use of believe_me in proof"
763 show (Partial (Other ns)) = "possibly not total due to: " ++ showSep ", " (map show ns)
764 show (Partial (Mutual ns)) = "possibly not total due to recursive path " ++
765 showSep " --> " (map show ns)
768deriving instance Binary Accessibility
772deriving instance Binary Totality
776deriving instance Binary PReason
779-- Possible attached meta-information for a definition in context
780data MetaInformation =
781 EmptyMI -- ^ No meta-information
782 | DataMI [Int] -- ^ Meta information for a data declaration with position of parameters
785-- | Contexts used for global definitions and for proof state. They contain
786-- universe constraints and existing definitions.
787data Context = MkContext {
789 definitions :: Ctxt (Def, Accessibility, Totality, MetaInformation)
792-- | The initial empty context
793initContext = MkContext 0 emptyContext
795mapDefCtxt :: (Def -> Def) -> Context -> Context
796mapDefCtxt f (MkContext t defs) = MkContext t (mapCtxt f' defs)
797 where f' (d, a, t, m) = f' (f d, a, t, m)
799-- | Get the definitions from a context
800ctxtAlist :: Context -> [(Name, Def)]
801ctxtAlist ctxt = map (\(n, (d, a, t, m)) -> (n, d)) $ toAlist (definitions ctxt)
803veval ctxt env t = evalState (eval False ctxt [] env t []) initEval
805addToCtxt :: Name -> Term -> Type -> Context -> Context
806addToCtxt n tm ty uctxt
807 = let ctxt = definitions uctxt
808 ctxt' = addDef n (Function ty tm, Public, Unchecked, EmptyMI) ctxt in
809 uctxt { definitions = ctxt' }
811setAccess :: Name -> Accessibility -> Context -> Context
813 = let ctxt = definitions uctxt
814 ctxt' = updateDef n (\ (d, _, t, m) -> (d, a, t, m)) ctxt in
815 uctxt { definitions = ctxt' }
817setTotal :: Name -> Totality -> Context -> Context
819 = let ctxt = definitions uctxt
820 ctxt' = updateDef n (\ (d, a, _, m) -> (d, a, t, m)) ctxt in
821 uctxt { definitions = ctxt' }
823setMetaInformation :: Name -> MetaInformation -> Context -> Context
824setMetaInformation n m uctxt
825 = let ctxt = definitions uctxt
826 ctxt' = updateDef n (\ (d, a, t, _) -> (d, a, t, m)) ctxt in
827 uctxt { definitions = ctxt' }
829addCtxtDef :: Name -> Def -> Context -> Context
830addCtxtDef n d c = let ctxt = definitions c
831 ctxt' = addDef n (d, Public, Unchecked, EmptyMI) $! ctxt in
832 c { definitions = ctxt' }
834addTyDecl :: Name -> NameType -> Type -> Context -> Context
835addTyDecl n nt ty uctxt
836 = let ctxt = definitions uctxt
837 ctxt' = addDef n (TyDecl nt ty, Public, Unchecked, EmptyMI) ctxt in
838 uctxt { definitions = ctxt' }
840addDatatype :: Datatype Name -> Context -> Context
841addDatatype (Data n tag ty unique cons) uctxt
842 = let ctxt = definitions uctxt
843 ty' = normalise uctxt [] ty
844 ctxt' = addCons 0 cons (addDef n
845 (TyDecl (TCon tag (arity ty')) ty, Public, Unchecked, EmptyMI) ctxt) in
846 uctxt { definitions = ctxt' }
848 addCons tag [] ctxt = ctxt
849 addCons tag ((n, ty) : cons) ctxt
850 = let ty' = normalise uctxt [] ty in
851 addCons (tag+1) cons (addDef n
852 (TyDecl (DCon tag (arity ty') unique) ty, Public, Unchecked, EmptyMI) ctxt)
854-- FIXME: Too many arguments! Refactor all these Bools.
856-- Issue #1724 on the issue tracker.
857-- https://github.com/idris-lang/Idris-dev/issues/1724
858addCasedef :: Name -> ErasureInfo -> CaseInfo ->
859 Bool -> SC -> -- default case
861 [Type] -> -- argument types
862 [Int] -> -- inaccessible arguments
863 [Either Term (Term, Term)] ->
864 [([Name], Term, Term)] -> -- totality
865 [([Name], Term, Term)] -> -- compile time
866 [([Name], Term, Term)] -> -- inlined
867 [([Name], Term, Term)] -> -- run time
868 Type -> Context -> Context
869addCasedef n ei ci@(CaseInfo inline alwaysInline tcdict)
870 tcase covering reflect asserted argtys inacc
871 ps_in ps_tot ps_inl ps_ct ps_rt ty uctxt
872 = let ctxt = definitions uctxt
873 access = case lookupDefAcc n False uctxt of
876 ctxt' = case (simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_tot ei,
877 simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_ct ei,
878 simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_inl ei,
879 simpleCase tcase covering reflect RunTime emptyFC inacc argtys ps_rt ei) of
880 (OK (CaseDef args_tot sc_tot _),
881 OK (CaseDef args_ct sc_ct _),
882 OK (CaseDef args_inl sc_inl _),
883 OK (CaseDef args_rt sc_rt _)) ->
884 let inl = alwaysInline -- tcdict
885 inlc = (inl || small n args_ct sc_ct) && (not asserted)
886 inlr = inl || small n args_rt sc_rt
887 cdef = CaseDefs (args_tot, sc_tot)
891 addDef n (CaseOp (ci { case_inlinable = inlc })
892 ty argtys ps_in ps_tot cdef,
893 access, Unchecked, EmptyMI) ctxt in
894 uctxt { definitions = ctxt' }
896-- simplify a definition for totality checking
897simplifyCasedef :: Name -> ErasureInfo -> Context -> Context
898simplifyCasedef n ei uctxt
899 = let ctxt = definitions uctxt
900 ctxt' = case lookupCtxt n ctxt of
901 [(CaseOp ci ty atys [] ps _, acc, tot, metainf)] ->
902 ctxt -- nothing to simplify (or already done...)
903 [(CaseOp ci ty atys ps_in ps cd, acc, tot, metainf)] ->
904 let ps_in' = map simpl ps_in
905 pdef = map debind ps_in' in
906 case simpleCase False (STerm Erased) False CompileTime emptyFC [] atys pdef ei of
907 OK (CaseDef args sc _) ->
909 ty atys ps_in' ps (cd { cases_totcheck = (args, sc) }),
910 acc, tot, metainf) ctxt
911 Error err -> error (show err)
913 uctxt { definitions = ctxt' }
915 depat acc (Bind n (PVar t) sc)
916 = depat (n : acc) (instantiate (P Bound n t) sc)
917 depat acc x = (acc, x)
918 debind (Right (x, y)) = let (vs, x') = depat [] x
919 (_, y') = depat [] y in
921 debind (Left x) = let (vs, x') = depat [] x in
923 simpl (Right (x, y)) = Right (x, simplify uctxt [] y)
926addOperator :: Name -> Type -> Int -> ([Value] -> Maybe Value) ->
928addOperator n ty a op uctxt
929 = let ctxt = definitions uctxt
930 ctxt' = addDef n (Operator ty a op, Public, Unchecked, EmptyMI) ctxt in
931 uctxt { definitions = ctxt' }
935lookupNames :: Name -> Context -> [Name]
937 = let ns = lookupCtxtName n (definitions ctxt) in
940-- | Get the list of pairs of fully-qualified names and their types that match some name
941lookupTyName :: Name -> Context -> [(Name, Type)]
942lookupTyName n ctxt = do
943 (name, def) <- lookupCtxtName n (definitions ctxt)
944 ty <- case tfst def of
945 (Function ty _) -> return ty
946 (TyDecl _ ty) -> return ty
947 (Operator ty _ _) -> return ty
948 (CaseOp _ ty _ _ _ _) -> return ty
951-- | Get the pair of a fully-qualified name and its type, if there is a unique one matching the name used as a key.
952lookupTyNameExact :: Name -> Context -> Maybe (Name, Type)
953lookupTyNameExact n ctxt = case lookupTyName n ctxt of
957-- | Get the types that match some name
958lookupTy :: Name -> Context -> [Type]
959lookupTy n ctxt = map snd (lookupTyName n ctxt)
961-- | Get the single type that matches some name precisely
962lookupTyExact :: Name -> Context -> Maybe Type
963lookupTyExact n ctxt = case lookupTy n ctxt of
967isConName :: Name -> Context -> Bool
968isConName n ctxt = isTConName n ctxt || isDConName n ctxt
970isTConName :: Name -> Context -> Bool
972 = case lookupDefExact n ctxt of
973 Just (TyDecl (TCon _ _) _) -> True
976-- | Check whether a resolved name is certainly a data constructor
977isDConName :: Name -> Context -> Bool
979 = case lookupDefExact n ctxt of
980 Just (TyDecl (DCon _ _ _) _) -> True
983-- | Check whether any overloading of a name is a data constructor
984canBeDConName :: Name -> Context -> Bool
986 = or $ do def <- lookupCtxt n (definitions ctxt)
988 (TyDecl (DCon _ _ _) _) -> return True
991isFnName :: Name -> Context -> Bool
993 = case lookupDefExact n ctxt of
994 Just (Function _ _) -> True
995 Just (Operator _ _ _) -> True
996 Just (CaseOp _ _ _ _ _ _) -> True
999isTCDict :: Name -> Context -> Bool
1001 = case lookupDefExact n ctxt of
1002 Just (Function _ _) -> False
1003 Just (Operator _ _ _) -> False
1004 Just (CaseOp ci _ _ _ _ _) -> tc_dictionary ci
1007lookupP :: Name -> Context -> [Term]
1008lookupP = lookupP_all False
1010lookupP_all :: Bool -> Name -> Context -> [Term]
1011lookupP_all all n ctxt
1012 = do def <- lookupCtxt n (definitions ctxt)
1014 (Function ty tm, a, _, _) -> return (P Ref n ty, a)
1015 (TyDecl nt ty, a, _, _) -> return (P nt n ty, a)
1016 (CaseOp _ ty _ _ _ _, a, _, _) -> return (P Ref n ty, a)
1017 (Operator ty _ _, a, _, _) -> return (P Ref n ty, a)
1019 Hidden -> if all then return (fst p) else []
1022lookupDefExact :: Name -> Context -> Maybe Def
1023lookupDefExact n ctxt = tfst <$> lookupCtxtExact n (definitions ctxt)
1025lookupDef :: Name -> Context -> [Def]
1026lookupDef n ctxt = tfst <$> lookupCtxt n (definitions ctxt)
1028lookupNameDef :: Name -> Context -> [(Name, Def)]
1029lookupNameDef n ctxt = mapSnd tfst $ lookupCtxtName n (definitions ctxt)
1030 where mapSnd f [] = []
1031 mapSnd f ((x,y):xys) = (x, f y) : mapSnd f xys
1033lookupDefAcc :: Name -> Bool -> Context ->
1034 [(Def, Accessibility)]
1035lookupDefAcc n mkpublic ctxt
1036 = map mkp $ lookupCtxt n (definitions ctxt)
1037 -- io_bind a special case for REPL prettiness
1038 where mkp (d, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_return"))
1039 then (d, Public) else (d, a)
1041lookupDefAccExact :: Name -> Bool -> Context ->
1042 Maybe (Def, Accessibility)
1043lookupDefAccExact n mkpublic ctxt
1044 = fmap mkp $ lookupCtxtExact n (definitions ctxt)
1045 -- io_bind a special case for REPL prettiness
1046 where mkp (d, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_return"))
1047 then (d, Public) else (d, a)
1049lookupTotal :: Name -> Context -> [Totality]
1050lookupTotal n ctxt = map mkt $ lookupCtxt n (definitions ctxt)
1051 where mkt (d, a, t, m) = t
1053lookupMetaInformation :: Name -> Context -> [MetaInformation]
1054lookupMetaInformation n ctxt = map mkm $ lookupCtxt n (definitions ctxt)
1055 where mkm (d, a, t, m) = m
1057lookupNameTotal :: Name -> Context -> [(Name, Totality)]
1058lookupNameTotal n = map (\(n, (_, _, t, _)) -> (n, t)) . lookupCtxtName n . definitions
1061lookupVal :: Name -> Context -> [Value]
1063 = do def <- lookupCtxt n (definitions ctxt)
1065 (Function _ htm) -> return (veval ctxt [] htm)
1066 (TyDecl nt ty) -> return (VP nt n (veval ctxt [] ty))
1068lookupTyEnv :: Name -> Env -> Maybe (Int, Type)
1069lookupTyEnv n env = li n 0 env where
1072 | n == x = Just (i, binderTy b)
1073 | otherwise = li n (i+1) xs
1075-- | Create a unique name given context and other existing names
1076uniqueNameCtxt :: Context -> Name -> [Name] -> Name
1077uniqueNameCtxt ctxt n hs
1078 | n `elem` hs = uniqueNameCtxt ctxt (nextName n) hs
1079 | [_] <- lookupTy n ctxt = uniqueNameCtxt ctxt (nextName n) hs
1082uniqueBindersCtxt :: Context -> [Name] -> TT Name -> TT Name
1083uniqueBindersCtxt ctxt ns (Bind n b sc)
1084 = let n' = uniqueNameCtxt ctxt n ns in
1085 Bind n' (fmap (uniqueBindersCtxt ctxt (n':ns)) b) (uniqueBindersCtxt ctxt ns sc)
1086uniqueBindersCtxt ctxt ns (App f a) = App (uniqueBindersCtxt ctxt ns f) (uniqueBindersCtxt ctxt ns a)
1087uniqueBindersCtxt ctxt ns t = t
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list