module Intensional.Guard where
import qualified GhcPlugins as GHC
import Binary
import Data.Map (Map)
import Data.Set (Set)
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.IntSet as IntSet
import qualified Data.IntMap as IntMap
import Intensional.Types
import Intensional.Constructors
-- data Named a = Named {toPair :: (GHC.Name, a)}
-- deriving (Eq, Functor)
-- instance Semigroup a => Semigroup (Named a) where
-- Named (n, ks1) <> Named (_, ks2) = Named (n, ks1 <> ks2)
-- instance GHC.Uniquable (Named a) where
-- getUnique (Named (n, _)) = GHC.getUnique n
-- instance Binary a => Binary (Named a) where
-- put_ bh = put_ bh . toPair
-- get bh = Named <$> Binary.get bh
-- A set of simple inclusion constraints, i.e. k in X(d), grouped by X(d)
newtype Guard
= Guard
{
groups :: Map (RVar, GHC.Name) (GHC.UniqSet GHC.Name)
}
deriving (Eq)
instance Semigroup Guard where
Guard g <> Guard g' = Guard (Map.unionWith GHC.unionUniqSets g g')
instance Monoid Guard where
mempty = Guard mempty
instance GHC.Outputable Guard where
ppr = prpr GHC.ppr
isEmpty :: Guard -> Bool
isEmpty (Guard g) = Map.null g
toList :: Guard -> [(Int, GHC.Name, GHC.Name)]
toList (Guard g) =
[ (x, d, k) | ((x,d), ks) <- Map.toList g, k <- GHC.nonDetEltsUniqSet ks ]
fromList :: [(Int, GHC.Name, GHC.Name)] -> Guard
fromList = foldMap (\(x, d, k) -> singleton [k] x d)
typedVars :: Guard -> Set (RVar, GHC.Name)
typedVars (Guard g) = Map.keysSet g
instance Binary Guard where
put_ bh = put_ bh . toList
get bh = fromList <$> get bh
instance Refined Guard where
domain (Guard g) =
Set.foldl' (\acc (x,_) -> IntSet.insert x acc) mempty (Map.keysSet g)
rename x y (Guard g) =
Guard (Map.foldrWithKey (\(z,d) ks m -> Map.insertWith GHC.unionUniqSets (if z == x then y else z, d) ks m) mempty g)
prpr m (Guard g) = GHC.pprWithCommas pprGuardAtom guardList
where
pprGuardAtom ((x,d), ks) = GHC.hsep [GHC.ppr ks, GHC.text "in", prpr m (Dom (Inj x d))]
guardList = fmap (\(x,y) -> (x, GHC.nonDetEltsUniqSet y)) (Map.toList g)
lookup :: RVar -> GHC.Name -> Guard -> Maybe (GHC.UniqSet GHC.Name)
lookup x d (Guard g) = Map.lookup (x,d) g
delete :: GHC.Name -> RVar -> GHC.Name -> Guard -> Guard
delete k x d (Guard g) = Guard (Map.alter del (x,d) g)
where
del Nothing = Nothing
del (Just ks) =
let ks' = GHC.delOneFromUniqSet ks k
in if GHC.isEmptyUniqSet ks' then Nothing else Just ks'
deleteAll :: [GHC.Name] -> RVar -> GHC.Name -> Guard -> Guard
deleteAll ms x d (Guard g) = Guard (Map.alter del (x,d) g)
where
del Nothing = Nothing
del (Just ks) =
let ks' = GHC.delListFromUniqSet ks ms
in if GHC.isEmptyUniqSet ks' then Nothing else Just ks'
-- A guard literal
-- Ignorning possibly trivial guards (e.g. 1-constructor types has already
-- happened in InferM.branch)
singleton :: [GHC.Name] -> RVar -> GHC.Name -> Guard
singleton ks x d =
Guard (Map.singleton (x, d) (GHC.addListToUniqSet mempty ks))
-- guardsFromList :: [GHC.Name] -> DataType GHC.Name -> Guard
-- guardsFromList ks (Inj x d) = foldr (\k gs -> singleton k (Inj x d) <> gs) mempty ks
impliedBy :: Guard -> Guard -> Bool
impliedBy (Guard g) (Guard g') =
Map.isSubmapOfBy keyInclusion g' g
where
keyInclusion u1 u2 =
{-# SCC keyInclusion #-}
IntMap.isSubmapOfBy (\_ _ -> True) (GHC.ufmToIntMap $ GHC.getUniqSet u1) (GHC.ufmToIntMap $ GHC.getUniqSet u2)