summaryrefslogtreecommitdiff
path: root/compiler/GHC/Unit/Home.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Unit/Home.hs')
-rw-r--r--compiler/GHC/Unit/Home.hs213
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
+