{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Language.Fixpoint.Types.Errors (
SrcSpan (..)
, dummySpan
, sourcePosElts
, FixResult (..)
, colorResult
, resultDoc
, resultExit
, Error, Error1
, err
, errLoc
, errMsg
, errs
, catError
, catErrors
, panic
, die
, dieAt
, exit
, errFreeVarInQual
, errFreeVarInConstraint
, errIllScopedKVar
) where
import System.Exit (ExitCode (..))
import Control.Exception
import Data.Serialize (Serialize (..))
import Data.Generics (Data)
import Data.Typeable
#if !MIN_VERSION_base(4,14,0)
import Data.Semigroup (Semigroup (..))
#endif
import Control.DeepSeq
import qualified Data.Binary as B
import GHC.Generics (Generic)
import Language.Fixpoint.Types.PrettyPrint
import Language.Fixpoint.Types.Spans
import Language.Fixpoint.Misc
import qualified Language.Fixpoint.Solver.Stats as Solver
import Text.PrettyPrint.HughesPJ.Compat
import Data.Function (on)
import qualified Text.PrettyPrint.Annotated.HughesPJ as Ann
deriving instance Generic (Ann.AnnotDetails a)
instance Serialize a => Serialize (Ann.AnnotDetails a)
instance Serialize a => Serialize (Ann.Doc a)
instance Serialize Error1
instance Serialize TextDetails
instance Serialize Doc
instance Serialize Error
instance Serialize (FixResult Error)
instance (B.Binary a) => B.Binary (FixResult a)
newtype Error = Error [Error1]
deriving (Eq, Ord, Show, Typeable, Generic)
errs :: Error -> [Error1]
errs (Error es) = es
data Error1 = Error1
{ errLoc :: SrcSpan
, errMsg :: Doc
} deriving (Eq, Show, Typeable, Generic)
instance Ord Error1 where
compare = compare `on` errLoc
instance PPrint Error1 where
pprintTidy k (Error1 l msg) = (pprintTidy k l <-> ": Error")
$+$ nest 2 msg
instance PPrint Error where
pprintTidy k (Error es) = vcat $ pprintTidy k <$> es
instance Fixpoint Error1 where
toFix = pprint
instance Exception Error
instance Exception (FixResult Error)
catError :: Error -> Error -> Error
catError (Error e1) (Error e2) = Error (e1 ++ e2)
catErrors :: ListNE Error -> Error
catErrors = foldr1 catError
err :: SrcSpan -> Doc -> Error
err sp d = Error [Error1 sp d]
panic :: String -> a
panic = die . err dummySpan . text . (panicMsg ++)
panicMsg :: String
panicMsg = "PANIC: Please file an issue at https://github.com/ucsd-progsys/liquid-fixpoint \n"
die :: Error -> a
die = throw
dieAt :: SrcSpan -> Error -> a
dieAt sp (Error es) = die (Error [ e {errLoc = sp} | e <- es])
exit :: a -> IO a -> IO a
exit def act = catch act $ \(e :: Error) -> do
putDocLn $ vcat ["Unexpected Errors!", pprint e]
return def
putDocLn :: Doc -> IO ()
putDocLn = putStrLn . render
data FixResult a = Crash [a] String
| Safe Solver.Stats
| Unsafe Solver.Stats ![a]
deriving (Data, Typeable, Foldable, Traversable, Show, Generic)
instance (NFData a) => NFData (FixResult a)
instance Eq a => Eq (FixResult a) where
Crash xs _ == Crash ys _ = xs == ys
Unsafe s1 xs == Unsafe s2 ys = xs == ys && s1 == s2
Safe s1 == Safe s2 = s1 == s2
_ == _ = False
instance Semigroup (FixResult a) where
Safe s1 <> Safe s2 = Safe (s1 <> s2)
Safe _ <> x = x
x <> Safe _ = x
_ <> c@(Crash{}) = c
c@(Crash{}) <> _ = c
(Unsafe s1 xs) <> (Unsafe s2 ys) = Unsafe (s1 <> s2) (xs ++ ys)
instance Monoid (FixResult a) where
mempty = Safe mempty
mappend = (<>)
instance Functor FixResult where
fmap f (Crash xs msg) = Crash (f <$> xs) msg
fmap f (Unsafe s xs) = Unsafe s (f <$> xs)
fmap _ (Safe stats) = Safe stats
resultDoc :: (Fixpoint a) => FixResult a -> Doc
resultDoc (Safe stats) = text "Safe (" <+> text (show $ Solver.checked stats) <+> " constraints checked)"
resultDoc (Crash xs msg) = vcat $ text ("Crash!: " ++ msg) : ((("CRASH:" <+>) . toFix) <$> xs)
resultDoc (Unsafe _ xs) = vcat $ text "Unsafe:" : ((("WARNING:" <+>) . toFix) <$> xs)
colorResult :: FixResult a -> Moods
colorResult (Safe (Solver.totalWork -> 0)) = Wary
colorResult (Safe _) = Happy
colorResult (Unsafe _ _) = Angry
colorResult (_) = Sad
resultExit :: FixResult a -> ExitCode
resultExit (Safe _stats) = ExitSuccess
resultExit _ = ExitFailure 1
errFreeVarInQual :: (PPrint q, Loc q, PPrint x) => q -> x -> Error
errFreeVarInQual q x = err sp $ vcat [ "Qualifier with free vars"
, pprint q
, pprint x ]
where
sp = srcSpan q
errFreeVarInConstraint :: (PPrint a) => (Integer, a) -> Error
errFreeVarInConstraint (i, ss) = err dummySpan $
vcat [ "Constraint with free vars"
, pprint i
, pprint ss
, "Try using the --prune-unsorted flag"
]
errIllScopedKVar :: (PPrint k, PPrint bs) => (k, Integer, Integer, bs) -> Error
errIllScopedKVar (k, inId, outId, xs) = err dummySpan $
vcat [ "Ill-scoped KVar" <+> pprint k
, "Missing common binders at def" <+> pprint inId <+> "and use" <+> pprint outId
, pprint xs
]