2Module : Idris.Termination
3Description : The termination checker for Idris
6Maintainer : The Idris Community.
8{-# LANGUAGE PatternGuards #-}
9module Idris.Termination (buildSCG, checkAllCovering, checkDeclTotality,
10 checkIfGuarded, checkPositive, checkSizeChange,
14import Idris.Core.CaseTree
15import Idris.Core.Evaluate
17import Idris.Delaborate
20import Idris.Output (iWarn)
22import Control.Monad.State.Strict
28-- | Check whether function and all descendants cover all cases
29-- (partial is okay, as long as it's due to recursion)
30checkAllCovering :: FC -> [Name] -> Name -> Name -> Idris ()
31checkAllCovering fc done top n | not (n `elem` done)
33 case lookupTotal n (tt_ctxt i) of
34 [tot@(Partial NotCovering)] ->
35 do let msg = show top ++ " is " ++ show tot ++ " due to " ++ show n
36 putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i }
37 addIBC (IBCTotCheckErr fc msg)
38 [Partial (Other ns)] ->
39 -- Check that none of the partial functions it relies
40 -- on are partial due to missing cases
41 mapM_ (checkAllCovering fc (n : done) top) ns
42 x -> return () -- stop if total, or partial due to recursion
43checkAllCovering _ _ _ _ = return ()
45-- | Check whether all 'Inf' arguments to the name end up guaranteed to be
46-- guarded by constructors (conservatively... maybe this can do better later).
47-- Essentially, all it does is check that every branch is a constructor application
48-- with no other function applications.
50-- If so, set the 'AllGuarded' flag which can be used by the productivity check
51checkIfGuarded :: Name -> Idris ()
55 case lookupDefExact n ctxt of
56 Just (CaseOp _ ty _ _ _ cases) ->
57 let gnames = fst (cases_compiletime cases) in
58 if allGuarded gnames i (snd (cases_compiletime cases))
59 then -- trace (show (n, gnames, ty, cases_compiletime cases)) $
64 guard n ist = isConName n (tt_ctxt ist) || guardFlag n ist
65 guardFlag n ist = case lookupCtxtExact n (idris_flags ist) of
67 Just fs -> AllGuarded `elem` fs
69 -- Top level thing always needs to be a constructor application if
70 -- the delayed things are going to be definitely guarded by this definition
71 allGuarded names i (STerm t)
72 | (P _ fn _, args) <- unApply t,
74 = and (map (guardedTerm names i) args)
76 allGuarded names i (ProjCase _ alts) = and (map (guardedAlt names i) alts)
77 allGuarded names i (Case _ _ alts) = and (map (guardedAlt names i) alts)
78 allGuarded names i _ = True
80 guardedTerm names i (P _ v _) = v `elem` names || guard v i
81 guardedTerm names i (Bind n (Let rig t v) sc)
82 = guardedTerm names i v && guardedTerm names i sc
83 guardedTerm names i (Bind n b sc) = False
84 guardedTerm names i ap@(App _ _ _)
85 | (P _ fn _, args) <- unApply ap,
86 guard fn i || fn `elem` names
87 = and (map (guardedTerm names i) args)
88 guardedTerm names i (App _ f a) = False
89 guardedTerm names i tm = True
91 guardedAlt names i (ConCase _ _ _ t) = allGuarded names i t
92 guardedAlt names i (FnCase _ _ t) = allGuarded names i t
93 guardedAlt names i (ConstCase _ t) = allGuarded names i t
94 guardedAlt names i (SucCase _ t) = allGuarded names i t
95 guardedAlt names i (DefaultCase t) = allGuarded names i t
97-- | Check if, in a given group of type declarations mut_ns, the
98-- constructor cn : ty is strictly positive, and update the context
100checkPositive :: [Name] -- ^ the group of type declarations
101 -> (Name, Type) -- ^ the constructor
103checkPositive mut_ns (cn, ty')
105 let ty = delazy' True (normalise (tt_ctxt i) [] ty')
107 let tot = if p then Total (args ty) else Partial NotPositive
108 let ctxt' = setTotal cn tot (tt_ctxt i)
109 putIState (i { tt_ctxt = ctxt' })
110 logCoverage 5 $ "Constructor " ++ show cn ++ " is " ++ show tot ++ " with " ++ show mut_ns
111 addIBC (IBCTotal cn tot)
114 args t = [0..length (getArgTys t)-1]
116 cp i (Bind n (Pi _ _ aty _) sc)
117 = posArg i aty && cp i sc
118 cp i t | (P _ n' _ , args) <- unApply t,
119 n' `elem` mut_ns = all noRec args
122 posArg ist (Bind _ (Pi _ _ nty _) sc) = noRec nty && posArg ist sc
123 posArg ist t = posParams ist t
125 noRec arg = all (\x -> x `notElem` mut_ns) (allTTNames arg)
127 -- If the type appears recursively in a parameter argument, that's
128 -- fine, otherwise if it appears in an argument it's not fine.
129 posParams ist t | (P _ n _, args) <- unApply t
130 = case lookupCtxtExact n (idris_datatypes ist) of
131 Just ti -> checkParamsOK (param_pos ti) 0 args
132 Nothing -> and (map (posParams ist) args)
133 posParams ist t = noRec t
135 checkParamsOK ppos i [] = True
136 checkParamsOK ppos i (p : ps)
137 | i `elem` ppos = checkParamsOK ppos (i + 1) ps
138 | otherwise = noRec p && checkParamsOK ppos (i + 1) ps
140-- | Calculate the totality of a function from its patterns. Either
141-- follow the size change graph (if inductive) or check for
142-- productivity (if coinductive)
143calcTotality :: FC -> Name -> [([Name], Term, Term)] -> Idris Totality
144calcTotality fc n pats
146 case mapMaybe (checkLHS i) (map (\ (_, l, r) -> l) pats) of
147 (failure : _) -> return failure
148 _ -> checkSizeChange n
150 checkLHS i (P _ fn _)
151 = case lookupTotalExact fn (tt_ctxt i) of
152 Just (Partial _) -> return (Partial (Other [fn]))
154 checkLHS i (App _ f a) = mplus (checkLHS i f) (checkLHS i a)
155 checkLHS _ _ = Nothing
157checkTotality :: [Name] -> FC -> Name -> Idris Totality
158checkTotality path fc n
159 | n `elem` path = return (Partial (Mutual (n : path)))
163 ctxt' <- do ctxt <- getContext
164 tclift $ simplifyCasedef n [] [] (getErasureInfo i) ctxt
168 let opts = case lookupCtxt n (idris_flags i) of
173 case lookupDef n ctxt of
174 [CaseOp _ _ _ _ pats _] ->
175 do t' <- if AssertTotal `elem` opts
176 then return $ Total []
177 else calcTotality fc n pats
178 logCoverage 2 $ "Set to " ++ show t'
180 addIBC (IBCTotal n t')
182 [TyDecl (DCon _ _ _) ty] ->
183 case unApply (getRetTy ty) of
185 let ms = case lookupCtxt tyn (idris_datatypes i) of
186 [TI _ _ _ _ xs@(_:_) _] -> xs
188 checkPositive ms (n, ty)
189 _-> return $ Total []
190 _ -> return $ Total []
194 Productive -> return t'
195 e -> do w <- cmdOptType WarnPartial
196 if TotalFn `elem` opts
197 then do totalityError t'; return t'
198 else do when (w && not (PartialFn `elem` opts)) $
202 totalityError t = do i <- getIState
203 let msg = show n ++ " is " ++ show t
204 putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i}
205 addIBC (IBCTotCheckErr fc msg)
209 case lookupDef n (tt_ctxt i) of
211 iWarn fc . pprintErr i . Msg $ "Warning - " ++ show n ++ " is " ++ show t
213-- let cg = lookupCtxtName Nothing n (idris_callgraph i)
214-- iputStrLn (show cg)
217checkDeclTotality :: (FC, Name) -> Idris Totality
218checkDeclTotality (fc, n)
219 = do logCoverage 2 $ "Checking " ++ show n ++ " for totality"
221 let opts = case lookupCtxtExact n (idris_flags i) of
224 when (CoveringFn `elem` opts) $ checkAllCovering fc [] n n
225 t <- checkTotality [] fc n
228-- If the name calls something which is partial, set it as partial
229verifyTotality :: (FC, Name) -> Idris ()
230verifyTotality (fc, n)
231 = do logCoverage 2 $ "Checking " ++ show n ++ "'s descendents are total"
233 case lookupTotalExact n (tt_ctxt ist) of
235 let ns = getNames (tt_ctxt ist)
237 case getPartial ist [] ns of
239 Just bad -> do let t' = Partial (Other bad)
240 logCoverage 2 $ "Set in verify to " ++ show t'
242 addIBC (IBCTotal n t')
245 getNames ctxt = case lookupDefExact n ctxt of
246 Just (CaseOp _ _ _ _ _ defs)
247 -> let (top, def) = cases_compiletime defs in
248 map fst (findCalls' True def top)
251 getPartial ist [] [] = Nothing
252 getPartial ist bad [] = Just bad
253 getPartial ist bad (n : ns)
254 = case lookupTotalExact n (tt_ctxt ist) of
255 Just (Partial _) -> getPartial ist (n : bad) ns
256 _ -> getPartial ist bad ns
258-- | Calculate the size change graph for this definition
260-- SCG for a function f consists of a list of:
261-- (g, [(a1, sizechange1), (a2, sizechange2), ..., (an, sizechangen)])
263-- where g is a function called
264-- a1 ... an are the arguments of f in positions 1..n of g
265-- sizechange1 ... sizechange2 is how their size has changed wrt the input
267-- Nothing, if the argument is unrelated to the input
268buildSCG :: (FC, Name) -> Idris ()
271 case lookupCtxtExact n (idris_callgraph ist) of
272 Just cg -> case lookupDefExact n (tt_ctxt ist) of
273 Just (CaseOp _ _ _ pats _ cd) ->
274 let (args, sc) = cases_compiletime cd in
275 do logCoverage 2 $ "Building SCG for " ++ show n ++ " from\n"
276 ++ show pats ++ "\n" ++ show sc
277 let newscg = buildSCG' ist n (rights pats) args
278 logCoverage 5 $ "SCG is: " ++ show newscg
279 addToCG n ( cg { scg = newscg } )
280 _ -> return () -- CG comes from a type declaration only
281 _ -> logCoverage 5 $ "Could not build SCG for " ++ show n ++ "\n"
283delazy = delazy' False -- not lazy codata
284delazy' all t@(App _ f a)
285 | (P _ (UN l) _, [P _ (UN lty) _, _, arg]) <- unApply t,
286 l == txt "Force" && (all || lty /= txt "Infinite") = delazy' all arg
287 | (P _ (UN l) _, [P _ (UN lty) _, _, arg]) <- unApply t,
288 l == txt "Delay" && (all || lty /= txt "Infinite") = delazy arg
289 | (P _ (UN l) _, [P _ (UN lty) _, arg]) <- unApply t,
290 l == txt "Delayed" && (all || lty /= txt "Infinite") = delazy' all arg
291delazy' all (App s f a) = App s (delazy' all f) (delazy' all a)
292delazy' all (Bind n b sc) = Bind n (fmap (delazy' all) b) (delazy' all sc)
295data Guardedness = Toplevel | Unguarded | Guarded | Delayed
298buildSCG' :: IState -> Name -> [(Term, Term)] -> [Name] -> [SCGEntry]
299buildSCG' ist topfn pats args = nub $ concatMap scgPat pats where
300 scgPat (lhs, rhs) = let lhs' = delazy lhs
302 (_, pargs) = unApply (dePat lhs') in
303 findCalls [] Toplevel (dePat rhs') (patvars lhs')
306 -- Under a delay, calls are excluded from the graph - if it's a call to a
307 -- non-total function we'll find that in the final totality check
308 findCalls cases Delayed ap@(P _ n _) pvs args = []
309 findCalls cases guarded ap@(App _ f a) pvs pargs
310 -- under a call to "assert_total", don't do any checking, just believe
312 | (P _ (UN at) _, [_, _]) <- unApply ap,
313 at == txt "assert_total" = []
314 -- don't go under calls to functions which are asserted total
315 | (P _ n _, _) <- unApply ap,
316 Just opts <- lookupCtxtExact n (idris_flags ist),
317 AssertTotal `elem` opts = []
318 -- under a guarded call to "Delay Infinite", we are 'Delayed', so don't
319 -- check under guarded constructors.
320 | (P _ (UN del) _, [_,_,arg]) <- unApply ap,
323 = findCalls cases Delayed arg pvs pargs
324 | (P _ n _, args) <- unApply ap,
326 isConName n (tt_ctxt ist) || allGuarded n ist
327 = -- Still under a 'Delay' and constructor guarded, so check
328 -- just the arguments to the constructor, remaining Delayed
329 concatMap (\x -> findCalls cases guarded x pvs pargs) args
330 | (P _ ifthenelse _, [_, _, t, e]) <- unApply ap,
331 ifthenelse == sNS (sUN "ifThenElse") ["Bool", "Prelude"]
332 -- Continue look inside if...then...else blocks
333 -- TODO: Consider whether we should do this for user defined ifThenElse
334 -- rather than just the one in the Prelude as a special case
335 = findCalls cases guarded t pvs pargs ++
336 findCalls cases guarded e pvs pargs
337 | (P _ n _, args) <- unApply ap,
338 caseName n && n /= topfn,
339 notPartial (lookupTotalExact n (tt_ctxt ist))
340 -- case block - look inside the block, as long as it was covering
341 -- (i.e. not currently set at Partial) to get a more accurate size
342 -- change result from the top level patterns (also to help pass
343 -- information through from guarded corecursion accurately)
344 = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args ++
346 then findCallsCase (n : cases) guarded n args pvs pargs
348 | (P _ n _, args) <- unApply ap,
350 -- Under a delayed recursive call just check the arguments
351 = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args
352 | (P _ n _, args) <- unApply ap,
354 -- Ordinary call, not under a delay.
355 -- If n is a constructor, set 'args' as Guarded
356 = let nguarded = case guarded of
357 Unguarded -> Unguarded
358 x -> if isConName n (tt_ctxt ist)
362 mkChange n args pargs ++
363 concatMap (\x -> findCalls cases nguarded x pvs pargs) args
364 where notPartial (Just (Partial NotCovering)) = False
366 findCalls cases guarded (App _ f a) pvs pargs
367 = findCalls cases Unguarded f pvs pargs ++ findCalls cases Unguarded a pvs pargs
368 findCalls cases guarded (Bind n (Let rig t v) e) pvs pargs
369 = findCalls cases Unguarded t pvs pargs ++
370 findCalls cases Unguarded v pvs pargs ++
371 -- Substitute in the scope since this might reveal some useful
373 findCalls cases guarded (substV v e) pvs pargs
374 findCalls cases guarded (Bind n t e) pvs pargs
375 = findCalls cases Unguarded (binderTy t) pvs pargs ++
376 findCalls cases guarded e (n : pvs) pargs
377 findCalls cases guarded (P _ f _ ) pvs pargs
378 | not (f `elem` pvs) = [(f, [])]
379 findCalls _ _ _ _ _ = []
381 -- Assumption is that names are preserved in the case block (shadowing
382 -- dealt with by the elaborator) so we can just assume the top level names
383 -- are okay for building the size change
384 findCallsCase cases guarded n args pvs pargs
385 = case lookupDefExact n (tt_ctxt ist) of
386 Just (CaseOp _ _ _ pats _ cd) ->
387 concatMap (fccPat cases pvs pargs args guarded) (rights pats)
390 fccPat cases pvs pargs args g (lhs, rhs)
391 = let lhs' = delazy lhs
393 (_, pargs_case) = unApply (dePat lhs')
394 -- pargs is a pair of a term, and the argument position that
395 -- term appears in. If any of the arguments to the case block
396 -- are also on the lhs, we also want those patterns to appear
397 -- in the parg list so that we'll spot patterns which are
399 newpargs = newPArg args pargs
400 -- Now need to update the rhs of the case with the names in the
401 -- outer definition: In rhs', wherever we see what's in pargs_case,
402 -- replace it with the corresponding thing in pargs
403 csubs = zip pargs_case args
404 newrhs = doCaseSubs csubs (dePat rhs')
405 pargs' = pargs ++ addPArg newpargs pargs_case in
406 findCalls cases g newrhs pvs pargs'
408 doCaseSubs [] tm = tm
409 doCaseSubs ((x, x') : cs) tm
410 = doCaseSubs (subIn x x' cs) (substTerm x x' tm)
413 subIn x x' ((l, r) : cs)
414 = (substTerm x x' l, substTerm x x' r) : subIn x x' cs
416 addPArg (Just (t, i) : ts) (t' : ts') = (t', i) : addPArg ts ts'
417 addPArg (Nothing : ts) (t' : ts') = addPArg ts ts'
420 newPArg :: [Term] -> [(Term, Int)] -> [Maybe (Term, Int)]
421 newPArg (t : ts) pargs = case lookup t pargs of
422 Just i -> Just (t, i) : newPArg ts pargs
423 Nothing -> Nothing : newPArg ts pargs
424 newPArg [] pargs = []
427 = case lookupTy n (tt_ctxt ist) of
428 [ty] -> expand 0 (normalise (tt_ctxt ist) [] ty) args
430 where expand i (Bind n (Pi _ _ _ _) sc) (x : xs) = x : expand (i + 1) sc xs
431 expand i (Bind n (Pi _ _ _ _) sc) [] = Nothing : expand (i + 1) sc []
434 mkChange n args pargs = [(n, expandToArity n (sizes args))]
437 sizes (a : as) = checkSize a pargs : sizes as
439 -- find which argument in pargs <a> is smaller than, if any
440 checkSize a ((p, i) : ps)
441 | a == p = Just (i, Same)
442 | (P _ (UN as) _, [_,_,arg,_]) <- unApply a,
443 as == txt "assert_smaller" && arg == p
445 | smaller Nothing a (p, Nothing) = Just (i, Smaller)
446 | otherwise = checkSize a ps
447 checkSize a [] = Nothing
449 -- Can't be smaller than an erased thing (need to be careful here
450 -- because Erased equals everything)
451 smaller _ _ (Erased, _) = False -- never smaller than an erased thing
452 -- If a == t, and we're under a cosntructor, we've found something
454 smaller (Just tyn) a (t, Just tyt) | a == t = True
455 smaller ty a (ap@(App _ f s), _)
456 -- Nothing can be smaller than a delayed infinite thing...
457 | (P (DCon _ _ _) (UN d) _, [P _ (UN reason) _, _, _]) <- unApply ap,
458 d == txt "Delay" && reason == txt "Infinite"
460 | (P (DCon _ _ _) n _, args) <- unApply ap
461 = let tyn = getType n in
462 any (smaller (ty `mplus` Just tyn) a)
463 (zip args (map toJust (getArgTys tyn)))
464 -- check higher order recursive arguments
465 smaller ty (App _ f s) a = smaller ty f a
466 smaller _ _ _ = False
468 toJust (n, t) = Just t
470 getType n = case lookupTyExact n (tt_ctxt ist) of
471 Just ty -> delazy (normalise (tt_ctxt ist) [] ty) -- must exist
473 dePat (Bind x (PVar _ ty) sc) = dePat (instantiate (P Bound x ty) sc)
476 patvars (Bind x (PVar _ _) sc) = x : patvars sc
479 allGuarded n ist = case lookupCtxtExact n (idris_flags ist) of
481 Just fs -> AllGuarded `elem` fs
483checkSizeChange :: Name -> Idris Totality
484checkSizeChange n = do
486 case lookupCtxt n (idris_callgraph ist) of
487 [cg] -> do let ms = mkMultiPaths ist [] (scg cg)
488 logCoverage 5 ("Multipath for " ++ show n ++ ":\n" ++
489 "from " ++ show (scg cg) ++ "\n" ++
490 show (length ms) ++ "\n" ++
491 showSep "\n" (map show ms))
492 logCoverage 6 (show cg)
493 -- every multipath must have an infinitely descending
494 -- thread, then the function terminates
495 -- also need to checks functions called are all total
496 -- (Unchecked is okay as we'll spot problems here)
497 let tot = map (checkMP ist n (getArity ist n)) ms
498 logCoverage 4 $ "Generated " ++ show (length tot) ++ " paths"
499 logCoverage 5 $ "Paths for " ++ show n ++ " yield " ++
500 (showSep "\n" (map show (zip ms tot)))
501 return (noPartial tot)
502 [] -> do logCoverage 5 $ "No paths for " ++ show n
505 = case lookupTy n (tt_ctxt ist) of
506 [ty] -> arity (normalise (tt_ctxt ist) [] ty)
507 _ -> error "Can't happen: checkSizeChange.getArity"
509type MultiPath = [SCGEntry]
511mkMultiPaths :: IState -> MultiPath -> [SCGEntry] -> [MultiPath]
512mkMultiPaths ist path [] = [reverse path]
513mkMultiPaths ist path cg = concatMap extend cg
514 where extend (nextf, args)
515 | (nextf, args) `inPath` path = [ reverse ((nextf, args) : path) ]
516 | [Unchecked] <- lookupTotal nextf (tt_ctxt ist)
517 = case lookupCtxt nextf (idris_callgraph ist) of
518 [ncg] -> mkMultiPaths ist ((nextf, args) : path) (scg ncg)
519 _ -> [ reverse ((nextf, args) : path) ]
520 | otherwise = [ reverse ((nextf, args) : path) ]
522 inPath :: SCGEntry -> [SCGEntry] -> Bool
524 inPath f (g : gs) = smallerEq f g || f == g || inPath f gs
526 smallerEq :: SCGEntry -> SCGEntry -> Bool
527 smallerEq (f, args) (g, args')
528 = f == g && not (null (filter smallers args))
529 && filter smallers args == filter smallers args'
530 smallers (Just (_, Smaller)) = True
533-- If any route along the multipath leads to infinite descent, we're fine.
534-- Try a route beginning with every argument.
535-- If we reach a point we've been to before, but with a smaller value,
536-- that means there is an infinitely descending path from that argument.
538checkMP :: IState -> Name -> Int -> MultiPath -> Totality
539checkMP ist topfn i mp = if i > 0
540 then let paths = (map (tryPath 0 [] mp) [0..i-1]) in
541-- trace ("Paths " ++ show paths) $
543 else tryPath 0 [] mp 0
545 mkBig (e, d) = (e, 10000)
547 tryPath :: Int -> [((SCGEntry, Int), Int)] -> MultiPath -> Int -> Totality
548 tryPath desc path [] _ = Total []
549-- tryPath desc path ((UN "believe_me", _) : _) arg
550-- = Partial BelieveMe
551 -- if we get to a constructor, it's fine as long as it's strictly positive
552 tryPath desc path ((f, _) : es) arg
553 | [TyDecl (DCon _ _ _) _] <- lookupDef f (tt_ctxt ist)
554 = case lookupTotalExact f (tt_ctxt ist) of
555 Just (Total _) -> Unchecked -- okay so far
556 Just (Partial _) -> Partial (Other [f])
557 x -> Unchecked -- An error elsewhere, set as Unchecked to make
559 | [TyDecl (TCon _ _) _] <- lookupDef f (tt_ctxt ist)
561 tryPath desc path (e@(f, args) : es) arg
562 | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
563 | e `elem` es && allNothing args = Partial (Mutual [f])
564 tryPath desc path (e@(f, nextargs) : es) arg
565 | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
566 | [Partial _] <- lookupTotal f (tt_ctxt ist) = Partial (Other [f])
567 | Just d <- lookup (e, arg) path
568 = if desc - d > 0 -- Now lower than when we were last here
569 then -- trace ("Descent " ++ show (desc - d) ++ " "
570 -- ++ show (path, e)) $
572 else Partial (Mutual (map (fst . fst . fst) path ++ [f]))
573 | e `elem` map (fst . fst) path
574 && not (f `elem` map fst es)
575 = Partial (Mutual (map (fst . fst . fst) path ++ [f]))
576 | [Unchecked] <- lookupTotal f (tt_ctxt ist) =
577 let argspos = zip nextargs [0..]
579 do (a, pos) <- argspos
581 Nothing -> -- gone up, but if the
582 -- rest definitely terminates without any
583 -- cycles (including the path so far, which
584 -- we take as inaccessible) the path is fine
585 return $ tryPath 0 (map mkBig (((e, arg), desc) : path)) es pos
586 Just (nextarg, sc) ->
587 if nextarg == arg then
589 Same -> return $ tryPath desc (((e, arg), desc) : path)
591 Smaller -> return $ tryPath (desc+1)
592 (((e, arg), desc) : path)
595 _ -> trace ("Shouldn't happen " ++ show e) $
596 return (Partial Itself)
597 else return Unchecked in
598-- trace (show (desc, argspos, path, es, pathres)) $
601 | otherwise = Unchecked
603allNothing :: [Maybe a] -> Bool
604allNothing xs = null (collapseNothing (zip xs [0..]))
606collapseNothing :: [(Maybe a, b)] -> [(Maybe a, b)]
607collapseNothing ((Nothing, t) : xs)
608 = (Nothing, t) : filter (\ (x, _) -> case x of
611collapseNothing (x : xs) = x : collapseNothing xs
612collapseNothing [] = []
614noPartial :: [Totality] -> Totality
615noPartial (Partial p : xs) = Partial p
616noPartial (_ : xs) = noPartial xs
617noPartial [] = Total []
619collapse :: [Totality] -> Totality
620collapse xs = collapse' Unchecked xs
621collapse' def (Total r : xs) = Total r
622collapse' def (Unchecked : xs) = collapse' def xs
623collapse' def (d : xs) = collapse' d xs
624-- collapse' Unchecked [] = Total []
625collapse' def [] = def
627-- totalityCheckBlock :: Idris ()
628-- totalityCheckBlock = do
630-- -- Do totality checking after entire mutual block
631-- mapM_ (\n -> do logElab 5 $ "Simplifying " ++ show n
632-- ctxt' <- do ctxt <- getContext
633-- tclift $ simplifyCasedef n (getErasureInfo ist) ctxt
635-- (map snd (idris_totcheck ist))
636-- mapM_ buildSCG (idris_totcheck ist)
637-- mapM_ checkDeclTotality (idris_totcheck ist)
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