1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
|
{-
(c) The University of Glasgow 2006
(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-}
module GHC.Types.Var.Set (
-- * Var, Id and TyVar set types
VarSet, IdSet, TyVarSet, CoVarSet, TyCoVarSet,
-- ** Manipulating these sets
emptyVarSet, unitVarSet, mkVarSet,
extendVarSet, extendVarSetList,
elemVarSet, subVarSet,
unionVarSet, unionVarSets, mapUnionVarSet,
intersectVarSet, intersectsVarSet, disjointVarSet,
isEmptyVarSet, delVarSet, delVarSetList, delVarSetByKey,
minusVarSet, filterVarSet, mapVarSet,
anyVarSet, allVarSet,
transCloVarSet, fixVarSet,
lookupVarSet_Directly, lookupVarSet, lookupVarSetByName,
sizeVarSet, seqVarSet,
elemVarSetByKey, partitionVarSet,
pluralVarSet, pprVarSet,
nonDetStrictFoldVarSet,
-- * Deterministic Var set types
DVarSet, DIdSet, DTyVarSet, DTyCoVarSet,
-- ** Manipulating these sets
emptyDVarSet, unitDVarSet, mkDVarSet,
extendDVarSet, extendDVarSetList,
elemDVarSet, dVarSetElems, subDVarSet,
unionDVarSet, unionDVarSets, mapUnionDVarSet,
intersectDVarSet, dVarSetIntersectVarSet,
intersectsDVarSet, disjointDVarSet,
isEmptyDVarSet, delDVarSet, delDVarSetList,
minusDVarSet,
nonDetStrictFoldDVarSet,
filterDVarSet, mapDVarSet,
dVarSetMinusVarSet, anyDVarSet, allDVarSet,
transCloDVarSet,
sizeDVarSet, seqDVarSet,
partitionDVarSet,
dVarSetToVarSet,
) where
import GHC.Prelude
import GHC.Types.Var ( Var, TyVar, CoVar, TyCoVar, Id )
import GHC.Types.Unique
import GHC.Types.Name ( Name )
import GHC.Types.Unique.Set
import GHC.Types.Unique.DSet
import GHC.Types.Unique.FM( disjointUFM, pluralUFM, pprUFM )
import GHC.Types.Unique.DFM( disjointUDFM, udfmToUfm, anyUDFM, allUDFM )
import GHC.Utils.Outputable (SDoc)
-- | A non-deterministic Variable Set
--
-- A non-deterministic set of variables.
-- See Note [Deterministic UniqFM] in "GHC.Types.Unique.DFM" for explanation why it's not
-- deterministic and why it matters. Use DVarSet if the set eventually
-- gets converted into a list or folded over in a way where the order
-- changes the generated code, for example when abstracting variables.
type VarSet = UniqSet Var
-- | Identifier Set
type IdSet = UniqSet Id
-- | Type Variable Set
type TyVarSet = UniqSet TyVar
-- | Coercion Variable Set
type CoVarSet = UniqSet CoVar
-- | Type or Coercion Variable Set
type TyCoVarSet = UniqSet TyCoVar
emptyVarSet :: VarSet
intersectVarSet :: VarSet -> VarSet -> VarSet
unionVarSet :: VarSet -> VarSet -> VarSet
unionVarSets :: [VarSet] -> VarSet
mapUnionVarSet :: (a -> VarSet) -> [a] -> VarSet
-- ^ map the function over the list, and union the results
unitVarSet :: Var -> VarSet
extendVarSet :: VarSet -> Var -> VarSet
extendVarSetList:: VarSet -> [Var] -> VarSet
elemVarSet :: Var -> VarSet -> Bool
delVarSet :: VarSet -> Var -> VarSet
delVarSetList :: VarSet -> [Var] -> VarSet
minusVarSet :: VarSet -> VarSet -> VarSet
isEmptyVarSet :: VarSet -> Bool
mkVarSet :: [Var] -> VarSet
lookupVarSet_Directly :: VarSet -> Unique -> Maybe Var
lookupVarSet :: VarSet -> Var -> Maybe Var
-- Returns the set element, which may be
-- (==) to the argument, but not the same as
lookupVarSetByName :: VarSet -> Name -> Maybe Var
sizeVarSet :: VarSet -> Int
filterVarSet :: (Var -> Bool) -> VarSet -> VarSet
delVarSetByKey :: VarSet -> Unique -> VarSet
elemVarSetByKey :: Unique -> VarSet -> Bool
partitionVarSet :: (Var -> Bool) -> VarSet -> (VarSet, VarSet)
emptyVarSet = emptyUniqSet
unitVarSet = unitUniqSet
extendVarSet = addOneToUniqSet
extendVarSetList= addListToUniqSet
intersectVarSet = intersectUniqSets
intersectsVarSet:: VarSet -> VarSet -> Bool -- True if non-empty intersection
disjointVarSet :: VarSet -> VarSet -> Bool -- True if empty intersection
subVarSet :: VarSet -> VarSet -> Bool -- True if first arg is subset of second
-- (s1 `intersectsVarSet` s2) doesn't compute s2 if s1 is empty;
-- ditto disjointVarSet, subVarSet
unionVarSet = unionUniqSets
unionVarSets = unionManyUniqSets
elemVarSet = elementOfUniqSet
minusVarSet = minusUniqSet
delVarSet = delOneFromUniqSet
delVarSetList = delListFromUniqSet
isEmptyVarSet = isEmptyUniqSet
mkVarSet = mkUniqSet
lookupVarSet_Directly = lookupUniqSet_Directly
lookupVarSet = lookupUniqSet
lookupVarSetByName set name = lookupUniqSet_Directly set (getUnique name)
sizeVarSet = sizeUniqSet
filterVarSet = filterUniqSet
delVarSetByKey = delOneFromUniqSet_Directly
elemVarSetByKey = elemUniqSet_Directly
partitionVarSet = partitionUniqSet
mapUnionVarSet get_set xs = foldr (unionVarSet . get_set) emptyVarSet xs
-- See comments with type signatures
intersectsVarSet s1 s2 = not (s1 `disjointVarSet` s2)
disjointVarSet s1 s2 = disjointUFM (getUniqSet s1) (getUniqSet s2)
subVarSet s1 s2 = isEmptyVarSet (s1 `minusVarSet` s2)
anyVarSet :: (Var -> Bool) -> VarSet -> Bool
anyVarSet = uniqSetAny
allVarSet :: (Var -> Bool) -> VarSet -> Bool
allVarSet = uniqSetAll
mapVarSet :: Uniquable b => (a -> b) -> UniqSet a -> UniqSet b
mapVarSet = mapUniqSet
-- See Note [Deterministic UniqFM] to learn about nondeterminism.
-- If you use this please provide a justification why it doesn't introduce
-- nondeterminism.
nonDetStrictFoldVarSet :: (Var -> a -> a) -> a -> VarSet -> a
nonDetStrictFoldVarSet = nonDetStrictFoldUniqSet
fixVarSet :: (VarSet -> VarSet) -- Map the current set to a new set
-> VarSet -> VarSet
-- (fixVarSet f s) repeatedly applies f to the set s,
-- until it reaches a fixed point.
fixVarSet fn vars
| new_vars `subVarSet` vars = vars
| otherwise = fixVarSet fn new_vars
where
new_vars = fn vars
transCloVarSet :: (VarSet -> VarSet)
-- Map some variables in the set to
-- extra variables that should be in it
-> VarSet -> VarSet
-- (transCloVarSet f s) repeatedly applies f to new candidates, adding any
-- new variables to s that it finds thereby, until it reaches a fixed point.
--
-- The function fn could be (Var -> VarSet), but we use (VarSet -> VarSet)
-- for efficiency, so that the test can be batched up.
-- It's essential that fn will work fine if given new candidates
-- one at a time; ie fn {v1,v2} = fn v1 `union` fn v2
-- Use fixVarSet if the function needs to see the whole set all at once
transCloVarSet fn seeds
= go seeds seeds
where
go :: VarSet -- Accumulating result
-> VarSet -- Work-list; un-processed subset of accumulating result
-> VarSet
-- Specification: go acc vs = acc `union` transClo fn vs
go acc candidates
| isEmptyVarSet new_vs = acc
| otherwise = go (acc `unionVarSet` new_vs) new_vs
where
new_vs = fn candidates `minusVarSet` acc
seqVarSet :: VarSet -> ()
seqVarSet s = s `seq` ()
-- | Determines the pluralisation suffix appropriate for the length of a set
-- in the same way that plural from Outputable does for lists.
pluralVarSet :: VarSet -> SDoc
pluralVarSet = pluralUFM . getUniqSet
-- | Pretty-print a non-deterministic set.
-- The order of variables is non-deterministic and for pretty-printing that
-- shouldn't be a problem.
-- Having this function helps contain the non-determinism created with
-- nonDetEltsUFM.
-- Passing a list to the pretty-printing function allows the caller
-- to decide on the order of Vars (eg. toposort them) without them having
-- to use nonDetEltsUFM at the call site. This prevents from let-binding
-- non-deterministically ordered lists and reusing them where determinism
-- matters.
pprVarSet :: VarSet -- ^ The things to be pretty printed
-> ([Var] -> SDoc) -- ^ The pretty printing function to use on the
-- elements
-> SDoc -- ^ 'SDoc' where the things have been pretty
-- printed
pprVarSet = pprUFM . getUniqSet
-- Deterministic VarSet
-- See Note [Deterministic UniqFM] in GHC.Types.Unique.DFM for explanation why we need
-- DVarSet.
-- | Deterministic Variable Set
type DVarSet = UniqDSet Var
-- | Deterministic Identifier Set
type DIdSet = UniqDSet Id
-- | Deterministic Type Variable Set
type DTyVarSet = UniqDSet TyVar
-- | Deterministic Type or Coercion Variable Set
type DTyCoVarSet = UniqDSet TyCoVar
emptyDVarSet :: DVarSet
emptyDVarSet = emptyUniqDSet
unitDVarSet :: Var -> DVarSet
unitDVarSet = unitUniqDSet
mkDVarSet :: [Var] -> DVarSet
mkDVarSet = mkUniqDSet
-- The new element always goes to the right of existing ones.
extendDVarSet :: DVarSet -> Var -> DVarSet
extendDVarSet = addOneToUniqDSet
elemDVarSet :: Var -> DVarSet -> Bool
elemDVarSet = elementOfUniqDSet
dVarSetElems :: DVarSet -> [Var]
dVarSetElems = uniqDSetToList
subDVarSet :: DVarSet -> DVarSet -> Bool
subDVarSet s1 s2 = isEmptyDVarSet (s1 `minusDVarSet` s2)
unionDVarSet :: DVarSet -> DVarSet -> DVarSet
unionDVarSet = unionUniqDSets
unionDVarSets :: [DVarSet] -> DVarSet
unionDVarSets = unionManyUniqDSets
-- | Map the function over the list, and union the results
mapUnionDVarSet :: (a -> DVarSet) -> [a] -> DVarSet
mapUnionDVarSet get_set xs = foldr (unionDVarSet . get_set) emptyDVarSet xs
intersectDVarSet :: DVarSet -> DVarSet -> DVarSet
intersectDVarSet = intersectUniqDSets
dVarSetIntersectVarSet :: DVarSet -> VarSet -> DVarSet
dVarSetIntersectVarSet = uniqDSetIntersectUniqSet
-- | True if empty intersection
disjointDVarSet :: DVarSet -> DVarSet -> Bool
disjointDVarSet s1 s2 = disjointUDFM (getUniqDSet s1) (getUniqDSet s2)
-- | True if non-empty intersection
intersectsDVarSet :: DVarSet -> DVarSet -> Bool
intersectsDVarSet s1 s2 = not (s1 `disjointDVarSet` s2)
isEmptyDVarSet :: DVarSet -> Bool
isEmptyDVarSet = isEmptyUniqDSet
delDVarSet :: DVarSet -> Var -> DVarSet
delDVarSet = delOneFromUniqDSet
minusDVarSet :: DVarSet -> DVarSet -> DVarSet
minusDVarSet = minusUniqDSet
dVarSetMinusVarSet :: DVarSet -> VarSet -> DVarSet
dVarSetMinusVarSet = uniqDSetMinusUniqSet
-- See Note [Deterministic UniqFM] to learn about nondeterminism.
-- If you use this please provide a justification why it doesn't introduce
-- nondeterminism.
nonDetStrictFoldDVarSet :: (Var -> a -> a) -> a -> DVarSet -> a
nonDetStrictFoldDVarSet = nonDetStrictFoldUniqDSet
anyDVarSet :: (Var -> Bool) -> DVarSet -> Bool
anyDVarSet p = anyUDFM p . getUniqDSet
allDVarSet :: (Var -> Bool) -> DVarSet -> Bool
allDVarSet p = allUDFM p . getUniqDSet
mapDVarSet :: Uniquable b => (a -> b) -> UniqDSet a -> UniqDSet b
mapDVarSet = mapUniqDSet
filterDVarSet :: (Var -> Bool) -> DVarSet -> DVarSet
filterDVarSet = filterUniqDSet
sizeDVarSet :: DVarSet -> Int
sizeDVarSet = sizeUniqDSet
-- | Partition DVarSet according to the predicate given
partitionDVarSet :: (Var -> Bool) -> DVarSet -> (DVarSet, DVarSet)
partitionDVarSet = partitionUniqDSet
-- | Delete a list of variables from DVarSet
delDVarSetList :: DVarSet -> [Var] -> DVarSet
delDVarSetList = delListFromUniqDSet
seqDVarSet :: DVarSet -> ()
seqDVarSet s = s `seq` ()
-- | Add a list of variables to DVarSet
extendDVarSetList :: DVarSet -> [Var] -> DVarSet
extendDVarSetList = addListToUniqDSet
-- | Convert a DVarSet to a VarSet by forgetting the order of insertion
dVarSetToVarSet :: DVarSet -> VarSet
dVarSetToVarSet = unsafeUFMToUniqSet . udfmToUfm . getUniqDSet
-- | transCloVarSet for DVarSet
transCloDVarSet :: (DVarSet -> DVarSet)
-- Map some variables in the set to
-- extra variables that should be in it
-> DVarSet -> DVarSet
-- (transCloDVarSet f s) repeatedly applies f to new candidates, adding any
-- new variables to s that it finds thereby, until it reaches a fixed point.
--
-- The function fn could be (Var -> DVarSet), but we use (DVarSet -> DVarSet)
-- for efficiency, so that the test can be batched up.
-- It's essential that fn will work fine if given new candidates
-- one at a time; ie fn {v1,v2} = fn v1 `union` fn v2
transCloDVarSet fn seeds
= go seeds seeds
where
go :: DVarSet -- Accumulating result
-> DVarSet -- Work-list; un-processed subset of accumulating result
-> DVarSet
-- Specification: go acc vs = acc `union` transClo fn vs
go acc candidates
| isEmptyDVarSet new_vs = acc
| otherwise = go (acc `unionDVarSet` new_vs) new_vs
where
new_vs = fn candidates `minusDVarSet` acc
|