module Language.Haskell.Liquid.Constraint.Types
(
CG
, CGInfo (..)
, CGEnv (..)
, LConstraint (..)
, FEnv (..)
, initFEnv
, insertsFEnv
, HEnv
, fromListHEnv
, elemHEnv
, SubC (..)
, FixSubC
, subVar
, WfC (..)
, FixWfC
, RTyConInv
, mkRTyConInv
, addRTyConInv
, addRInv
, RTyConIAl
, mkRTyConIAl
, removeInvariant, restoreInvariant, makeRecInvariants
, addArgument, addArguments
) where
import Prelude hiding (error)
import CoreSyn
import Type (TyThing( AnId ))
import Var
import SrcLoc
import Unify (tcUnifyTy)
import qualified TyCon as TC
import qualified DataCon as DC
import Text.PrettyPrint.HughesPJ hiding (first)
import qualified Data.HashMap.Strict as M
import qualified Data.HashSet as S
import qualified Data.List as L
import Control.DeepSeq
import Data.Maybe (catMaybes, isJust)
import Control.Monad.State
import Language.Haskell.Liquid.GHC.SpanStack
import Language.Haskell.Liquid.Types hiding (binds)
import Language.Haskell.Liquid.Types.Strata
import Language.Haskell.Liquid.Misc (fourth4)
import Language.Haskell.Liquid.Types.RefType (shiftVV, toType)
import Language.Haskell.Liquid.WiredIn (wiredSortedSyms)
import qualified Language.Fixpoint.Types as F
import Language.Fixpoint.Misc
import qualified Language.Haskell.Liquid.UX.CTags as Tg
type CG = State CGInfo
data CGEnv = CGE
{ cgLoc :: !SpanStack
, renv :: !REnv
, syenv :: !(F.SEnv Var)
, denv :: !RDEnv
, litEnv :: !(F.SEnv F.Sort)
, constEnv :: !(F.SEnv F.Sort)
, fenv :: !FEnv
, recs :: !(S.HashSet Var)
, fargs :: !(S.HashSet Var)
, invs :: !RTyConInv
, rinvs :: !RTyConInv
, ial :: !RTyConIAl
, grtys :: !REnv
, assms :: !REnv
, intys :: !REnv
, emb :: F.TCEmb TC.TyCon
, tgEnv :: !Tg.TagEnv
, tgKey :: !(Maybe Tg.TagKey)
, trec :: !(Maybe (M.HashMap F.Symbol SpecType))
, lcb :: !(M.HashMap F.Symbol CoreExpr)
, holes :: !HEnv
, lcs :: !LConstraint
, aenv :: !(M.HashMap Var F.Symbol)
, cerr :: !(Maybe (TError SpecType))
, cgInfo :: !GhcInfo
, cgVar :: !(Maybe Var)
}
instance HasConfig CGEnv where
getConfig = getConfig . cgInfo
data LConstraint = LC [[(F.Symbol, SpecType)]]
instance Monoid LConstraint where
mempty = LC []
mappend (LC cs1) (LC cs2) = LC (cs1 ++ cs2)
instance PPrint CGEnv where
pprintTidy k = pprintTidy k . renv
instance Show CGEnv where
show = showpp
data SubC = SubC { senv :: !CGEnv
, lhs :: !SpecType
, rhs :: !SpecType
}
| SubR { senv :: !CGEnv
, oblig :: !Oblig
, ref :: !RReft
}
data WfC = WfC !CGEnv !SpecType
type FixSubC = F.SubC Cinfo
type FixWfC = F.WfC Cinfo
subVar :: FixSubC -> Maybe Var
subVar = ci_var . F.sinfo
instance PPrint SubC where
pprintTidy k c@(SubC {}) = pprintTidy k (senv c)
$+$ ("||-" <+> vcat [ pprintTidy k (lhs c)
, "<:"
, pprintTidy k (rhs c) ] )
pprintTidy k c@(SubR {}) = pprintTidy k (senv c)
$+$ ("||-" <+> vcat [ pprintTidy k (ref c)
, parens (pprintTidy k (oblig c))])
instance PPrint WfC where
pprintTidy k (WfC _ r) = "<...> |-" <+> pprintTidy k r
instance SubStratum SubC where
subS su (SubC γ t1 t2) = SubC γ (subS su t1) (subS su t2)
subS _ c = c
data CGInfo = CGInfo {
fEnv :: !(F.SEnv F.Sort)
, hsCs :: ![SubC]
, hsWfs :: ![WfC]
, sCs :: ![SubC]
, fixCs :: ![FixSubC]
, isBind :: ![Bool]
, fixWfs :: ![FixWfC]
, freshIndex :: !Integer
, binds :: !F.BindEnv
, annotMap :: !(AnnInfo (Annot SpecType))
, tyConInfo :: !(M.HashMap TC.TyCon RTyCon)
, specDecr :: ![(Var, [Int])]
, newTyEnv :: !(M.HashMap TC.TyCon SpecType)
, termExprs :: !(M.HashMap Var [F.Located F.Expr])
, specLVars :: !(S.HashSet Var)
, specLazy :: !(S.HashSet Var)
, autoSize :: !(S.HashSet TC.TyCon)
, tyConEmbed :: !(F.TCEmb TC.TyCon)
, kuts :: !F.Kuts
, kvPacks :: ![S.HashSet F.KVar]
, cgLits :: !(F.SEnv F.Sort)
, cgConsts :: !(F.SEnv F.Sort)
, cgADTs :: ![F.DataDecl]
, tcheck :: !Bool
, scheck :: !Bool
, pruneRefs :: !Bool
, logErrors :: ![Error]
, kvProf :: !KVProf
, recCount :: !Int
, bindSpans :: M.HashMap F.BindId SrcSpan
, allowHO :: !Bool
, ghcI :: !GhcInfo
, dataConTys :: ![(Var, SpecType)]
}
instance PPrint CGInfo where
pprintTidy = pprCGInfo
pprCGInfo :: F.Tidy -> CGInfo -> Doc
pprCGInfo _k _cgi
= "*********** Constraint Information (omitted) *************"
newtype HEnv = HEnv (S.HashSet F.Symbol)
fromListHEnv :: [F.Symbol] -> HEnv
fromListHEnv = HEnv . S.fromList
elemHEnv :: F.Symbol -> HEnv -> Bool
elemHEnv x (HEnv s) = x `S.member` s
data RInv = RInv { _rinv_args :: [RSort]
, _rinv_type :: SpecType
, _rinv_name :: Maybe Var
} deriving Show
type RTyConInv = M.HashMap RTyCon [RInv]
type RTyConIAl = M.HashMap RTyCon [RInv]
addArgument :: CGEnv -> Var -> CGEnv
addArgument γ v
| higherOrderFlag γ
= γ {fargs = S.insert v (fargs γ) }
| otherwise
= γ
addArguments :: CGEnv -> [Var] -> CGEnv
addArguments γ vs
| higherOrderFlag γ
= foldl addArgument γ vs
| otherwise
= γ
mkRTyConInv :: [(Maybe Var, F.Located SpecType)] -> RTyConInv
mkRTyConInv ts = group [ (c, RInv (go ts) t v) | (v, t@(RApp c ts _ _)) <- strip <$> ts]
where
strip = mapSnd (fourth4 . bkUniv . val)
go ts | generic (toRSort <$> ts) = []
| otherwise = toRSort <$> ts
generic ts = let ts' = L.nub ts in
all isRVar ts' && length ts' == length ts
mkRTyConIAl :: [(a, F.Located SpecType)] -> RTyConInv
mkRTyConIAl = mkRTyConInv . fmap ((Nothing,) . snd)
addRTyConInv :: RTyConInv -> SpecType -> SpecType
addRTyConInv m t
= case lookupRInv t m of
Nothing -> t
Just ts -> L.foldl' conjoinInvariantShift t ts
lookupRInv :: SpecType -> RTyConInv -> Maybe [SpecType]
lookupRInv (RApp c ts _ _) m
= case M.lookup c m of
Nothing -> Nothing
Just invs -> Just (catMaybes $ goodInvs ts <$> invs)
lookupRInv _ _
= Nothing
goodInvs :: [SpecType] -> RInv -> Maybe SpecType
goodInvs _ (RInv [] t _)
= Just t
goodInvs ts (RInv ts' t _)
| and (zipWith unifiable ts' (toRSort <$> ts))
= Just t
| otherwise
= Nothing
unifiable :: RSort -> RSort -> Bool
unifiable t1 t2 = isJust $ tcUnifyTy (toType t1) (toType t2)
addRInv :: RTyConInv -> (Var, SpecType) -> (Var, SpecType)
addRInv m (x, t)
| x `elem` ids , Just invs <- lookupRInv (res t) m
= (x, addInvCond t (mconcat $ catMaybes (stripRTypeBase <$> invs)))
| otherwise
= (x, t)
where
ids = [id | tc <- M.keys m
, dc <- TC.tyConDataCons $ rtc_tc tc
, AnId id <- DC.dataConImplicitTyThings dc]
res = ty_res . toRTypeRep
conjoinInvariantShift :: SpecType -> SpecType -> SpecType
conjoinInvariantShift t1 t2
= conjoinInvariant t1 (shiftVV t2 (rTypeValueVar t1))
conjoinInvariant :: SpecType -> SpecType -> SpecType
conjoinInvariant (RApp c ts rs r) (RApp ic its _ ir)
| c == ic && length ts == length its
= RApp c (zipWith conjoinInvariantShift ts its) rs (r `F.meet` ir)
conjoinInvariant t@(RApp _ _ _ r) (RVar _ ir)
= t { rt_reft = r `F.meet` ir }
conjoinInvariant t@(RVar _ r) (RVar _ ir)
= t { rt_reft = r `F.meet` ir }
conjoinInvariant t _
= t
removeInvariant :: CGEnv -> CoreBind -> (CGEnv, RTyConInv)
removeInvariant γ cbs
= (γ { invs = M.map (filter f) (invs γ)
, rinvs = M.map (filter (not . f)) (invs γ)}
, invs γ)
where
f i | Just v <- _rinv_name i, v `elem` binds cbs
= False
| otherwise
= True
binds (NonRec x _) = [x]
binds (Rec xes) = fst $ unzip xes
restoreInvariant :: CGEnv -> RTyConInv -> CGEnv
restoreInvariant γ is = γ {invs = is}
makeRecInvariants :: CGEnv -> [Var] -> CGEnv
makeRecInvariants γ [x] = γ {invs = M.unionWith (++) (invs γ) is}
where
is = M.map (map f . filter (isJust . (varType x `tcUnifyTy`) . toType . _rinv_type)) (rinvs γ)
f i = i{_rinv_type = guard $ _rinv_type i}
guard (RApp c ts rs r)
| Just f <- szFun <$> sizeFunction (rtc_info c)
= RApp c ts rs (MkUReft (ref f $ F.toReft r) mempty mempty)
| otherwise
= RApp c ts rs mempty
guard t
= t
ref f (F.Reft(v, rr))
= F.Reft (v, F.PImp (F.PAtom F.Lt (f v) (f $ F.symbol x)) rr)
makeRecInvariants γ _ = γ
data FEnv = FE
{ feBinds :: !F.IBindEnv
, feEnv :: !(F.SEnv F.Sort)
, feIdEnv :: !(F.SEnv F.BindId)
}
insertFEnv :: FEnv -> ((F.Symbol, F.Sort), F.BindId) -> FEnv
insertFEnv (FE benv env ienv) ((x, t), i)
= FE (F.insertsIBindEnv [i] benv)
(F.insertSEnv x t env)
(F.insertSEnv x i ienv)
insertsFEnv :: FEnv -> [((F.Symbol, F.Sort), F.BindId)] -> FEnv
insertsFEnv = L.foldl' insertFEnv
initFEnv :: [(F.Symbol, F.Sort)] -> FEnv
initFEnv xts = FE benv0 env0 ienv0
where
benv0 = F.emptyIBindEnv
env0 = F.fromListSEnv (wiredSortedSyms ++ xts)
ienv0 = F.emptySEnv
instance NFData RInv where
rnf (RInv x y z) = rnf x `seq` rnf y `seq` rnf z
instance NFData CGEnv where
rnf (CGE x1 _ x3 _ x4 x5 x55 x6 x7 x8 x9 _ _ _ x10 _ _ _ _ _ _ _ _ _ _ _)
= x1 `seq` seq x3
`seq` rnf x5
`seq` rnf x55
`seq` rnf x6
`seq` x7
`seq` rnf x8
`seq` rnf x9
`seq` rnf x10
`seq` rnf x4
instance NFData FEnv where
rnf (FE x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3
instance NFData SubC where
rnf (SubC x1 x2 x3)
= rnf x1 `seq` rnf x2 `seq` rnf x3
rnf (SubR x1 _ x2)
= rnf x1 `seq` rnf x2
instance NFData WfC where
rnf (WfC x1 x2)
= rnf x1 `seq` rnf x2
instance NFData CGInfo where
rnf x = ( rnf (hsCs x)) `seq`
( rnf (hsWfs x)) `seq`
( rnf (fixCs x)) `seq`
( rnf (fixWfs x)) `seq`
( rnf (freshIndex x)) `seq`
( rnf (binds x)) `seq`
( rnf (annotMap x)) `seq`
( rnf (kuts x)) `seq`
( rnf (kvPacks x)) `seq`
( rnf (cgLits x)) `seq`
( rnf (cgConsts x)) `seq`
( rnf (kvProf x))