g2-0.2.0.0: src/G2/Liquid/Conversion.hs
{-# LANGUAGE CPP, FlexibleContexts #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
module G2.Liquid.Conversion ( LHDictMap
, DictMaps (..)
, BoundTypes
, CheckPre (..)
, mergeLHSpecState
, convertSpecType
, dictMapFromIds
, convertLHExpr
, specTypeToType
, unsafeSpecTypeToType
, symbolName
, lhTCDict'
, higherOrderTickName) where
import G2.Language
import qualified G2.Language.KnownValues as KV
import G2.Language.Monad
import qualified G2.Language.ExprEnv as E
import G2.Language.TypeEnv
import G2.Liquid.Types
import G2.Translation.Haskell
#if MIN_VERSION_GLASGOW_HASKELL(9,0,2,0)
import qualified GHC.Types.Var as Var
#else
import qualified Var as Var
#endif
import Language.Fixpoint.Types.Names
import Language.Fixpoint.Types.Sorts
import qualified Language.Fixpoint.Types.Refinements as Ref
import Language.Fixpoint.Types.Refinements hiding (Expr, I)
import Language.Haskell.Liquid.Types
import Data.Coerce
import Data.Foldable
import qualified Data.HashMap.Lazy as HM
import qualified Data.Map as M
import Data.Maybe
import qualified Data.Text as T
-- | A mapping of TyVar Name's, to Id's for the LH dict's
type LHDictMap = HM.HashMap Name Id
-- | A mapping of TyVar Name's, to Id's for the Num dict's
type NumDictMap = HM.HashMap Name Id
-- | A mapping of TyVar Name's, to Id's for the Integral dict's
type IntegralDictMap = HM.HashMap Name Id
-- | A mapping of TyVar Name's, to Id's for the Fractional dict's
type FractionalDictMap = HM.HashMap Name Id
-- | A mapping of TyVar Name's, to Id's for the Ord dict's
type OrdDictMap = HM.HashMap Name Id
-- | A collection of all DictMaps required to convert LH refinement types to G2 `Expr`@s@
data DictMaps = DictMaps { lh_dicts :: LHDictMap
, num_dicts :: NumDictMap
, integral_dicts :: IntegralDictMap
, fractional_dicts :: FractionalDictMap
, ord_dicts :: OrdDictMap } deriving (Eq, Show, Read)
copyIds :: Name -> Name -> DictMaps -> DictMaps
copyIds n1 n2 dm@(DictMaps { lh_dicts = lhd
, num_dicts = nd
, integral_dicts = ind
, fractional_dicts = frac
, ord_dicts = od }) =
let
dm2 = case HM.lookup n1 lhd of
Just lh -> dm { lh_dicts = HM.insert n2 lh lhd }
Nothing -> dm
dm3 = case HM.lookup n1 nd of
Just num -> dm2 { num_dicts = HM.insert n2 num nd }
Nothing -> dm2
dm4 = case HM.lookup n1 ind of
Just int -> dm3 { integral_dicts = HM.insert n2 int ind }
Nothing -> dm3
dm5 = case HM.lookup n1 frac of
Just fr -> dm4 { fractional_dicts = HM.insert n2 fr frac }
Nothing -> dm4
dm6 = case HM.lookup n1 od of
Just ord -> dm5 { ord_dicts = HM.insert n2 ord od }
Nothing -> dm5
in
dm6
-- | A mapping of variable names to the corresponding types
type BoundTypes = HM.HashMap Name Type
type NMExprEnv = HM.HashMap (T.Text, Maybe T.Text) (Name, Expr)
mergeLHSpecState :: [(Var.Var, LocSpecType)] -> LHStateM ()
mergeLHSpecState var_st = do
eenv <- exprEnv
let nm_eenv = E.nameModMap eenv
mapM_ (uncurry (mergeLHSpecState' nm_eenv)) var_st
mergeLHSpecState' :: NMExprEnv -> Var.Var -> LocSpecType -> LHStateM ()
mergeLHSpecState' nm_eenv v lst = do
let
(Id (Name n m _ _) _) = mkIdUnsafe v
g2N = HM.lookup (n, m) nm_eenv
case g2N of
Just (n', e) -> do
case convertVar n' of
True -> do
e' <- mergeSpecType (val lst) n' e
insertE n' e'
assumpt <- createAssumption (val lst) e
insertAssumptionM n' assumpt
post <- createPost (val lst) e
insertPostM n' post
False -> return ()
Nothing -> return ()
convertVar :: Name -> Bool
convertVar (Name "fromInteger" _ _ _) = False
convertVar (Name "error" _ _ _) = False
convertVar (Name "patError" _ _ _) = False
convertVar (Name "." _ _ _) = False
convertVar _ = True
mergeSpecType :: SpecType -> Name -> Expr -> LHStateM Expr
mergeSpecType st fn e = do
lh <- lhTCM
-- Create new bindings to use in the Ref. Type
let argT = spArgumentTypes e
is <- mapM argsFromArgT argT
let lu = map argTypeToLamUse argT
-- Gather up LH TC's to use in Assertion
dm@(DictMaps {lh_dicts = lhm}) <- dictMapFromIds is
trueE <- mkTrueE
higher_is <- handleHigherOrderSpecs CheckPre (mkHigherAssert trueE) lh dm (HM.map typeOf lhm) is st
let e' = foldl' App e . map (\(i, hi) -> maybe (Var i) id hi) $ zip is higher_is
-- Create a variable for the returned value
-- We do not pass the LH TC to the assertion, since there is no matching
-- lambda for it in the LH Spec
r <- freshIdN (typeOf e')
let is' = filter (not . isTC lh . typeOf) is
assert <- convertAssertSpecType dm (HM.map typeOf lhm) is' r st
let fc = FuncCall { funcName = fn
, arguments = map Var is
, returns = Var r }
e'' = modifyASTs (repAssertFC fc) e'
let rLet = Let [(r, e'')] $ Assert (Just fc) assert (Var r)
let e''' = foldr (uncurry Lam) rLet $ zip lu is
return e'''
where
-- We insert an extra, redundant assume to record information about the function being used as a higher order function
mkHigherAssert true_dc spec i ars ret =
Tick (NamedLoc higherOrderTickName) . Assume (Just $ FuncCall { funcName = idName i, arguments = map Var ars, returns = Var ret }) true_dc $ Assert Nothing spec (Var ret)
repAssertFC fc_ (Assert Nothing e1 e2) = Assert (Just fc_) e1 e2
repAssertFC _ e_ = e_
createAssumption :: SpecType -> Expr -> LHStateM ([(LamUse, Id)], [Maybe Expr], Expr)
createAssumption st e = do
lh <- lhTCM
-- Create new bindings to use in the Ref. Type
let argT = spArgumentTypes e
is <- mapM argsFromArgT argT
let lu = map argTypeToLamUse argT
let is' = filter (not . isTC lh . typeOf) is
dm@(DictMaps {lh_dicts = lhm}) <- dictMapFromIds is
assume <- convertAssumeSpecType dm (HM.map typeOf lhm) is' st
higher_is <- handleHigherOrderSpecs CheckOnlyPost mkHigherAssume lh dm (HM.map typeOf lhm) is st
let assume' = foldr (uncurry Lam) assume $ zip lu is
return (zip lu is, higher_is, assume')
where
mkHigherAssume spec i ars ret =
Tick (NamedLoc higherOrderTickName) $ Assume (Just $ FuncCall { funcName = idName i, arguments = map Var ars, returns = Var ret } ) spec (Var ret)
higherOrderTickName :: Name
higherOrderTickName = Name "HIGHER_ORDER_FUNC" Nothing 0 Nothing
createPost :: SpecType -> Expr -> LHStateM Expr
createPost st e = do
lh <- lhTCM
-- Create new bindings to use in the Ref. Type
let argT = spArgumentTypes e
is <- mapM argsFromArgT argT
let lu = map argTypeToLamUse argT
r <- freshIdN (returnType e)
let is' = filter (not . isTC lh . typeOf) is
dm@(DictMaps {lh_dicts = lhm}) <- dictMapFromIds is
pst <- convertPostSpecType dm (HM.map typeOf lhm) is' r st
return . foldr (uncurry Lam) pst $ zip (lu ++ [TermL]) (is ++ [r])
dictMapFromIds :: [Id] -> LHStateM DictMaps
dictMapFromIds is = do
lh <- lhTCM
num <- lhNumTCM
int <- return . KV.integralTC =<< knownValues
frac <- return . KV.fractionalTC =<< knownValues
ord <- ordTCM
let lhm = tcWithNameMap lh is
let nm = tcWithNameMap num is
let im = tcWithNameMap int is
let fr = tcWithNameMap frac is
let om = tcWithNameMap ord is
return $ DictMaps { lh_dicts = lhm
, num_dicts = nm
, integral_dicts = im
, fractional_dicts = fr
, ord_dicts = om }
isTC :: Name -> Type -> Bool
isTC n t = case tyAppCenter t of
TyCon n' _ -> n == n'
_ -> False
argsFromArgT :: ArgType -> LHStateM Id
argsFromArgT (AnonType t) = freshIdN t
argsFromArgT (NamedType i) = return i
-- | Should we translate the precondition in convertSpecType?
data CheckPre = CheckPre | CheckOnlyPost deriving Eq
convertAssumeSpecType :: DictMaps -> BoundTypes -> [Id] -> SpecType -> LHStateM Expr
convertAssumeSpecType m bt is st = do
convertSpecType CheckPre m bt is Nothing st
convertAssertSpecType :: DictMaps -> BoundTypes -> [Id] -> Id -> SpecType -> LHStateM Expr
convertAssertSpecType m bt is r st = do
convertSpecType CheckPre m bt is (Just r) st
convertPostSpecType :: DictMaps -> BoundTypes -> [Id] -> Id -> SpecType -> LHStateM Expr
convertPostSpecType m bt is r st =
convertSpecType CheckOnlyPost m bt is (Just r) st
-- | See also: convertAssumeSpecType, convertAssertSpecType
-- We can Maybe pass an Id for the value returned by the function
-- If we do, our Expr includes the Refinement on the return value,
-- otherwise it does not. This allows us to use this same function to
-- translate both for assumptions and assertions
convertSpecType :: CheckPre -> DictMaps -> BoundTypes -> [Id] -> Maybe Id -> SpecType -> LHStateM Expr
convertSpecType _ m bt _ r (RVar {rt_var = (RTV v), rt_reft = ref})
| Just r' <- r = do
let symb = reftSymbol $ ur_reft ref
let i = mkIdUnsafe v
let symbId = convertSymbolT symb (TyVar i)
let bt' = HM.insert (idName symbId) (typeOf symbId) bt
re <- convertLHExpr m bt' Nothing (reftExpr $ ur_reft ref)
return $ App (Lam TermL symbId re) (Var r')
| otherwise = mkTrueE
convertSpecType cp m bt (i:is) r (RFun {rt_bind = b, rt_in = fin, rt_out = fout }) = do
t <- unsafeSpecTypeToType fin
let i' = convertSymbolT b t
let bt' = HM.insert (idName i') t bt
e <- convertSpecType cp m bt' is r fout
case hasFuncType i of
True -> return $ App (Lam TermL i' e) (Var i)
False -> do
e' <- convertSpecType cp m bt' [] (Just i') fin
an <- lhAndE
let e'' = if cp == CheckPre
then App (App an e') e
else e
return $ App (Lam TermL i' e'') (Var i)
convertSpecType cp m bt (i:is) r (RAllT {rt_tvbind = RTVar (RTV v) _, rt_ty = rty}) = do
let i' = mkIdUnsafe v
let m' = copyIds (idName i) (idName i') m
let bt' = HM.insert (idName i') (typeOf i) bt
e <- convertSpecType cp m' bt' is r rty
return $ App (Lam TypeL i' e) (Var i)
convertSpecType cp m bt _ r (RApp {rt_tycon = c, rt_reft = ref, rt_args = as})
| Just r' <- r = do
let symb = reftSymbol $ ur_reft ref
ty <- return . maybe (error "Error in convertSpecType") id =<< rTyConType c as
let i = convertSymbolT symb ty
let bt' = HM.insert (idName i) ty bt
argsPred <- polyPredFunc cp as ty m bt' r'
re <- convertLHExpr m bt' Nothing (reftExpr $ ur_reft ref)
an <- lhAndE
return $ App (App an (App (Lam TermL i re) (Var r'))) argsPred
| otherwise = mkTrueE
convertSpecType _ _ _ _ _ (RAppTy { }) = mkTrueE
convertSpecType _ _ _ _ _ st@(RFun {}) = error $ "RFun " ++ show st
convertSpecType _ _ _ _ _ st@(RAllT {}) = error $ "RAllT " ++ show st
convertSpecType _ _ _ _ _ st@(RAllP {}) = error $ "RAllP " ++ show st
convertSpecType _ _ _ _ _ st@(RAllE {}) = error $ "RAllE " ++ show st
convertSpecType _ _ _ _ _ st@(REx {}) = error $ "REx " ++ show st
convertSpecType _ _ _ _ _ st@(RExprArg {}) = error $ "RExprArg " ++ show st
convertSpecType _ _ _ _ _ st@(RRTy {}) = error $ "RRTy " ++ show st
convertSpecType _ _ _ _ _ st = error $ "Bad st = " ++ show st
handleHigherOrderSpecs :: CheckPre -> (Expr -> Id -> [Id] -> Id -> Expr) -> Name -> DictMaps -> BoundTypes -> [Id] -> SpecType -> LHStateM [Maybe Expr]
handleHigherOrderSpecs check_pre wrap_spec lh dm bt (i:is) st | isTC lh $ typeOf i = do
es <- handleHigherOrderSpecs check_pre wrap_spec lh dm bt is st
return $ Nothing:es
handleHigherOrderSpecs check_pre wrap_spec lh dm bt (i:is) (RFun {rt_bind = b, rt_in = fin, rt_out = fout })
| hasFuncType i = do
t <- unsafeSpecTypeToType fin
let i' = convertSymbolT b t
let bt' = HM.insert (idName i') t bt
es <- handleHigherOrderSpecs check_pre wrap_spec lh dm bt' is fout
ars <- freshIdsN (anonArgumentTypes i)
ret <- freshIdN (returnType i)
spec <- convertSpecType check_pre dm bt' ars (Just ret) fin
let let_assert_spec = mkLams (zip (repeat TermL) ars)
. Let [(ret, mkApp $ Var i:map Var ars)]
$ wrap_spec spec i ars ret -- (Var ret)
return $ Just let_assert_spec:es
| otherwise = do
t <- unsafeSpecTypeToType fin
let i' = convertSymbolT b t
let bt' = HM.insert (idName i') t bt
es <- handleHigherOrderSpecs check_pre wrap_spec lh dm bt' is fout
return $ Nothing:es
handleHigherOrderSpecs _ _ _ _ _ [] _ = return []
handleHigherOrderSpecs check_pre wrap_spec lh dm bt (i:is) (RAllT {rt_tvbind = RTVar (RTV v) _, rt_ty = rty}) = do
let i' = mkIdUnsafe v
let dm' = copyIds (idName i) (idName i') dm
let bt' = HM.insert (idName i') (typeOf i) bt
es <- handleHigherOrderSpecs check_pre wrap_spec lh dm' bt' is rty
return $ Nothing:es
handleHigherOrderSpecs _ _ _ _ _ _ _ = error "handleHigherOrderSpecs: unhandled SpecType"
polyPredFunc :: CheckPre -> [SpecType] -> Type -> DictMaps -> BoundTypes -> Id -> LHStateM Expr
polyPredFunc cp as ty m bt b = do
dict <- lhTCDict m ty
as' <- mapM (polyPredLam cp m bt) as
bool <- tyBoolT
let ar1 = Type (typeOf b)
ars = [dict] ++ as' ++ [Var b]
t = TyForAll b $ foldr1 TyFun $ map typeOf ars ++ [bool]
lhPP <- lhPPM
return $ mkApp $ Var (Id lhPP t):ar1:ars
polyPredLam :: CheckPre -> DictMaps -> BoundTypes -> SpecType -> LHStateM Expr
polyPredLam cp m bt rapp = do
t <- unsafeSpecTypeToType rapp
let argT = spArgumentTypes $ PresType t
is <- mapM argsFromArgT argT
i <- freshIdN . returnType $ PresType t
st <- convertSpecType cp m bt is (Just i) rapp
return $ Lam TermL i st
convertLHExpr :: DictMaps -> BoundTypes -> Maybe Type -> Ref.Expr -> LHStateM Expr
convertLHExpr _ _ t (ECon c) = convertCon t c
convertLHExpr _ bt t (EVar s) = convertEVar (symbolName s) bt t
convertLHExpr m bt rt eapp@(EApp e e') = do
meas <- measuresM
m_set_e <- convertSetExpr meas m bt rt eapp
case m_set_e of
Just set_e -> return set_e
Nothing -> do
f <- convertLHExpr m bt Nothing e
let at = argumentTypes f
f_ar_t = case at of
(_:_) -> Just $ last at
_ -> Nothing
f_ar_ts = fmap relTyVars f_ar_t
argE <- convertLHExpr m bt f_ar_t e'
let tArgE = typeOf argE
ctArgE = tyAppCenter tArgE
ts = take (numTypeArgs f) $ relTyVars tArgE
case (ctArgE, f_ar_ts) of
(_, Just f_ar_ts') -> do
let specTo = concatMap (map snd) $ map M.toList $ map (fromJust . uncurry specializes) $ zip ts f_ar_ts'
te = map Type specTo
tcs <- mapM (lhTCDict m) ts
let fw = mkApp $ f:te
apps = mkApp $ fw:tcs ++ [argE]
return apps
_ -> return $ App f argE
where
relTyVars t@(TyVar _) = [t]
relTyVars t@(TyApp _ _) = tyAppArgs t
relTyVars _ = []
convertLHExpr m bt t (ENeg e) = do
e' <- convertLHExpr m bt t e
let t' = typeOf e'
neg <- lhNegateM
num <- lhNumTCM
a <- freshIdN TYPE
let tva = TyVar a
let negate' = Var $ Id neg
(TyForAll a
(TyFun
(TyApp (TyCon num (TyFun TYPE TYPE)) tva)
(TyFun
tva
tva
)
)
)
nDict <- numDict m t'
return $ mkApp [ negate'
, Type t'
, nDict
, e' ]
convertLHExpr m bt t (EBin b e e') = do
(e2, e2') <- correctTypes m bt t e e'
b' <- convertBop b
let t' = typeOf e2
nDict <- bopTCDict b m t'
return $ mkApp [ b'
, Type t'
, nDict
, e2
, e2' ]
convertLHExpr m bt t (EIte b e e') = do
b2 <- convertLHExpr m bt t b
(e2, e2') <- correctTypes m bt t e e'
trueDC <- mkDCTrueM
falseDC <- mkDCFalseM
bnd <- freshIdN =<< tyBoolT
return $ Case b2 bnd (typeOf e2) [Alt (DataAlt trueDC []) e2, Alt (DataAlt falseDC []) e2']
convertLHExpr m bt _ (ECst e s) = do
t <- sortToType s
convertLHExpr m bt (Just t) e
convertLHExpr m bt _ (PAnd es) = do
es' <- mapM (convertLHExpr m bt Nothing) es
trueE <- mkTrueE
an <- lhAndE
case es' of
[] -> return $ trueE
[e] -> return e
_ -> return $ foldr (\e -> App (App an e)) trueE es'
convertLHExpr m bt _ (POr es) = do
es' <- mapM (convertLHExpr m bt Nothing) es
false <- mkFalseE
orE <- lhOrE
case es' of
[] -> return false
[e] -> return e
_ -> return $ foldr (\e -> App (App orE e)) false es'
convertLHExpr m bt _ (PNot e) = do
e' <- convertLHExpr m bt Nothing e
no <- notM
return (App no e')
convertLHExpr m bt t (PImp e1 e2) = do
e1' <- convertLHExpr m bt t e1
e2' <- convertLHExpr m bt t e2
imp <- mkImpliesE
return $ mkApp [imp, e1', e2']
convertLHExpr m bt t (PIff e1 e2) = do
e1' <- convertLHExpr m bt t e1
e2' <- convertLHExpr m bt t e2
iff <- iffM
return $ mkApp [iff, e1', e2']
convertLHExpr m bt _ (PAtom brel e1 e2) = do
(e1', e2') <- correctTypes m bt Nothing e1 e2
brel' <- convertBrel brel
let t' = typeOf e1'
dict <- brelTCDict m t'
return $ mkApp [brel', Type t', dict, e1', e2']
convertLHExpr _ _ _ e = error $ "Untranslated LH Expr " ++ (show e)
convertSetExpr :: Measures -> DictMaps -> BoundTypes -> Maybe Type -> Ref.Expr -> LHStateM (Maybe Expr)
convertSetExpr meas dm bt rt e
| [EVar v, e1] <- unEApp e
, Just (nm, nm_mod) <- get_nameTyVarAr v
, Just (f_nm, f_e) <- E.lookupNameMod nm nm_mod meas = do
e1' <- convertLHExpr dm bt rt e1
tyI <- tyIntegerT
t <- if typeOf e1' == tyI then tyIntT else return $ typeOf e1'
e1'' <- if typeOf e1' == tyI then correctType dm t e1' else return e1'
return . Just $ mkApp ([ Var (Id f_nm (typeOf f_e))
, Type t
, e1''])
| [EVar v, e1, e2] <- unEApp e
, Just (nm, nm_mod) <- get_nameTyVarArOrd v
, Just (f_nm, f_e) <- E.lookupNameMod nm nm_mod meas = do
e1' <- convertLHExpr dm bt rt e1
e2' <- convertLHExpr dm bt rt e2
let TyApp _ t2 = typeOf e2'
e1'' <- correctType dm t2 e1'
let t = typeOf e1''
ord <- ordDict dm t
return . Just $ mkApp ([ Var (Id f_nm (typeOf f_e))
, Type t
, ord
, e1''
, e2' ])
| EVar v:es <- unEApp e
, Just (nm, nm_mod) <- get_nameSetAr v
, Just (f_nm, f_e) <- E.lookupNameMod nm nm_mod meas = do
es' <- mapM (convertLHExpr dm bt rt) es
case typeOf (head es') of
TyApp _ t -> do
return . Just $ mkApp ([ Var (Id f_nm (typeOf f_e))
, Type t ]
++ es')
_ -> do
t <- tyIntT
return . Just $ App (Var (Id f_nm (typeOf f_e))) (Type t)
| EVar v:es <- unEApp e
, Just (nm, nm_mod) <- get_nameSetArOrd v
, Just (f_nm, f_e) <- E.lookupNameMod nm nm_mod meas = do
es' <- mapM (convertLHExpr dm bt rt) es
case typeOf (head es') of
TyApp _ t -> do
ord <- ordDict dm t
return . Just $ mkApp ([ Var (Id f_nm (typeOf f_e))
, Type t
, ord ]
++ es')
_ -> error "convertSetExpr: incorrect type"
| otherwise = return Nothing
where
get_nameTyVarAr v = case nameOcc (symbolName v) of
"Set_sng" -> Just ("singleton", Just "Data.Set.Internal")
_ -> Nothing
get_nameTyVarArOrd v = case nameOcc (symbolName v) of
"Set_mem" -> Just ("member", Just "Data.Set.Internal")
_ -> Nothing
get_nameSetAr v = case nameOcc (symbolName v) of
"Set_empty" -> Just ("empty", Just "Data.Set.Internal")
"Set_emp" -> Just ("null", Just "Data.Set.Internal")
_ -> Nothing
get_nameSetArOrd v = case nameOcc (symbolName v) of
"Set_cup" -> Just ("union", Just "Data.Set.Internal")
"Set_cap" -> Just ("intersection", Just "Data.Set.Internal")
"Set_sub" -> Just ("isSubsetOf", Just "Data.Set.Internal")
_ -> Nothing
unEApp :: Ref.Expr -> [Ref.Expr]
unEApp (EApp f a) = unEApp f ++ [a]
unEApp e = [e]
convertBop :: Bop -> LHStateM Expr
convertBop Ref.Plus = convertBop' lhPlusM
convertBop Ref.Minus = convertBop' lhMinusM
convertBop Ref.Times = convertBop' lhTimesM
convertBop Ref.Div = convertBop' lhDivM
convertBop Ref.Mod = convertBop' lhModM
convertBop Ref.RTimes = convertBop' lhTimesM
convertBop Ref.RDiv = convertBop' lhDivM
convertBop' :: LHStateM Name -> LHStateM Expr
convertBop' f = do
num <- lhNumTCM
n <- f
a <- freshIdN TYPE
let tva = TyVar a
return $ Var $ Id n (TyForAll a
(TyFun
(TyApp (TyCon num (TyFun TYPE TYPE)) tva)
(TyFun
tva
(TyFun
tva
tva
)
)
)
)
-- | We often end up in the situation of having to compare some value of type a1
-- to an instance of type Integer. This function, in order:
-- (1) Converts the value of type Integer to the type a1, if a1 is an instance
-- of Num.
-- (2) Converts the value of type a1 to Integer, if a1 is not an instance of Num
-- but is a value of type Integral
-- (3) Fails with an error.
correctTypes :: DictMaps -> BoundTypes -> Maybe Type -> Ref.Expr -> Ref.Expr -> LHStateM (Expr, Expr)
correctTypes m bt mt re re' = do
fIntgr <- lhFromIntegerM
tIntgr <- lhToIntegerM
tyI <- tyIntegerT
e <- convertLHExpr m bt mt re
e' <- convertLHExpr m bt mt re'
let t = typeOf e
let t' = typeOf e'
let retT = returnType e
let retT' = returnType e'
may_nDict <- maybeNumDict m retT
may_nDict' <- maybeNumDict m retT'
may_iDict <- maybeIntegralDict m retT
may_iDict' <- maybeIntegralDict m retT'
may_fDict <- maybeFractionalDict m retT
may_fDict' <- maybeFractionalDict m retT'
may_ratio_e <- maybeRatioFromInteger m e
may_ratio_e' <- maybeRatioFromInteger m e'
fromRationalF <- lhFromRationalM
if | t == t' -> return (e, e')
| retT /= tyI
, retT' == tyI
, Just nDict <- may_nDict -> return (e, mkApp [Var fIntgr, Type t, nDict, e'])
| retT == tyI
, retT' /= tyI
, Just nDict' <- may_nDict' -> return (mkApp [Var fIntgr, Type t', nDict', e], e')
| retT /= tyI
, retT' == tyI
, Just iDict <- may_iDict -> return (mkApp [Var tIntgr, Type t, iDict, e], e')
| retT == tyI
, retT' /= tyI
, Just iDict' <- may_iDict' -> return (e, mkApp [Var tIntgr, Type t', iDict', e'])
| Just ratio_e <- may_ratio_e
, Just fDict' <- may_fDict' -> return (mkApp [Var fromRationalF, Type t', fDict', ratio_e], e')
| Just fDict <- may_fDict
, Just ratio_e' <- may_ratio_e' -> return (e, mkApp [Var fromRationalF, Type t, fDict, ratio_e'])
| Just iDict <- may_iDict
, Just nDict' <- may_nDict' ->
return (mkApp [Var fIntgr, Type t', nDict', mkApp [Var tIntgr, Type t, iDict, e]], e')
| Just nDict <- may_nDict
, Just iDict' <- may_iDict' ->
return (e, mkApp [Var fIntgr, Type t, nDict, mkApp [Var tIntgr, Type t', iDict', e']])
| otherwise -> error $ "correctTypes: Unhandled case"
++ "\ne = " ++ show e
++ "\ne' = " ++ show e'
++ "\nt = " ++ show t
++ "\nt' = " ++ show t'
++ "\nretT = " ++ show retT
++ "\nretT' = " ++ show retT'
++ "\nm = " ++ show m
correctType :: DictMaps -> Type -> Expr -> LHStateM Expr
correctType m t e = do
fIntgr <- lhFromIntegerM
tyI <- tyIntegerT
let t' = typeOf e
may_nDict <- maybeNumDict m t
if | t == t' -> return e
| t' == tyI
, t /= tyI
, Just nDict <- may_nDict -> return $ mkApp [Var fIntgr, Type t, nDict, e]
| otherwise -> error $ "correctType: unhandled case\n" ++ show e ++ "\nmay_nDict" ++ show may_nDict
maybeRatioFromInteger :: DictMaps -> Expr -> LHStateM (Maybe Expr)
maybeRatioFromInteger m e = do
tyI <- tyIntegerT
toRatioF <- lhToRatioFuncM -- return . mkToRatioExpr =<< knownValues
may_iDict <- maybeIntegralDict m (typeOf e)
dcIntegerE <- mkDCIntegerE
if | Just iDict <- may_iDict
, typeOf e == tyI ->
return . Just $ mkApp [Var toRatioF, Type (typeOf e), iDict, e, App dcIntegerE (Lit (LitInt 1))]
| otherwise -> return Nothing
convertSymbolT :: Symbol -> Type -> Id
convertSymbolT s = Id (symbolName s)
reftSymbol :: Reft -> Symbol
reftSymbol = fst . unpackReft
reftExpr :: Reft -> Ref.Expr
reftExpr = snd . unpackReft
unpackReft :: Reft -> (Symbol, Ref.Expr)
unpackReft = coerce
-- If possible, we split symbols at the last "." not in parenthesis, to
-- correctly set module names
symbolName :: Symbol -> Name
symbolName s =
let
t = symbolSafeText s
l = case T.null t of
True -> Just $ T.last t
False -> Nothing
((m, n), i) =
case l of
Just ')' -> (T.breakOnEnd ".(" t, 2)
_ -> (T.breakOnEnd "." t, 1)
m' = T.dropEnd i m
in
case (m', n) of
(n', "") -> Name n' Nothing 0 Nothing
_ -> Name n (Just m') 0 Nothing
convertEVar :: Name -> BoundTypes -> Maybe Type -> LHStateM Expr
convertEVar nm@(Name n md _ _) bt mt
| Just t <- HM.lookup nm bt = return $ Var (Id nm t)
| otherwise = do
meas <- measuresM
tenv <- typeEnv
if | Just (n', e) <- E.lookupNameMod n md meas ->
return . Var $ Id n' (typeOf e)
| Just dc <- getDataConNameMod' tenv nm -> return $ Data dc
| Just t <- mt -> return $ Var (Id nm t)
| otherwise -> error $ "convertEVar: Required type not found" ++ "\n" ++ show n ++ "\nbt = " ++ show bt
where
getDataConNameMod' tenv n = find (flip dataConHasNameMod n) $ concatMap dataCon $ HM.elems tenv
dataConHasNameMod (DataCon (Name n m _ _) _) (Name n' m' _ _) = n == n' && m == m'
convertCon :: Maybe Type -> Constant -> LHStateM Expr
convertCon (Just (TyCon n _)) (Ref.I i) = do
tyI <- tyIntT
case tyI of
TyCon ti _ -> do
dc <- mkDCIntE
if n == ti
then return $ App dc (Lit . LitInt $ fromIntegral i)
else error $ "Unknown Con" ++ show n
_ -> error "convertCon: Non-tyInt"
convertCon _ (Ref.I i) = do
dc <- mkDCIntegerE
return $ App dc (Lit . LitInt $ fromIntegral i)
convertCon _ (Ref.R d) = do
dc <- mkDCDoubleE
return $ App dc (Lit . LitDouble $ toRational d)
convertCon _ _ = error "convertCon: Unhandled case"
unsafeSpecTypeToType :: SpecType -> LHStateM Type
unsafeSpecTypeToType st = do
t' <- specTypeToType st
case t' of
Just t'' -> return t''
Nothing -> error $ "Unhandled SpecType" ++ show st
specTypeToType :: SpecType -> LHStateM (Maybe Type)
specTypeToType (RVar {rt_var = (RTV v)}) = do
let i = mkIdUnsafe v
return $ Just (TyVar i)
specTypeToType (RFun {rt_in = fin, rt_out = fout}) = do
t <- specTypeToType fin
t2 <- specTypeToType fout
case (t, t2) of
(Just t', Just t2') -> return $ Just (TyFun t' t2')
_ -> return Nothing
specTypeToType (RAllT {rt_tvbind = RTVar (RTV v) _, rt_ty = rty}) = do
let i = mkIdUnsafe v
t <- specTypeToType rty
return $ fmap (TyForAll i) t
specTypeToType (RApp {rt_tycon = c, rt_args = as}) = rTyConType c as
specTypeToType (RAppTy {rt_arg = arg, rt_res = res}) = do
argT <- specTypeToType arg
resT <- specTypeToType res
case (argT, resT) of
(Just argT', Just resT') -> return $ Just (TyApp argT' resT')
_ -> return Nothing
specTypeToType rty = error $ "Unmatched pattern in specTypeToType " ++ show (pprint rty)
rTyConType :: RTyCon -> [SpecType]-> LHStateM (Maybe Type)
rTyConType rtc sts = do
tenv <- typeEnv
let tcn = mkTyConNameUnsafe . rtc_tc $ rtc
n = nameModMatch tcn tenv
ts <- mapM specTypeToType sts
case (not . any isNothing $ ts) of
True -> case fmap (\n' -> mkFullAppedTyCon n' (catMaybes ts) TYPE) n of
Nothing -> return $ primType tcn
t -> return t
False -> return Nothing
primType :: Name -> Maybe Type
primType (Name "Int#" _ _ _) = Just TyLitInt
primType (Name "Float#" _ _ _) = Just TyLitFloat
primType (Name "Double#" _ _ _) = Just TyLitDouble
primType (Name "Word#" _ _ _) = Just TyLitInt
primType _ = Nothing
sortToType :: Sort -> LHStateM Type
sortToType FInt = tyIntT
sortToType FReal = tyDoubleT
sortToType _ = error "Unhandled sort"
convertBrel :: Brel -> LHStateM Expr
convertBrel Ref.Eq = convertBrel' lhEqM
convertBrel Ref.Ueq = convertBrel' lhEqM
convertBrel Ref.Ne = convertBrel' lhNeM
convertBrel Ref.Gt = return . Var =<< lhGtE
convertBrel Ref.Ge = return . Var =<< lhGeE
convertBrel Ref.Lt = return . Var =<< lhLtE
convertBrel Ref.Le = return . Var =<< lhLeE
convertBrel _ = error "convertBrel: Unhandled brel"
convertBrel' :: LHStateM Name -> LHStateM Expr
convertBrel' f = do
n <- f
a <- freshIdN TYPE
lh <- lhTCM
b <- tyBoolT
let tva = TyVar a
t = TyForAll
a
(TyFun
(TyCon lh (TyFun TYPE TYPE))
(TyFun
tva
(TyFun tva b)
)
)
return $ Var $ Id n t
brelTCDict :: DictMaps -> Type -> LHStateM Expr
brelTCDict = lhTCDict
bopTCDict :: Bop -> DictMaps -> Type -> LHStateM Expr
bopTCDict Ref.Mod dm t = integralDict dm t
bopTCDict Ref.Div dm t = do
fd <- maybeFractionalDict dm t
case fd of
Just fd' -> return fd'
Nothing -> integralDict dm t
bopTCDict Ref.RDiv dm t = do
fd <- maybeFractionalDict dm t
case fd of
Just fd' -> return fd'
Nothing -> integralDict dm t
bopTCDict _ dm t = numDict dm t
lhTCDict :: DictMaps -> Type -> LHStateM Expr
lhTCDict m t = do
lh <- lhTCM
tc <- typeClassInstTC (lh_dicts m) lh t
case tc of
Just e -> return e
Nothing -> error $ "No lh dict " ++ show lh ++ "\n" ++ show t ++ "\n" ++ show m
lhTCDict' :: LHDictMap -> Type -> LHStateM Expr
lhTCDict' m t = do
lh <- lhTCM
tc <- typeClassInstTC m lh t
case tc of
Just e -> return e
Nothing -> error $ "No lh dict " ++ show lh ++ "\n" ++ show t ++ "\n" ++ show m
maybeOrdDict :: DictMaps -> Type -> LHStateM (Maybe Expr)
maybeOrdDict m t = do
ordTC <- lhOrdTCM
tc <- typeClassInstTC (ord_dicts m) ordTC t
case tc of
Just _ -> return tc
Nothing -> do
ord <- lhOrdM
lh <- lhTCDict m t
return . Just $ App (App (Var (Id ord TyUnknown)) (Type t)) lh
ordDict :: DictMaps -> Type -> LHStateM Expr
ordDict m t = do
tc <- maybeOrdDict m t
case tc of
Just e -> return e
Nothing -> error $ "No ord dict \n" ++ show t ++ "\n" ++ show m
maybeNumDict :: DictMaps -> Type -> LHStateM (Maybe Expr)
maybeNumDict m t = do
num <- lhNumTCM
typeClassInstTC (num_dicts m) num t
numDict :: DictMaps -> Type -> LHStateM Expr
numDict m t = do
tc <- maybeNumDict m t
case tc of
Just e -> return e
Nothing -> error $ "No num dict \n" ++ show t ++ "\n" ++ show m
maybeIntegralDict :: DictMaps -> Type -> LHStateM (Maybe Expr)
maybeIntegralDict m t = do
integral <- return . KV.integralTC =<< knownValues
typeClassInstTC (integral_dicts m) integral t
integralDict :: DictMaps -> Type -> LHStateM Expr
integralDict m t = do
tc <- maybeIntegralDict m t
case tc of
Just e -> return e
Nothing -> error $ "No integral dict\n" ++ show t ++ "\n" ++ show m
maybeFractionalDict :: DictMaps -> Type -> LHStateM (Maybe Expr)
maybeFractionalDict m t = do
integral <- return . KV.fractionalTC =<< knownValues
typeClassInstTC (fractional_dicts m) integral t