g2-0.2.0.0: src/G2/Liquid/Helpers.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
module G2.Liquid.Helpers ( MeasureSymbols (..)
, getGHCInfos
, funcSpecs
, getTySigs
, putTySigs
, getAssumedSigs
, putAssumedSigs
, getQualifiers
, putQualifiers
, findFuncSpec
, measureSpecs
, measureSymbols
, measureNames
, varToName
, varEqName
, namesEq
, fillLHDictArgs ) where
import G2.Language as G2
import G2.Liquid.Types
import G2.Translation.Haskell
#if MIN_VERSION_liquidhaskell(0,9,0)
import qualified Liquid.GHC.Interface as LHI
#else
import qualified Language.Haskell.Liquid.GHC.Interface as LHI
#endif
import Language.Fixpoint.Types.Names
#if MIN_VERSION_liquidhaskell(0,8,10)
import Language.Haskell.Liquid.Types hiding
(Config, TargetInfo (..), TargetSpec (..), GhcSpec (..), cls, names)
#else
import Language.Haskell.Liquid.Types
#endif
import qualified Language.Haskell.Liquid.UX.Config as LHC
import Language.Fixpoint.Types (Qualifier (..))
import Data.List
import qualified Data.Map as M
import qualified Data.Text as T
import GHC as GHC
#if MIN_VERSION_GLASGOW_HASKELL(9,0,2,0)
import GHC.Types.Name
import GHC.Types.Var as V
#else
import Name
import Var as V
#endif
-- | Interface with LH
getGHCInfos :: LHC.Config -> [FilePath] -> [FilePath] -> IO [GhcInfo]
getGHCInfos config proj fp = do
let config' = config {idirs = idirs config ++ proj
, files = files config
, ghcOptions = ["-v"]}
-- GhcInfo
#if MIN_VERSION_liquidhaskell(0,8,10)
(ghci, _) <- LHI.getTargetInfos Nothing config' fp
#else
(ghci, _) <- LHI.getGhcInfos Nothing config' fp
#endif
return ghci
funcSpecs :: [GhcInfo] -> [(Var, LocSpecType)]
funcSpecs fs =
let
asserted = concatMap getTySigs fs
assumed = concatMap getAssumedSigs fs
in
asserted ++ assumed
-- | Functions asserted in LH
getTySigs :: GhcInfo -> [(Var, LocSpecType)]
#if MIN_VERSION_liquidhaskell(0,8,6)
getTySigs = gsTySigs . gsSig . giSpec
#else
getTySigs = gsTySigs . spec
#endif
putTySigs :: GhcInfo -> [(Var, LocSpecType)] -> GhcInfo
#if MIN_VERSION_liquidhaskell(0,8,6)
putTySigs gi@(GI {
giSpec = sp@(SP { gsSig = sp_sig })
}
) new_ty_sigs =
gi { giSpec = sp { gsSig = sp_sig { gsTySigs = new_ty_sigs } } }
#else
putTySigs gi@(GI { spec = sp }) new_ty_sigs =
gi { spec = sp { gsTySigs = new_ty_sigs }}
#endif
-- | Functions assumed in LH
getAssumedSigs :: GhcInfo -> [(Var, LocSpecType)]
#if MIN_VERSION_liquidhaskell(0,8,6)
getAssumedSigs = gsAsmSigs . gsSig . giSpec
#else
getAssumedSigs = gsAsmSigs . spec
#endif
putAssumedSigs :: GhcInfo -> [(Var, LocSpecType)] -> GhcInfo
#if MIN_VERSION_liquidhaskell(0,8,6)
putAssumedSigs gi@(GI {
giSpec = sp@(SP { gsSig = sp_sig })
}
) new_ty_sigs =
gi { giSpec = sp { gsSig = sp_sig { gsTySigs = new_ty_sigs } } }
#else
putAssumedSigs gi@(GI { spec = sp }) new_ty_sigs =
gi { spec = sp { gsTySigs = new_ty_sigs }}
#endif
getQualifiers :: GhcInfo -> [Qualifier]
#if MIN_VERSION_liquidhaskell(0,8,6)
getQualifiers = gsQualifiers . gsQual . giSpec
#else
getQualifiers = gsQualifiers . spec
#endif
putQualifiers :: GhcInfo -> [Qualifier] -> GhcInfo
#if MIN_VERSION_liquidhaskell(0,8,6)
putQualifiers gi@(GI {
giSpec = sp@(SP { gsQual = quals })
}
) new_quals =
gi { giSpec = sp { gsQual = quals { gsQualifiers = new_quals } } }
#else
putQualifiers gi@(GI { spec = sp }) new_quals =
gi { spec = sp { gsQualifiers = new_quals }}
#endif
findFuncSpec :: [GhcInfo] -> G2.Name -> Maybe SpecType
findFuncSpec ghci g2_n =
let
fs = funcSpecs ghci
fs' = map (\(v, lst) -> (V.varName v, lst)) fs
in
case find (\(n, _) -> namesEq n g2_n) fs' of
Just st -> Just . val . snd $ st
Nothing -> Nothing
varToName :: V.Var -> G2.Name
varToName = mkName . V.varName
varEqName :: V.Var -> G2.Name -> Bool
varEqName v = namesEq (V.varName v)
namesEq :: GHC.Name -> G2.Name -> Bool
namesEq ghc_n (Name n m _ _) =
T.pack (occNameString $ nameOccName ghc_n) == n
&& (case nameModule_maybe ghc_n of
Just m' ->
Just (T.pack . moduleNameString . moduleName $ m') == m
Nothing -> m == Nothing)
measureSpecs :: [GhcInfo] -> [Measure SpecType GHC.DataCon]
#if MIN_VERSION_liquidhaskell(0,8,6)
measureSpecs = concatMap (gsMeasures . gsData . giSpec)
#else
measureSpecs = concatMap (gsMeasures . spec)
#endif
newtype MeasureSymbols = MeasureSymbols { symbols :: [Symbol] }
measureSymbols :: [GhcInfo] -> MeasureSymbols
measureSymbols = MeasureSymbols . measureNames
measureNames :: [GhcInfo] -> [Symbol]
#if MIN_VERSION_liquidhaskell(0,8,6)
measureNames = map (val . msName) . measureSpecs
#else
measureNames = map (val . name) . measureSpecs
#endif
-- The walk function takes lhDict arguments that are not correctly accounted for by mkStrict.
-- The arguments are not actually used, so, here, we fill them in with undefined.
fillLHDictArgs :: Walkers -> Expr -> Expr
fillLHDictArgs w = modifyAppTop (fillLHDictArgs' w)
fillLHDictArgs' :: Walkers -> Expr -> Expr
fillLHDictArgs' w e
| f@(Var i):xs <- unApp e
, any (\(_, i') -> i == i') (M.toList w) = mkApp $ f:fillLHDictArgs'' 0 xs
| otherwise = e
fillLHDictArgs'' :: Int -> [Expr] -> [Expr]
fillLHDictArgs'' !n [] = replicate n (Prim Undefined TyBottom)
fillLHDictArgs'' !n (t@(Type _):xs) = t:fillLHDictArgs'' (n + 1) xs
fillLHDictArgs'' !n xs = replicate n (Prim Undefined TyBottom) ++ xs