@@ -1,6 +1,6 @@
2Module : Idris.Coverage
2Module : Idris.Coverage
3−Description : The coverage and totality checkers for Idris are in this module.
3+Description : Clause generation for coverage checking
5License : BSD3
5License : BSD3
6Maintainer : The Idris Community.
6Maintainer : The Idris Community.
@@ -362,626 +362,3 @@ genAll i (addPH, args)
362upd :: t -> PArg' t -> PArg' t
362upd :: t -> PArg' t -> PArg' t
363upd p' p = p { getTm = p' }
363upd p' p = p { getTm = p' }
365−-- | Check whether function and all descendants cover all cases
366−-- (partial is okay, as long as it's due to recursion)
367−checkAllCovering :: FC -> [Name] -> Name -> Name -> Idris ()
368−checkAllCovering fc done top n | not (n `elem` done)
370− case lookupTotal n (tt_ctxt i) of
371− [tot@(Partial NotCovering)] ->
372− do let msg = show top ++ " is " ++ show tot ++ " due to " ++ show n
373− putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i }
374− addIBC (IBCTotCheckErr fc msg)
376− case lookupCtxt n (idris_callgraph i) of
377− [cg] -> mapM_ (checkAllCovering fc (n : done) top)
380− x -> return () -- stop if total
381−checkAllCovering _ _ _ _ = return ()
383−-- | Check whether all 'Inf' arguments to the name end up guaranteed to be
384−-- guarded by constructors (conservatively... maybe this can do better later).
385−-- Essentially, all it does is check that every branch is a constructor application
386−-- with no other function applications.
388−-- If so, set the 'AllGuarded' flag which can be used by the productivity check
389−checkIfGuarded :: Name -> Idris ()
392− let ctxt = tt_ctxt i
393− case lookupDefExact n ctxt of
394− Just (CaseOp _ ty _ _ _ cases) ->
395− let gnames = fst (cases_compiletime cases) in
396− if allGuarded gnames i (snd (cases_compiletime cases))
397− then -- trace (show (n, gnames, ty, cases_compiletime cases)) $
398− addFnOpt n AllGuarded
402− guard n ist = isConName n (tt_ctxt ist) || guardFlag n ist
403− guardFlag n ist = case lookupCtxtExact n (idris_flags ist) of
405− Just fs -> AllGuarded `elem` fs
407− -- Top level thing always needs to be a constructor application if
408− -- the delayed things are going to be definitely guarded by this definition
409− allGuarded names i (STerm t)
410− | (P _ fn _, args) <- unApply t,
412− = and (map (guardedTerm names i) args)
414− allGuarded names i (ProjCase _ alts) = and (map (guardedAlt names i) alts)
415− allGuarded names i (Case _ _ alts) = and (map (guardedAlt names i) alts)
416− allGuarded names i _ = True
418− guardedTerm names i (P _ v _) = v `elem` names || guard v i
419− guardedTerm names i (Bind n (Let t v) sc)
420− = guardedTerm names i v && guardedTerm names i sc
421− guardedTerm names i (Bind n b sc) = False
422− guardedTerm names i ap@(App _ _ _)
423− | (P _ fn _, args) <- unApply ap,
424− guard fn i || fn `elem` names
425− = and (map (guardedTerm names i) args)
426− guardedTerm names i (App _ f a) = False
427− guardedTerm names i tm = True
429− guardedAlt names i (ConCase _ _ _ t) = allGuarded names i t
430− guardedAlt names i (FnCase _ _ t) = allGuarded names i t
431− guardedAlt names i (ConstCase _ t) = allGuarded names i t
432− guardedAlt names i (SucCase _ t) = allGuarded names i t
433− guardedAlt names i (DefaultCase t) = allGuarded names i t
435−-- | Check if, in a given group of type declarations mut_ns, the
436−-- constructor cn : ty is strictly positive, and update the context
438−checkPositive :: [Name] -- ^ the group of type declarations
439− -> (Name, Type) -- ^ the constructor
441−checkPositive mut_ns (cn, ty')
443− let ty = delazy' True (normalise (tt_ctxt i) [] ty')
445− let tot = if p then Total (args ty) else Partial NotPositive
446− let ctxt' = setTotal cn tot (tt_ctxt i)
447− putIState (i { tt_ctxt = ctxt' })
448− logCoverage 5 $ "Constructor " ++ show cn ++ " is " ++ show tot ++ " with " ++ show mut_ns
449− addIBC (IBCTotal cn tot)
452− args t = [0..length (getArgTys t)-1]
454− cp i (Bind n (Pi _ aty _) sc)
455− = posArg i aty && cp i sc
456− cp i t | (P _ n' _ , args) <- unApply t,
457− n' `elem` mut_ns = all noRec args
460− posArg ist (Bind _ (Pi _ nty _) sc) = noRec nty && posArg ist sc
461− posArg ist t = posParams ist t
463− noRec arg = all (\x -> x `notElem` mut_ns) (allTTNames arg)
465− -- If the type appears recursively in a parameter argument, that's
466− -- fine, otherwise if it appears in an argument it's not fine.
467− posParams ist t | (P _ n _, args) <- unApply t
468− = case lookupCtxtExact n (idris_datatypes ist) of
469− Just ti -> checkParamsOK (param_pos ti) 0 args
470− Nothing -> and (map (posParams ist) args)
471− posParams ist t = noRec t
473− checkParamsOK ppos i [] = True
474− checkParamsOK ppos i (p : ps)
475− | i `elem` ppos = checkParamsOK ppos (i + 1) ps
476− | otherwise = noRec p && checkParamsOK ppos (i + 1) ps
478−-- | Calculate the totality of a function from its patterns. Either
479−-- follow the size change graph (if inductive) or check for
480−-- productivity (if coinductive)
481−calcTotality :: FC -> Name -> [([Name], Term, Term)] -> Idris Totality
482−calcTotality fc n pats
484− let opts = case lookupCtxt n (idris_flags i) of
487− case mapMaybe (checkLHS i) (map (\ (_, l, r) -> l) pats) of
488− (failure : _) -> return failure
489− _ -> checkSizeChange n
491− checkLHS i (P _ fn _)
492− = case lookupTotalExact fn (tt_ctxt i) of
493− Just (Partial _) -> return (Partial (Other [fn]))
495− checkLHS i (App _ f a) = mplus (checkLHS i f) (checkLHS i a)
496− checkLHS _ _ = Nothing
498−checkTotality :: [Name] -> FC -> Name -> Idris Totality
499−checkTotality path fc n
500− | n `elem` path = return (Partial (Mutual (n : path)))
504− ctxt' <- do ctxt <- getContext
505− tclift $ simplifyCasedef n (getErasureInfo i) ctxt
509− let opts = case lookupCtxt n (idris_flags i) of
514− case lookupDef n ctxt of
515− [CaseOp _ _ _ _ pats _] ->
516− do t' <- if AssertTotal `elem` opts
517− then return $ Total []
518− else calcTotality fc n pats
519− logCoverage 2 $ "Set to " ++ show t'
521− addIBC (IBCTotal n t')
523− [TyDecl (DCon _ _ _) ty] ->
524− case unApply (getRetTy ty) of
525− (P _ tyn _, _) -> do
526− let ms = case lookupCtxt tyn (idris_datatypes i) of
527− [TI _ _ _ _ xs@(_:_)] -> xs
529− checkPositive ms (n, ty)
530− _-> return $ Total []
531− _ -> return $ Total []
534− Total _ -> return t'
535− Productive -> return t'
536− e -> do w <- cmdOptType WarnPartial
537− if TotalFn `elem` opts
538− then do totalityError t'; return t'
539− else do when (w && not (PartialFn `elem` opts)) $
543− totalityError t = do i <- getIState
544− let msg = show n ++ " is " ++ show t
545− putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i}
546− addIBC (IBCTotCheckErr fc msg)
550− case lookupDef n (tt_ctxt i) of
552− iWarn fc . pprintErr i . Msg $ "Warning - " ++ show n ++ " is " ++ show t
554−-- let cg = lookupCtxtName Nothing n (idris_callgraph i)
555−-- iputStrLn (show cg)
558−checkDeclTotality :: (FC, Name) -> Idris Totality
559−checkDeclTotality (fc, n)
560− = do logCoverage 2 $ "Checking " ++ show n ++ " for totality"
562− let opts = case lookupCtxtExact n (idris_flags i) of
565− when (CoveringFn `elem` opts) $ checkAllCovering fc [] n n
566− t <- checkTotality [] fc n
569−-- If the name calls something which is partial, set it as partial
570−verifyTotality :: (FC, Name) -> Idris ()
571−verifyTotality (fc, n)
572− = do logCoverage 2 $ "Checking " ++ show n ++ "'s descendents are total"
574− case lookupTotalExact n (tt_ctxt ist) of
575− Just (Total _) -> do
576− let ns = getNames (tt_ctxt ist)
578− case getPartial ist [] ns of
579− Nothing -> return ()
580− Just bad -> do let t' = Partial (Other bad)
581− logCoverage 2 $ "Set to " ++ show t'
583− addIBC (IBCTotal n t')
586− getNames ctxt = case lookupDefExact n ctxt of
587− Just (CaseOp _ _ _ _ _ defs)
588− -> let (top, def) = cases_compiletime defs in
589− map fst (findCalls' True def top)
592− getPartial ist [] [] = Nothing
593− getPartial ist bad [] = Just bad
594− getPartial ist bad (n : ns)
595− = case lookupTotalExact n (tt_ctxt ist) of
596− Just (Partial _) -> getPartial ist (n : bad) ns
597− _ -> getPartial ist bad ns
599−-- | Calculate the size change graph for this definition
601−-- SCG for a function f consists of a list of:
602−-- (g, [(a1, sizechange1), (a2, sizechange2), ..., (an, sizechangen)])
604−-- where g is a function called
605−-- a1 ... an are the arguments of f in positions 1..n of g
606−-- sizechange1 ... sizechange2 is how their size has changed wrt the input
608−-- Nothing, if the argument is unrelated to the input
609−buildSCG :: (FC, Name) -> Idris ()
612− case lookupCtxt n (idris_callgraph ist) of
613− [cg] -> case lookupDefExact n (tt_ctxt ist) of
614− Just (CaseOp _ _ _ pats _ cd) ->
615− let (args, sc) = cases_compiletime cd in
616− do logCoverage 2 $ "Building SCG for " ++ show n ++ " from\n"
617− ++ show pats ++ "\n" ++ show sc
618− let newscg = buildSCG' ist n (rights pats) args
619− logCoverage 5 $ "SCG is: " ++ show newscg
620− addToCG n ( cg { scg = newscg } )
621− _ -> return () -- CG comes from a type declaration only
622− [] -> logCoverage 5 $ "Could not build SCG for " ++ show n ++ "\n"
623− x -> error $ "buildSCG: " ++ show (n, x)
625−delazy = delazy' False -- not lazy codata
626−delazy' all t@(App _ f a)
627− | (P _ (UN l) _, [_, _, arg]) <- unApply t,
628− l == txt "Force" = delazy' all arg
629− | (P _ (UN l) _, [P _ (UN lty) _, _, arg]) <- unApply t,
630− l == txt "Delay" && (all || lty /= txt "Infinite") = delazy arg
631− | (P _ (UN l) _, [P _ (UN lty) _, arg]) <- unApply t,
632− l == txt "Delayed" && (all || lty /= txt "Infinite") = delazy' all arg
633−delazy' all (App s f a) = App s (delazy' all f) (delazy' all a)
634−delazy' all (Bind n b sc) = Bind n (fmap (delazy' all) b) (delazy' all sc)
637−data Guardedness = Toplevel | Unguarded | Guarded | Delayed
640−buildSCG' :: IState -> Name -> [(Term, Term)] -> [Name] -> [SCGEntry]
641−buildSCG' ist topfn pats args = nub $ concatMap scgPat pats where
642− scgPat (lhs, rhs) = let lhs' = delazy lhs
644− (f, pargs) = unApply (dePat lhs') in
645− findCalls [] Toplevel (dePat rhs') (patvars lhs')
648− -- Under a delay, calls are excluded from the graph - if it's a call to a
649− -- non-total function we'll find that in the final totality check
650− findCalls cases Delayed ap@(P _ n _) pvs args = []
651− findCalls cases guarded ap@(App _ f a) pvs pargs
652− -- under a call to "assert_total", don't do any checking, just believe
653− -- that it is total.
654− | (P _ (UN at) _, [_, _]) <- unApply ap,
655− at == txt "assert_total" = []
656− -- don't go under calls to functions which are asserted total
657− | (P _ n _, _) <- unApply ap,
658− Just opts <- lookupCtxtExact n (idris_flags ist),
659− AssertTotal `elem` opts = []
660− -- under a guarded call to "Delay Infinite", we are 'Delayed', so don't
661− -- check under guarded constructors.
662− | (P _ (UN del) _, [_,_,arg]) <- unApply ap,
665− = findCalls cases Delayed arg pvs pargs
666− | (P _ n _, args) <- unApply ap,
668− isConName n (tt_ctxt ist) || allGuarded n ist
669− = -- Still under a 'Delay' and constructor guarded, so check
670− -- just the arguments to the constructor, remaining Delayed
671− concatMap (\x -> findCalls cases guarded x pvs pargs) args
672− | (P _ ifthenelse _, [_, _, t, e]) <- unApply ap,
673− ifthenelse == sNS (sUN "ifThenElse") ["Bool", "Prelude"]
674− -- Continue look inside if...then...else blocks
675− -- TODO: Consider whether we should do this for user defined ifThenElse
676− -- rather than just the one in the Prelude as a special case
677− = findCalls cases guarded t pvs pargs ++
678− findCalls cases guarded e pvs pargs
679− | (P _ n _, args) <- unApply ap,
680− caseName n && n /= topfn,
681− notPartial (lookupTotalExact n (tt_ctxt ist))
682− -- case block - look inside the block, as long as it was covering
683− -- (i.e. not currently set at Partial) to get a more accurate size
684− -- change result from the top level patterns (also to help pass
685− -- information through from guarded corecursion accurately)
686− = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args ++
687− if n `notElem` cases
688− then findCallsCase (n : cases) guarded n args pvs pargs
690− | (P _ n _, args) <- unApply ap,
692− -- Under a delayed recursive call just check the arguments
693− = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args
694− | (P _ n _, args) <- unApply ap
695− -- Ordinary call, not under a delay.
696− -- If n is a constructor, set 'args' as Guarded
697− = let nguarded = case guarded of
698− Unguarded -> Unguarded
699− x -> if isConName n (tt_ctxt ist)
703− mkChange n args pargs ++
704− concatMap (\x -> findCalls cases nguarded x pvs pargs) args
705− where notPartial (Just (Partial NotCovering)) = False
707− findCalls cases guarded (App _ f a) pvs pargs
708− = findCalls cases Unguarded f pvs pargs ++ findCalls cases Unguarded a pvs pargs
709− findCalls cases guarded (Bind n (Let t v) e) pvs pargs
710− = findCalls cases Unguarded t pvs pargs ++
711− findCalls cases Unguarded v pvs pargs ++
712− -- Substitute in the scope since this might reveal some useful
714− findCalls cases guarded (substV v e) pvs pargs
715− findCalls cases guarded (Bind n t e) pvs pargs
716− = findCalls cases Unguarded (binderTy t) pvs pargs ++
717− findCalls cases guarded e (n : pvs) pargs
718− findCalls cases guarded (P _ f _ ) pvs pargs
719− | not (f `elem` pvs) = [(f, [])]
720− findCalls _ _ _ _ _ = []
722− -- Assumption is that names are preserved in the case block (shadowing
723− -- dealt with by the elaborator) so we can just assume the top level names
724− -- are okay for building the size change
725− findCallsCase cases guarded n args pvs pargs
726− = case lookupDefExact n (tt_ctxt ist) of
727− Just (CaseOp _ _ _ pats _ cd) ->
728− concatMap (fccPat cases pvs pargs args guarded) (rights pats)
731− fccPat cases pvs pargs args g (lhs, rhs)
732− = let lhs' = delazy lhs
734− (f, pargs_case) = unApply (dePat lhs')
735− -- pargs is a pair of a term, and the argument position that
736− -- term appears in. If any of the arguments to the case block
737− -- are also on the lhs, we also want those patterns to appear
738− -- in the parg list so that we'll spot patterns which are
739− -- smaller than then
740− newpargs = newPArg args pargs
741− -- Now need to update the rhs of the case with the names in the
742− -- outer definition: In rhs', wherever we see what's in pargs_case,
743− -- replace it with the corresponding thing in pargs
744− csubs = zip pargs_case args
745− newrhs = doCaseSubs csubs (dePat rhs')
746− pargs' = pargs ++ addPArg newpargs pargs_case in
747− findCalls cases g newrhs pvs pargs'
749− doCaseSubs [] tm = tm
750− doCaseSubs ((x, x') : cs) tm
751− = doCaseSubs (subIn x x' cs) (substTerm x x' tm)
754− subIn x x' ((l, r) : cs)
755− = (substTerm x x' l, substTerm x x' r) : subIn x x' cs
757− addPArg (Just (t, i) : ts) (t' : ts') = (t', i) : addPArg ts ts'
758− addPArg (Nothing : ts) (t' : ts') = addPArg ts ts'
761− newPArg :: [Term] -> [(Term, Int)] -> [Maybe (Term, Int)]
762− newPArg (t : ts) pargs = case lookup t pargs of
763− Just i -> Just (t, i) : newPArg ts pargs
764− Nothing -> Nothing : newPArg ts pargs
765− newPArg [] pargs = []
767− expandToArity n args
768− = case lookupTy n (tt_ctxt ist) of
769− [ty] -> expand 0 (normalise (tt_ctxt ist) [] ty) args
771− where expand i (Bind n (Pi _ _ _) sc) (x : xs) = x : expand (i + 1) sc xs
772− expand i (Bind n (Pi _ _ _) sc) [] = Just (i, Same) : expand (i + 1) sc []
775− mkChange n args pargs = [(n, expandToArity n (sizes args))]
778− sizes (a : as) = checkSize a pargs : sizes as
780− -- find which argument in pargs <a> is smaller than, if any
781− checkSize a ((p, i) : ps)
782− | a == p = Just (i, Same)
783− | (P _ (UN as) _, [_,_,arg,_]) <- unApply a,
784− as == txt "assert_smaller" && arg == p
786− | smaller Nothing a (p, Nothing) = Just (i, Smaller)
787− | otherwise = checkSize a ps
788− checkSize a [] = Nothing
790− -- the smaller thing we find must be defined in the same group of mutally
791− -- defined types as <a>, and not be coinductive - so carry the type of
792− -- the constructor we've gone under.
794− smaller (Just tyn) a (t, Just tyt)
795− | a == t = isInductive (fst (unApply (getRetTy tyn)))
796− (fst (unApply (getRetTy tyt)))
797− smaller ty a (ap@(App _ f s), _)
798− | (P (DCon _ _ _) n _, args) <- unApply ap
799− = let tyn = getType n in
800− any (smaller (ty `mplus` Just tyn) a)
801− (zip args (map toJust (getArgTys tyn)))
802− -- check higher order recursive arguments
803− smaller ty (App _ f s) a = smaller ty f a
804− smaller _ _ _ = False
806− toJust (n, t) = Just t
808− getType n = case lookupTyExact n (tt_ctxt ist) of
809− Just ty -> delazy (normalise (tt_ctxt ist) [] ty) -- must exist
811− isInductive (P _ nty _) (P _ nty' _) =
812− let (co, muts) = case lookupCtxt nty (idris_datatypes ist) of
813− [TI _ x _ _ muts] -> (x, muts)
815− (nty == nty' || any (== nty') muts) && not co
816− isInductive _ _ = False
818− dePat (Bind x (PVar ty) sc) = dePat (instantiate (P Bound x ty) sc)
821− patvars (Bind x (PVar _) sc) = x : patvars sc
824− allGuarded n ist = case lookupCtxtExact n (idris_flags ist) of
826− Just fs -> AllGuarded `elem` fs
828−checkSizeChange :: Name -> Idris Totality
829−checkSizeChange n = do
831− case lookupCtxt n (idris_callgraph ist) of
832− [cg] -> do let ms = mkMultiPaths ist [] (scg cg)
833− logCoverage 5 ("Multipath for " ++ show n ++ ":\n" ++
834− "from " ++ show (scg cg) ++ "\n" ++
835− show (length ms) ++ "\n" ++
836− showSep "\n" (map show ms))
837− logCoverage 6 (show cg)
838− -- every multipath must have an infinitely descending
839− -- thread, then the function terminates
840− -- also need to checks functions called are all total
841− -- (Unchecked is okay as we'll spot problems here)
842− let tot = map (checkMP ist n (getArity ist n)) ms
843− logCoverage 4 $ "Generated " ++ show (length tot) ++ " paths"
844− logCoverage 5 $ "Paths for " ++ show n ++ " yield " ++
845− (showSep "\n" (map show (zip ms tot)))
846− return (noPartial tot)
847− [] -> do logCoverage 5 $ "No paths for " ++ show n
849− where getArity ist n
850− = case lookupTy n (tt_ctxt ist) of
851− [ty] -> arity (normalise (tt_ctxt ist) [] ty)
852− _ -> error "Can't happen: checkSizeChange.getArity"
854−type MultiPath = [SCGEntry]
856−mkMultiPaths :: IState -> MultiPath -> [SCGEntry] -> [MultiPath]
857−mkMultiPaths ist path [] = [reverse path]
858−mkMultiPaths ist path cg = concatMap extend cg
859− where extend (nextf, args)
860− | (nextf, args) `inPath` path = [ reverse ((nextf, args) : path) ]
861− | [Unchecked] <- lookupTotal nextf (tt_ctxt ist)
862− = case lookupCtxt nextf (idris_callgraph ist) of
863− [ncg] -> mkMultiPaths ist ((nextf, args) : path) (scg ncg)
864− _ -> [ reverse ((nextf, args) : path) ]
865− | otherwise = [ reverse ((nextf, args) : path) ]
867− inPath :: SCGEntry -> [SCGEntry] -> Bool
869− inPath f (g : gs) = smallerEq f g || f == g || inPath f gs
871− smallerEq :: SCGEntry -> SCGEntry -> Bool
872− smallerEq (f, args) (g, args')
873− = f == g && not (null (filter smallers args))
874− && filter smallers args == filter smallers args'
875− smallers (Just (_, Smaller)) = True
878−-- If any route along the multipath leads to infinite descent, we're fine.
879−-- Try a route beginning with every argument.
880−-- If we reach a point we've been to before, but with a smaller value,
881−-- that means there is an infinitely descending path from that argument.
883−checkMP :: IState -> Name -> Int -> MultiPath -> Totality
884−checkMP ist topfn i mp = if i > 0
885− then let paths = (map (tryPath 0 [] mp) [0..i-1]) in
886−-- trace ("Paths " ++ show paths) $
888− else tryPath 0 [] mp 0
890− tryPath' d path mp arg
891− = let res = tryPath d path mp arg in
892− trace (show mp ++ "\n" ++ show arg ++ " " ++ show res) res
894− mkBig (e, d) = (e, 10000)
896− tryPath :: Int -> [((SCGEntry, Int), Int)] -> MultiPath -> Int -> Totality
897− tryPath desc path [] _ = Total []
898−-- tryPath desc path ((UN "believe_me", _) : _) arg
899−-- = Partial BelieveMe
900− -- if we get to a constructor, it's fine as long as it's strictly positive
901− tryPath desc path ((f, _) : es) arg
902− | [TyDecl (DCon _ _ _) _] <- lookupDef f (tt_ctxt ist)
903− = case lookupTotalExact f (tt_ctxt ist) of
904− Just (Total _) -> Unchecked -- okay so far
905− Just (Partial _) -> Partial (Other [f])
906− x -> Unchecked -- An error elsewhere, set as Unchecked to make
908− | [TyDecl (TCon _ _) _] <- lookupDef f (tt_ctxt ist)
910− tryPath desc path (e@(f, args) : es) arg
911− | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
912− | e `elem` es && allNothing args = Partial (Mutual [f])
913− tryPath desc path (e@(f, nextargs) : es) arg
914− | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
915− | [Partial _] <- lookupTotal f (tt_ctxt ist) = Partial (Other [f])
916− | Just d <- lookup (e, arg) path
917− = if desc - d > 0 -- Now lower than when we were last here
918− then -- trace ("Descent " ++ show (desc - d) ++ " "
919− -- ++ show (path, e)) $
921− else Partial (Mutual (map (fst . fst . fst) path ++ [f]))
922− | e `elem` map (fst . fst) path
923− && not (f `elem` map fst es)
924− = Partial (Mutual (map (fst . fst . fst) path ++ [f]))
925− | [Unchecked] <- lookupTotal f (tt_ctxt ist) =
926− let argspos = zip nextargs [0..]
928− do (a, pos) <- argspos
930− Nothing -> -- gone up, but if the
931− -- rest definitely terminates without any
932− -- cycles (including the path so far, which
933− -- we take as inaccessible) the path is fine
934− return $ tryPath 0 (map mkBig (((e, arg), desc) : path)) es pos
935− Just (nextarg, sc) ->
936− if nextarg == arg then
938− Same -> return $ tryPath desc (((e, arg), desc) : path)
940− Smaller -> return $ tryPath (desc+1)
941− (((e, arg), desc) : path)
944− _ -> trace ("Shouldn't happen " ++ show e) $
945− return (Partial Itself)
946− else return Unchecked in
947−-- trace (show (desc, argspos, path, es, pathres)) $
950− | otherwise = Unchecked
952−allNothing :: [Maybe a] -> Bool
953−allNothing xs = null (collapseNothing (zip xs [0..]))
955−collapseNothing :: [(Maybe a, b)] -> [(Maybe a, b)]
956−collapseNothing ((Nothing, t) : xs)
957− = (Nothing, t) : filter (\ (x, _) -> case x of
960−collapseNothing (x : xs) = x : collapseNothing xs
961−collapseNothing [] = []
963−noPartial :: [Totality] -> Totality
964−noPartial (Partial p : xs) = Partial p
965−noPartial (_ : xs) = noPartial xs
966−noPartial [] = Total []
968−collapse :: [Totality] -> Totality
969−collapse xs = collapse' Unchecked xs
970−collapse' def (Total r : xs) = Total r
971−collapse' def (Unchecked : xs) = collapse' def xs
972−collapse' def (d : xs) = collapse' d xs
973−-- collapse' Unchecked [] = Total []
974−collapse' def [] = def
976−totalityCheckBlock :: Idris ()
977−totalityCheckBlock = do
979− -- Do totality checking after entire mutual block
980− mapM_ (\n -> do logElab 5 $ "Simplifying " ++ show n
981− ctxt' <- do ctxt <- getContext
982− tclift $ simplifyCasedef n (getErasureInfo ist) ctxt
984− (map snd (idris_totcheck ist))
985− mapM_ buildSCG (idris_totcheck ist)
986− mapM_ checkDeclTotality (idris_totcheck ist)