{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PatternGuards #-}
module Language.Fixpoint.Solver.UniqifyBinds (renameAll) where
import Language.Fixpoint.Types
import Language.Fixpoint.Solver.Sanitize (dropDeadSubsts)
import Language.Fixpoint.Misc (fst3, mlookup)
import qualified Data.HashMap.Strict as M
import qualified Data.HashSet as S
import qualified Data.List as L
import Data.Foldable (foldl')
import Data.Maybe (catMaybes, fromJust, isJust)
import Data.Hashable (Hashable)
import GHC.Generics (Generic)
import Control.Arrow (second)
import Control.DeepSeq (NFData, ($!!))
renameAll :: SInfo a -> SInfo a
renameAll fi2 = fi6
where
fi6 = {-# SCC "dropDead" #-} dropDeadSubsts fi5
fi5 = {-# SCC "dropUnused" #-} dropUnusedBinds fi4
fi4 = {-# SCC "renameBinds" #-} renameBinds fi3 $!! rnm
fi3 = {-# SCC "renameVars" #-} renameVars fi2 rnm $!! idm
rnm = {-# SCC "mkRenameMap" #-} mkRenameMap $!! bs fi2
idm = {-# SCC "mkIdMap" #-} mkIdMap fi2
dropUnusedBinds :: SInfo a -> SInfo a
dropUnusedBinds fi = fi {bs = filterBindEnv isUsed (bs fi)}
where
isUsed i _x r = memberIBindEnv i usedBinds || isTauto r
usedBinds = L.foldl' unionIBindEnv emptyIBindEnv (cEnvs ++ wEnvs)
wEnvs = wenv <$> M.elems (ws fi)
cEnvs = senv <$> M.elems (cm fi)
data Ref
= RB !BindId
| RI !Integer
deriving (Eq, Generic)
instance NFData Ref
instance Hashable Ref
type IdMap = M.HashMap Ref (S.HashSet BindId)
type RenameMap = M.HashMap Symbol [(Sort, Maybe Symbol)]
mkIdMap :: SInfo a -> IdMap
mkIdMap fi = M.foldlWithKey' (updateIdMap $ bs fi) M.empty $ cm fi
updateIdMap :: BindEnv -> IdMap -> Integer -> SimpC a -> IdMap
updateIdMap be m scId s = M.insertWith S.union (RI scId) refSet m'
where
ids = elemsIBindEnv (senv s)
nameMap = M.fromList [(fst $ lookupBindEnv i be, i) | i <- ids]
m' = foldl' (insertIdIdLinks be nameMap) m ids
symSet = S.fromList $ syms $ crhs s
refSet = namesToIds symSet nameMap
insertIdIdLinks :: BindEnv -> M.HashMap Symbol BindId -> IdMap -> BindId -> IdMap
insertIdIdLinks be nameMap m i = M.insertWith S.union (RB i) refSet m
where
sr = snd $ lookupBindEnv i be
symSet = reftFreeVars $ sr_reft sr
refSet = namesToIds symSet nameMap
namesToIds :: S.HashSet Symbol -> M.HashMap Symbol BindId -> S.HashSet BindId
namesToIds xs m = S.fromList $ catMaybes [M.lookup x m | x <- S.toList xs]
mkRenameMap :: BindEnv -> RenameMap
mkRenameMap be = foldl' (addId be) M.empty ids
where
ids = fst3 <$> bindEnvToList be
addId :: BindEnv -> RenameMap -> BindId -> RenameMap
addId be m i
| M.member sym m = addDupId m sym t i
| otherwise = M.insert sym [(t, Nothing)] m
where
(sym, t) = second sr_sort $ lookupBindEnv i be
addDupId :: RenameMap -> Symbol -> Sort -> BindId -> RenameMap
addDupId m sym t i
| isJust $ L.lookup t mapping = m
| otherwise = M.insert sym ((t, Just $ renameSymbol sym i) : mapping) m
where
mapping = fromJust $ M.lookup sym m
renameVars :: SInfo a -> RenameMap -> IdMap -> SInfo a
renameVars fi rnMap idMap = M.foldlWithKey' (updateRef rnMap) fi idMap
updateRef :: RenameMap -> SInfo a -> Ref -> S.HashSet BindId -> SInfo a
updateRef rnMap fi rf bset = applySub (mkSubst subs) fi rf
where
symTList = [second sr_sort $ lookupBindEnv i $ bs fi | i <- S.toList bset]
subs = catMaybes $ mkSubUsing rnMap <$> symTList
mkSubUsing :: RenameMap -> (Symbol, Sort) -> Maybe (Symbol, Expr)
mkSubUsing m (sym, t) = do
newName <- fromJust $ L.lookup t $ mlookup m sym
return (sym, eVar newName)
applySub :: Subst -> SInfo a -> Ref -> SInfo a
applySub sub fi (RB i) = fi { bs = adjustBindEnv go i (bs fi) }
where
go (sym, sr) = (sym, subst sub sr)
applySub sub fi (RI i) = fi { cm = M.adjust go i (cm fi) }
where
go c = c { _crhs = subst sub (_crhs c) }
renameBinds :: SInfo a -> RenameMap -> SInfo a
renameBinds fi m = fi { bs = bindEnvFromList $ renameBind m <$> beList }
where
beList = bindEnvToList $ bs fi
renameBind :: RenameMap -> (BindId, Symbol, SortedReft) -> (BindId, Symbol, SortedReft)
renameBind m (i, sym, sr)
| Just newSym <- mnewSym = (i, newSym, sr)
| otherwise = (i, sym, sr)
where
t = sr_sort sr
mnewSym = fromJust $ L.lookup t $ mlookup m sym