module Language.Haskell.Liquid.Bare.RTEnv ( makeRTEnv ) where
import Prelude hiding (error)
import Data.Graph hiding (Graph)
import Data.Maybe
import qualified Control.Exception as Ex
import qualified Data.HashMap.Strict as M
import qualified Data.List as L
import Language.Fixpoint.Misc (fst3)
import Language.Fixpoint.Types (Expr(..), Symbol, symbol)
import Language.Haskell.Liquid.GHC.Misc (sourcePosSrcSpan)
import Language.Haskell.Liquid.Types.RefType (symbolRTyVar)
import Language.Haskell.Liquid.Types
import qualified Language.Haskell.Liquid.Measure as Ms
import Language.Haskell.Liquid.Bare.Env
import Language.Haskell.Liquid.Bare.Expand
import Language.Haskell.Liquid.Bare.OfType
import Language.Haskell.Liquid.Bare.Resolve
makeRTEnv :: ModName
-> Ms.BareSpec
-> [(ModName, Ms.BareSpec)]
-> M.HashMap Symbol LMap
-> BareM ()
makeRTEnv m lfSpec specs lm = do
makeREAliases (eAs ++ eAs' ++ eAs'')
makeRTAliases tAs
where
tAs = [ (m, t) | (m, s) <- specs, t <- Ms.aliases s ]
eAs = [ (m, e) | (m, s) <- specs, e <- Ms.ealiases s ]
eAs' = [ (m, e) | e <- Ms.ealiases lfSpec ]
eAs'' = [ (m, e) | (_, xl) <- M.toList lm, let e = lmapEAlias xl ]
makeRTAliases :: [(ModName, RTAlias Symbol BareType)] -> BareM ()
makeRTAliases = graphExpand buildTypeEdges expBody
where
expBody (m, xt) = inModule m $ do
let l = rtPos xt
let l' = rtPosE xt
body <- withVArgs l l' (rtVArgs xt) $ ofBareType l $ rtBody xt
setRTAlias (rtName xt) $ mapRTAVars symbolRTyVar $ xt { rtBody = body }
makeREAliases :: [(ModName, RTAlias Symbol Expr)] -> BareM ()
makeREAliases
= graphExpand buildExprEdges expBody
where
expBody (mod, xt)
= inModule mod $
do let l = rtPos xt
let l' = rtPosE xt
body <- withVArgs l l' (rtVArgs xt) $ resolve l =<< expand (rtBody xt)
setREAlias (rtName xt) $ xt { rtBody = body }
graphExpand :: (PPrint t)
=> (AliasTable t -> t -> [Symbol])
-> ((ModName, RTAlias Symbol t) -> BareM b)
-> [(ModName, RTAlias Symbol t)]
-> BareM ()
graphExpand buildEdges expBody xts
= do let table = buildAliasTable xts
graph = buildAliasGraph (buildEdges table) (map snd xts)
checkCyclicAliases table graph
mapM_ expBody $ genExpandOrder table graph
type AliasTable t = M.HashMap Symbol (ModName, RTAlias Symbol t)
buildAliasTable :: [(ModName, RTAlias Symbol t)] -> AliasTable t
buildAliasTable
= M.fromList . map (\(m, rta) -> (rtName rta, (m, rta)))
fromAliasSymbol :: AliasTable t -> Symbol -> (ModName, RTAlias Symbol t)
fromAliasSymbol table sym
= fromMaybe err $ M.lookup sym table
where
err = panic Nothing $ "fromAliasSymbol: Dangling alias symbol: " ++ show sym
type Graph t = [Node t]
type Node t = (t, t, [t])
buildAliasGraph :: (PPrint t) => (t -> [Symbol]) -> [RTAlias Symbol t] -> Graph Symbol
buildAliasGraph buildEdges
= map (buildAliasNode buildEdges)
buildAliasNode :: (PPrint t) => (t -> [Symbol]) -> RTAlias Symbol t -> Node Symbol
buildAliasNode buildEdges alias
= (rtName alias, rtName alias, buildEdges $ rtBody alias)
checkCyclicAliases :: AliasTable t -> Graph Symbol -> BareM ()
checkCyclicAliases table graph
= case mapMaybe go $ stronglyConnComp graph of
[] -> return ()
sccs -> Ex.throw (cycleAliasErr table <$> sccs)
where
go (CyclicSCC vs) = Just vs
go (AcyclicSCC _) = Nothing
cycleAliasErr :: AliasTable t -> [Symbol] -> Error
cycleAliasErr _ [] = panic Nothing "checkCyclicAliases: No type aliases in reported cycle"
cycleAliasErr t scc@(rta:_) = ErrAliasCycle { pos = fst (locate rta)
, acycle = map locate scc }
where
locate sym = ( sourcePosSrcSpan $ rtPos $ snd $ fromAliasSymbol t sym
, pprint sym )
genExpandOrder :: AliasTable t -> Graph Symbol -> [(ModName, RTAlias Symbol t)]
genExpandOrder table graph
= map (fromAliasSymbol table) symOrder
where
(digraph, lookupVertex, _)
= graphFromEdges graph
symOrder
= map (fst3 . lookupVertex) $ reverse $ topSort digraph
ordNub :: Ord a => [a] -> [a]
ordNub = map head . L.group . L.sort
buildTypeEdges :: AliasTable BareType -> BareType -> [Symbol]
buildTypeEdges table = ordNub . go
where
go :: BareType -> [Symbol]
go (RApp c ts rs _) = go_alias (symbol c) ++ concatMap go ts ++ concatMap go (mapMaybe go_ref rs)
go (RFun _ t1 t2 _) = go t1 ++ go t2
go (RAppTy t1 t2 _) = go t1 ++ go t2
go (RAllE _ t1 t2) = go t1 ++ go t2
go (REx _ t1 t2) = go t1 ++ go t2
go (RAllT _ t) = go t
go (RAllP _ t) = go t
go (RAllS _ t) = go t
go (RVar _ _) = []
go (RExprArg _) = []
go (RHole _) = []
go (RRTy env _ _ t) = concatMap (go . snd) env ++ go t
go_alias c = [c | M.member c table]
go_ref (RProp _ (RHole _)) = Nothing
go_ref (RProp _ t) = Just t
buildExprEdges :: M.HashMap Symbol a -> Expr -> [Symbol]
buildExprEdges table = ordNub . go
where
go :: Expr -> [Symbol]
go (EApp e1 e2) = go e1 ++ go e2
go (ENeg e) = go e
go (EBin _ e1 e2) = go e1 ++ go e2
go (EIte _ e1 e2) = go e1 ++ go e2
go (ECst e _) = go e
go (ESym _) = []
go (ECon _) = []
go (EVar v) = go_alias v
go (PAnd ps) = concatMap go ps
go (POr ps) = concatMap go ps
go (PNot p) = go p
go (PImp p q) = go p ++ go q
go (PIff p q) = go p ++ go q
go (PAll _ p) = go p
go (ELam _ e) = go e
go (PAtom _ e1 e2) = go e1 ++ go e2
go (ETApp e _) = go e
go (ETAbs e _) = go e
go (PKVar _ _) = []
go (PExist _ e) = go e
go (PGrad _ _ _ e) = go e
go_alias f = [f | M.member f table ]