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
|
-- | The home unit is the unit (i.e. compiled package) that contains the module
-- we are compiling/typechecking.
module GHC.Unit.Home
( GenHomeUnit (..)
, HomeUnit
, homeUnitId
, homeUnitInstantiations
, homeUnitInstanceOf
, homeUnitInstanceOfMaybe
, homeUnitAsUnit
, homeUnitMap
-- * Predicates
, isHomeUnitIndefinite
, isHomeUnitDefinite
, isHomeUnitInstantiating
, isHomeUnit
, isHomeUnitId
, isHomeUnitInstanceOf
, isHomeModule
, isHomeInstalledModule
, notHomeUnitId
, notHomeModule
, notHomeModuleMaybe
, notHomeInstalledModule
, notHomeInstalledModuleMaybe
-- * Helpers
, mkHomeModule
, mkHomeInstalledModule
, homeModuleInstantiation
, homeModuleNameInstantiation
)
where
import GHC.Prelude
import GHC.Unit.Types
import Data.Maybe
import Language.Haskell.Syntax.Module.Name
-- | Information about the home unit (i.e., the until that will contain the
-- modules we are compiling)
--
-- The unit identifier of the instantiating units is left open to allow
-- switching from UnitKey (what is provided by the user) to UnitId (internal
-- unit identifier) with `homeUnitMap`.
--
-- TODO: this isn't implemented yet. UnitKeys are still converted too early into
-- UnitIds in GHC.Unit.State.readUnitDataBase
data GenHomeUnit u
= DefiniteHomeUnit UnitId (Maybe (u, GenInstantiations u))
-- ^ Definite home unit (i.e. that we can compile).
--
-- Nothing: not an instantiated unit
-- Just (i,insts): made definite by instantiating "i" with "insts"
| IndefiniteHomeUnit UnitId (GenInstantiations u)
-- ^ Indefinite home unit (i.e. that we can only typecheck)
--
-- All the holes are instantiated with fake modules from the Hole unit.
-- See Note [Representation of module/name variables] in "GHC.Unit"
type HomeUnit = GenHomeUnit UnitId
-- | Return home unit id
homeUnitId :: GenHomeUnit u -> UnitId
homeUnitId (DefiniteHomeUnit u _) = u
homeUnitId (IndefiniteHomeUnit u _) = u
-- | Return home unit instantiations
homeUnitInstantiations :: GenHomeUnit u -> GenInstantiations u
homeUnitInstantiations (DefiniteHomeUnit _ Nothing) = []
homeUnitInstantiations (DefiniteHomeUnit _ (Just (_,is))) = is
homeUnitInstantiations (IndefiniteHomeUnit _ is) = is
-- | Return the unit id of the unit that is instantiated by the home unit.
--
-- E.g. if home unit = q[A=p:B,...] we return q.
--
-- If the home unit is not an instance of another unit, we return its own unit
-- id (it is an instance of itself if you will).
homeUnitInstanceOf :: HomeUnit -> UnitId
homeUnitInstanceOf h = fromMaybe (homeUnitId h) (homeUnitInstanceOfMaybe h)
-- | Return the unit id of the unit that is instantiated by the home unit.
--
-- E.g. if home unit = q[A=p:B,...] we return (Just q).
--
-- If the home unit is not an instance of another unit, we return Nothing.
homeUnitInstanceOfMaybe :: GenHomeUnit u -> Maybe u
homeUnitInstanceOfMaybe (DefiniteHomeUnit _ (Just (u,_))) = Just u
homeUnitInstanceOfMaybe _ = Nothing
-- | Return the home unit as a normal unit.
--
-- We infer from the home unit itself the kind of unit we create:
-- 1. If the home unit is definite, we must be compiling so we return a real
-- unit. The definite home unit may be the result of a unit instantiation,
-- say `p = q[A=r:X]`. In this case we could have returned a virtual unit
-- `q[A=r:X]` but it's not what the clients of this function expect,
-- especially because `p` is lost when we do this. The unit id of a virtual
-- unit is made up internally so `unitId(q[A=r:X])` is not equal to `p`.
--
-- 2. If the home unit is indefinite we can only create a virtual unit from
-- it. It's ok because we must be only typechecking the home unit so we won't
-- produce any code object that rely on the unit id of this virtual unit.
homeUnitAsUnit :: HomeUnit -> Unit
homeUnitAsUnit (DefiniteHomeUnit u _) = RealUnit (Definite u)
homeUnitAsUnit (IndefiniteHomeUnit u is) = mkVirtUnit u is
-- | Map over the unit identifier for instantiating units
homeUnitMap :: IsUnitId v => (u -> v) -> GenHomeUnit u -> GenHomeUnit v
homeUnitMap _ (DefiniteHomeUnit u Nothing) = DefiniteHomeUnit u Nothing
homeUnitMap f (DefiniteHomeUnit u (Just (i,is))) = DefiniteHomeUnit u (Just (f i, mapInstantiations f is))
homeUnitMap f (IndefiniteHomeUnit u is) = IndefiniteHomeUnit u (mapInstantiations f is)
----------------------------
-- Predicates
----------------------------
-- | Test if we are type-checking an indefinite unit
--
-- (if it is not, we should never use on-the-fly renaming)
isHomeUnitIndefinite :: GenHomeUnit u -> Bool
isHomeUnitIndefinite (DefiniteHomeUnit {}) = False
isHomeUnitIndefinite (IndefiniteHomeUnit {}) = True
-- | Test if we are compiling a definite unit
--
-- (if it is, we should never use on-the-fly renaming)
isHomeUnitDefinite :: GenHomeUnit u -> Bool
isHomeUnitDefinite (DefiniteHomeUnit {}) = True
isHomeUnitDefinite (IndefiniteHomeUnit {}) = False
-- | Test if we are compiling by instantiating a definite unit
isHomeUnitInstantiating :: GenHomeUnit u -> Bool
isHomeUnitInstantiating u =
isHomeUnitDefinite u && not (null (homeUnitInstantiations u))
-- | Test if the unit is the home unit
isHomeUnit :: HomeUnit -> Unit -> Bool
isHomeUnit hu u = u == homeUnitAsUnit hu
-- | Test if the unit-id is the home unit-id
isHomeUnitId :: GenHomeUnit u -> UnitId -> Bool
isHomeUnitId hu uid = uid == homeUnitId hu
-- | Test if the unit-id is not the home unit-id
notHomeUnitId :: Maybe (GenHomeUnit u) -> UnitId -> Bool
notHomeUnitId Nothing _ = True
notHomeUnitId (Just hu) uid = not (isHomeUnitId hu uid)
-- | Test if the home unit is an instance of the given unit-id
isHomeUnitInstanceOf :: HomeUnit -> UnitId -> Bool
isHomeUnitInstanceOf hu u = homeUnitInstanceOf hu == u
-- | Test if the module comes from the home unit
isHomeModule :: HomeUnit -> Module -> Bool
isHomeModule hu m = isHomeUnit hu (moduleUnit m)
-- | Test if the module comes from the home unit
isHomeInstalledModule :: GenHomeUnit u -> InstalledModule -> Bool
isHomeInstalledModule hu m = isHomeUnitId hu (moduleUnit m)
-- | Test if a module doesn't come from the given home unit
notHomeInstalledModule :: GenHomeUnit u -> InstalledModule -> Bool
notHomeInstalledModule hu m = not (isHomeInstalledModule hu m)
-- | Test if a module doesn't come from the given home unit
notHomeInstalledModuleMaybe :: Maybe (GenHomeUnit u) -> InstalledModule -> Bool
notHomeInstalledModuleMaybe mh m = fromMaybe True $ fmap (`notHomeInstalledModule` m) mh
-- | Test if a module doesn't come from the given home unit
notHomeModule :: HomeUnit -> Module -> Bool
notHomeModule hu m = not (isHomeModule hu m)
-- | Test if a module doesn't come from the given home unit
notHomeModuleMaybe :: Maybe HomeUnit -> Module -> Bool
notHomeModuleMaybe mh m = fromMaybe True $ fmap (`notHomeModule` m) mh
----------------------------
-- helpers
----------------------------
-- | Make a module in home unit
mkHomeModule :: HomeUnit -> ModuleName -> Module
mkHomeModule hu = mkModule (homeUnitAsUnit hu)
-- | Make a module in home unit
mkHomeInstalledModule :: GenHomeUnit u -> ModuleName -> InstalledModule
mkHomeInstalledModule hu = mkModule (homeUnitId hu)
-- | Return the module that is used to instantiate the given home module name.
-- If the ModuleName doesn't refer to a signature, return the actual home
-- module.
--
-- E.g., the instantiating module of @A@ in @p[A=q[]:B]@ is @q[]:B@.
-- the instantiating module of @A@ in @p@ is @p:A@.
homeModuleNameInstantiation :: HomeUnit -> ModuleName -> Module
homeModuleNameInstantiation hu mod_name =
case lookup mod_name (homeUnitInstantiations hu) of
Nothing -> mkHomeModule hu mod_name
Just mod -> mod
-- | Return the module that is used to instantiate the given home module.
--
-- If the given module isn't a module hole, return the actual home module.
--
-- E.g., the instantiating module of @p:A@ in @p[A=q[]:B]@ is @q[]:B@.
-- the instantiating module of @r:A@ in @p[A=q[]:B]@ is @r:A@.
-- the instantiating module of @p:A@ in @p@ is @p:A@.
-- the instantiating module of @r:A@ in @p@ is @r:A@.
homeModuleInstantiation :: Maybe HomeUnit -> Module -> Module
homeModuleInstantiation mhu mod
| Just hu <- mhu
, isHomeModule hu mod = homeModuleNameInstantiation hu (moduleName mod)
| otherwise = mod
|