module Distribution.Solver.Modular.Log ( Log , logToProgress , SolverFailure(..) ) where import Prelude () import Distribution.Solver.Compat.Prelude import Distribution.Solver.Types.Progress import Distribution.Solver.Modular.Dependency import Distribution.Solver.Modular.Message import Distribution.Solver.Modular.Tree (FailReason(..)) import qualified Distribution.Solver.Modular.ConflictSet as CS import Distribution.Verbosity -- | The 'Log' datatype. -- -- Represents the progress of a computation lazily. -- -- Parameterized over the type of actual messages and the final result. type Log m a = Progress m (ConflictSet, ConflictMap) a data Exhaustiveness = Exhaustive | BackjumpLimit -- | Information about a dependency solver failure. It includes an error message -- and a final conflict set, if available. data SolverFailure = NoSolution ConflictSet String | BackjumpLimitReached String -- | Postprocesses a log file. Takes as an argument a limit on allowed backjumps. -- If the limit is 'Nothing', then infinitely many backjumps are allowed. If the -- limit is 'Just 0', backtracking is completely disabled. logToProgress :: Verbosity -> Maybe Int -> Log Message a -> Progress String SolverFailure a logToProgress verbosity mbj l = let ms = proc mbj l mapFailure f = foldProgress Step (Fail . f) Done in mapFailure finalError (showMessages ms) -- run with backjump limit applied where -- Proc takes the allowed number of backjumps and a 'Progress' and explores the -- messages until the maximum number of backjumps has been reached. It filters out -- and ignores repeated backjumps. If proc reaches the backjump limit, it truncates -- the 'Progress' and ends it with the last conflict set. Otherwise, it leaves the -- original result. proc :: Maybe Int -> Log Message b -> Progress Message (Exhaustiveness, ConflictSet, ConflictMap) b proc _ (Done x) = Done x proc _ (Fail (cs, cm)) = Fail (Exhaustive, cs, cm) proc mbj' (Step x@(Failure cs Backjump) xs@(Step Leave (Step (Failure cs' Backjump) _))) | cs == cs' = Step x (proc mbj' xs) -- repeated backjumps count as one proc (Just 0) (Step (Failure cs Backjump) _) = Fail (BackjumpLimit, cs, mempty) -- No final conflict map available proc (Just n) (Step x@(Failure _ Backjump) xs) = Step x (proc (Just (n - 1)) xs) proc mbj' (Step x xs) = Step x (proc mbj' xs) finalError :: (Exhaustiveness, ConflictSet, ConflictMap) -> SolverFailure finalError (exh, cs, cm) = case exh of Exhaustive -> NoSolution cs $ "After searching the rest of the dependency tree exhaustively, " ++ "these were the goals I've had most trouble fulfilling: " ++ showCS cm cs where showCS = if verbosity > normal then CS.showCSWithFrequency else CS.showCSSortedByFrequency BackjumpLimit -> BackjumpLimitReached $ "Backjump limit reached (" ++ currlimit mbj ++ "change with --max-backjumps or try to run with --reorder-goals).\n" where currlimit (Just n) = "currently " ++ show n ++ ", " currlimit Nothing = ""