-- | Validate and Transform Constraints to Ensure various Invariants ------------------------- -- 1. Each binder must be unique module Language.Fixpoint.Solver.Validate ( -- * Validate and Transform FInfo to enforce invariants validate -- * Sorts for each Symbol , symbolSorts ) where import Language.Fixpoint.Config import Language.Fixpoint.PrettyPrint import qualified Language.Fixpoint.Misc as Misc import qualified Language.Fixpoint.Types as F import qualified Language.Fixpoint.Errors as E import qualified Data.HashMap.Strict as M import qualified Data.List as L -- import Control.Monad (filterM) -- import Control.Applicative ((<$>)) -- import Debug.Trace (trace) import Text.Printf --------------------------------------------------------------------------- validate :: Config -> F.FInfo a -> Either E.Error (F.FInfo a) --------------------------------------------------------------------------- validate _ = Right . renameVV --------------------------------------------------------------------------- -- | symbol |-> sort for EVERY variable in the FInfo --------------------------------------------------------------------------- symbolSorts :: F.FInfo a -> Either E.Error [(F.Symbol, F.Sort)] --------------------------------------------------------------------------- symbolSorts fi = compact . (\z -> lits ++ consts ++ z) =<< bindSorts fi where lits = F.lits fi consts = [(x, t) | (x, F.RR t _) <- F.toListSEnv $ F.gs fi] compact :: [(F.Symbol, F.Sort)] -> Either E.Error [(F.Symbol, F.Sort)] compact xts | null bad = Right [(x, t) | (x, [t]) <- ok ] | otherwise = Left $ dupBindErrors bad where (bad, ok) = L.partition multiSorted . binds $ xts binds = M.toList . M.map Misc.sortNub . Misc.group --------------------------------------------------------------------------- bindSorts :: F.FInfo a -> Either E.Error [(F.Symbol, F.Sort)] --------------------------------------------------------------------------- bindSorts fi | null bad = Right [ (x, t) | (x, [(t, _)]) <- ok ] | otherwise = Left $ dupBindErrors [ (x, map fst ts) | (x, ts) <- bad] where (bad, ok) = L.partition multiSorted . binds $ fi binds = symBinds . F.bs multiSorted :: (x, [t]) -> Bool multiSorted = (1 <) . length . snd dupBindErrors :: [(F.Symbol, [F.Sort])] -> E.Error dupBindErrors = foldr1 E.catError . map dbe where dbe (x, y) = E.err E.dummySpan $ printf "Multiple sorts for %s : %s \n" (showpp x) (showpp y) --------------------------------------------------------------------------- symBinds :: F.BindEnv -> [SymBinds] --------------------------------------------------------------------------- symBinds = M.toList . M.map Misc.groupList . Misc.group . binders type SymBinds = (F.Symbol, [(F.Sort, [F.BindId])]) binders :: F.BindEnv -> [(F.Symbol, (F.Sort, F.BindId))] binders be = [(x, (F.sr_sort t, i)) | (i, x, t) <- F.bindEnvToList be] --------------------------------------------------------------------------- -- | Alpha Rename bindings to ensure each var appears in unique binder --------------------------------------------------------------------------- renameVV :: F.FInfo a -> F.FInfo a --------------------------------------------------------------------------- renameVV fi = fi {F.bs = be'} where vts = map subcVV $ M.elems $ F.cm fi be' = L.foldl' addVV be vts be = F.bs fi addVV :: F.BindEnv -> (F.Symbol, F.SortedReft) -> F.BindEnv addVV b (x, t) = snd $ F.insertBindEnv x t b subcVV :: F.SubC a -> (F.Symbol, F.SortedReft) subcVV c = (x, sr) where sr = F.slhs c x = F.reftBind $ F.sr_reft sr