module Language.Fixpoint.Types.Solutions (
Solution, GSolution
, Sol (gMap, sEnv), updateGMap, updateGMapWithKey
, sScp
, CMap
, Hyp, Cube (..), QBind, GBind
, EQual (..)
, eQual
, trueEqual
, qbToGb, gbToQbs, gbEquals, equalsGb, emptyGMap, qbExprs
, Cand
, fromList
, update
, lookupQBind
, lookup, glookup
, qb
, qbPreds
, qbFilter
, gbFilterM
, result, resultGradual
, Index (..)
, KIndex (..)
, BindPred (..)
, BIndex (..)
) where
import Prelude hiding (lookup)
import GHC.Generics
import Control.DeepSeq
import Data.Maybe (fromMaybe)
import Data.Hashable
import qualified Data.HashMap.Strict as M
import qualified Data.List as L
import Data.Generics (Data)
import Data.Typeable (Typeable)
import Control.Monad (filterM)
import Language.Fixpoint.Misc
import Language.Fixpoint.Types.PrettyPrint
import Language.Fixpoint.Types.Names
import Language.Fixpoint.Types.Sorts
import Language.Fixpoint.Types.Theories
import Language.Fixpoint.Types.Refinements
import Language.Fixpoint.Types.Environments
import Language.Fixpoint.Types.Constraints
import Language.Fixpoint.Types.Substitutions
import Language.Fixpoint.SortCheck (elaborate)
import Text.PrettyPrint.HughesPJ
update :: Sol a QBind -> [KVar] -> [(KVar, EQual)] -> (Bool, Sol a QBind)
update s ks kqs = (or bs, s')
where
kqss = groupKs ks kqs
(bs, s') = folds update1 s kqss
folds :: (a -> b -> (c, a)) -> a -> [b] -> ([c], a)
folds f b = L.foldl' step ([], b)
where
step (cs, acc) x = (c:cs, x')
where
(c, x') = f acc x
groupKs :: [KVar] -> [(KVar, EQual)] -> [(KVar, QBind)]
groupKs ks kqs = [ (k, QB eqs) | (k, eqs) <- M.toList $ groupBase m0 kqs ]
where
m0 = M.fromList $ (,[]) <$> ks
update1 :: Sol a QBind -> (KVar, QBind) -> (Bool, Sol a QBind)
update1 s (k, qs) = (change, updateK k qs s)
where
oldQs = lookupQBind s k
change = qbSize oldQs /= qbSize qs
type Solution = Sol () QBind
type GSolution = Sol (((Symbol, Sort), Expr), GBind) QBind
newtype QBind = QB [EQual] deriving (Show, Data, Typeable, Generic, Eq)
newtype GBind = GB [[EQual]] deriving (Show, Data, Typeable, Generic)
emptyGMap :: GSolution -> GSolution
emptyGMap sol = mapGMap sol (\(x,_) -> (x, GB []))
updateGMapWithKey :: [(KVar, QBind)] -> GSolution -> GSolution
updateGMapWithKey kqs sol = sol {gMap = foldl (\m (k, (QB eq)) -> M.adjust (\(x, GB eqs) -> (x, GB (if eq `elem` eqs then eqs else eq:eqs))) k m) (gMap sol) kqs }
qb :: [EQual] -> QBind
qb = QB
qbEQuals :: QBind -> [EQual]
qbEQuals (QB xs) = xs
qbExprs :: QBind -> [Expr]
qbExprs (QB xs) = eqPred <$> xs
qbToGb :: QBind -> GBind
qbToGb (QB xs) = GB $ map (:[]) xs
gbToQbs :: GBind -> [QBind]
gbToQbs (GB []) = [QB [trueEqual]]
gbToQbs (GB ess) = QB <$> ess
gbEquals :: GBind -> [[EQual]]
gbEquals (GB eqs) = eqs
equalsGb :: [[EQual]] -> GBind
equalsGb = GB
gbFilterM :: Monad m => ([EQual] -> m Bool) -> GBind -> m GBind
gbFilterM f (GB eqs) = GB <$> filterM f eqs
qbSize :: QBind -> Int
qbSize = length . qbEQuals
qbFilter :: (EQual -> Bool) -> QBind -> QBind
qbFilter f (QB eqs) = QB (filter f eqs)
instance NFData QBind
instance NFData GBind
instance PPrint QBind where
pprintTidy k = pprintTidy k . qbEQuals
data Sol b a = Sol
{ sEnv :: !SymEnv
, sMap :: !(M.HashMap KVar a)
, gMap :: !(M.HashMap KVar b)
, sHyp :: !(M.HashMap KVar Hyp)
, sScp :: !(M.HashMap KVar IBindEnv)
}
updateGMap :: Sol b a -> M.HashMap KVar b -> Sol b a
updateGMap sol gmap = sol {gMap = gmap}
mapGMap :: Sol b a -> (b -> b) -> Sol b a
mapGMap sol f = sol {gMap = M.map f (gMap sol)}
instance Monoid (Sol a b) where
mempty = Sol mempty mempty mempty mempty mempty
mappend s1 s2 = Sol { sEnv = mappend (sEnv s1) (sEnv s2)
, sMap = mappend (sMap s1) (sMap s2)
, gMap = mappend (gMap s1) (gMap s2)
, sHyp = mappend (sHyp s1) (sHyp s2)
, sScp = mappend (sScp s1) (sScp s2)
}
instance Functor (Sol a) where
fmap f (Sol e s m1 m2 m3) = Sol e (f <$> s) m1 m2 m3
instance (PPrint a, PPrint b) => PPrint (Sol a b) where
pprintTidy k = pprintTidy k . sMap
type Hyp = ListNE Cube
data Cube = Cube
{ cuBinds :: IBindEnv
, cuSubst :: Subst
, cuId :: SubcId
, cuTag :: Tag
}
instance PPrint Cube where
pprintTidy _ c = "Cube" <+> pprint (cuId c)
instance Show Cube where
show = showpp
result :: Sol a QBind -> M.HashMap KVar Expr
result s = sMap $ (pAnd . fmap eqPred . qbEQuals) <$> s
resultGradual :: GSolution -> M.HashMap KVar (Expr, [Expr])
resultGradual s = fmap go' (gMap s)
where
go' ((_,e), GB eqss)
= (e, [PAnd $ fmap eqPred eqs | eqs <- eqss])
fromList :: SymEnv -> [(KVar, a)] -> [(KVar, b)] -> [(KVar, Hyp)] -> M.HashMap KVar IBindEnv -> Sol a b
fromList env kGs kXs kYs = Sol env kXm kGm kYm
where
kXm = M.fromList kXs
kYm = M.fromList kYs
kGm = M.fromList kGs
qbPreds :: String -> Sol a QBind -> Subst -> QBind -> [(Pred, EQual)]
qbPreds msg s su (QB eqs) = [ (elabPred eq, eq) | eq <- eqs ]
where
elabPred = elaborate ("qbPreds:" ++ msg) env . subst su . eqPred
env = sEnv s
lookupQBind :: Sol a QBind -> KVar -> QBind
lookupQBind s k = fromMaybe (QB []) (lookupElab s k)
where
_msg = "lookupQB: k = " ++ show k
glookup :: GSolution -> KVar -> Either Hyp (Either QBind (((Symbol, Sort), Expr), GBind))
glookup s k
| Just gbs <- M.lookup k (gMap s)
= Right (Right gbs)
| Just cs <- M.lookup k (sHyp s)
= Left cs
| Just eqs <- lookupElab s k
= Right (Left eqs)
| otherwise
= errorstar $ "solLookup: Unknown kvar " ++ show k
lookup :: Sol a QBind -> KVar -> Either Hyp QBind
lookup s k
| Just cs <- M.lookup k (sHyp s)
= Left cs
| Just eqs <- lookupElab s k
= Right eqs
| otherwise
= errorstar $ "solLookup: Unknown kvar " ++ show k
lookupElab :: Sol b QBind -> KVar -> Maybe QBind
lookupElab s k = M.lookup k (sMap s)
updateK :: KVar -> a -> Sol b a -> Sol b a
updateK k qs s = s { sMap = M.insert k qs (sMap s)
}
type Cand a = [(Expr, a)]
data EQual = EQL
{ _eqQual :: !Qualifier
, eqPred :: !Expr
, _eqArgs :: ![Expr]
} deriving (Eq, Show, Data, Typeable, Generic)
trueEqual :: EQual
trueEqual = EQL trueQual mempty []
instance PPrint EQual where
pprintTidy k = pprintTidy k . eqPred
instance NFData EQual
eQual :: Qualifier -> [Symbol] -> EQual
eQual q xs = EQL q p es
where
p = subst su $ qBody q
su = mkSubst $ safeZip "eQual" qxs es
es = eVar <$> xs
qxs = fst <$> qParams q
data KIndex = KIndex { kiBIndex :: !BindId
, kiPos :: !Int
, kiKVar :: !KVar
}
deriving (Eq, Ord, Show, Generic)
instance Hashable KIndex
instance PPrint KIndex where
pprintTidy _ = tshow
data BIndex = Root
| Bind !BindId
| Cstr !SubcId
deriving (Eq, Ord, Show, Generic)
instance Hashable BIndex
instance PPrint BIndex where
pprintTidy _ = tshow
data BindPred = BP
{ bpConc :: !Pred
, bpKVar :: ![KIndex]
} deriving (Show)
instance PPrint BindPred where
pprintTidy _ = tshow
data Index = FastIdx
{ bindExpr :: !(BindId |-> BindPred)
, kvUse :: !(KIndex |-> KVSub)
, kvDef :: !(KVar |-> Hyp)
, envBinds :: !(CMap IBindEnv)
, envTx :: !(CMap [SubcId])
, envSorts :: !(SEnv Sort)
}
type CMap a = M.HashMap SubcId a