diff options
Diffstat (limited to 'compiler/GHC/Unit/Home.hs')
-rw-r--r-- | compiler/GHC/Unit/Home.hs | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/compiler/GHC/Unit/Home.hs b/compiler/GHC/Unit/Home.hs new file mode 100644 index 0000000000..eceebd81d0 --- /dev/null +++ b/compiler/GHC/Unit/Home.hs @@ -0,0 +1,213 @@ +-- | 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 + , notHomeModule + , notHomeModuleMaybe + , notHomeInstalledModule + , notHomeInstalledModuleMaybe + -- * Helpers + , mkHomeModule + , mkHomeInstalledModule + , homeModuleInstantiation + , homeModuleNameInstantiation + ) +where + +import GHC.Prelude +import GHC.Unit.Types +import GHC.Unit.Module.Name +import Data.Maybe + +-- | 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 and wiring of home unit +-- instantiations is done inplace in DynFlags by +-- GHC.Unit.State.upd_wired_in_home_instantiations. +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 (Indefinite u Nothing) 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 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 :: HomeUnit -> Module -> Module +homeModuleInstantiation hu mod + | isHomeModule hu mod = homeModuleNameInstantiation hu (moduleName mod) + | otherwise = mod + |