    -- | Info about modules in the "home" unit
    module GHC.Unit.Home.ModInfo
       ( HomeModInfo (..)
       , HomePackageTable
       , emptyHomePackageTable
       , lookupHpt
       , eltsHpt
       , filterHpt
       , allHpt
       , anyHpt
       , mapHpt
       , delFromHpt
       , addToHpt
       , addListToHpt
       , lookupHptDirectly
       , lookupHptByModule
       , listToHpt
       , pprHPT
       )
    where

    import GHC.Prelude

    import GHC.Unit.Module.ModIface
    import GHC.Unit.Module.ModDetails
    import GHC.Unit.Module

    import GHC.Linker.Types ( Linkable(..) )

    import GHC.Types.Unique
    import GHC.Types.Unique.DFM

    import GHC.Utils.Outputable

    -- | Information about modules in the package being compiled
    data HomeModInfo = HomeModInfo
       { HomeModInfo -> ModIface
    hm_iface    :: !ModIface
            -- ^ The basic loaded interface file: every loaded module has one of
            -- these, even if it is imported from another package

       , HomeModInfo -> ModDetails
    hm_details  :: ModDetails
            -- ^ Extra information that has been created from the 'ModIface' for
            -- the module, typically during typechecking

            -- This field is LAZY because a ModDetails is constructed by knot tying.

       , HomeModInfo -> Maybe Linkable
    hm_linkable :: !(Maybe Linkable)
            -- ^ The actual artifact we would like to link to access things in
            -- this module.
            --
            -- 'hm_linkable' might be Nothing:
            --
            --   1. If this is an .hs-boot module
            --
            --   2. Temporarily during compilation if we pruned away
            --      the old linkable because it was out of date.
            --
            -- After a complete compilation ('GHC.load'), all 'hm_linkable' fields
            -- in the 'HomePackageTable' will be @Just@.
            --
            -- When re-linking a module ('GHC.Driver.Main.HscNoRecomp'), we construct the
            -- 'HomeModInfo' by building a new 'ModDetails' from the old
            -- 'ModIface' (only).
       }

    -- | Helps us find information about modules in the home package
    type HomePackageTable = DModuleNameEnv HomeModInfo
       -- Domain = modules in the home unit that have been fully compiled
       -- "home" unit id cached (implicit) here for convenience

    -- | Constructs an empty HomePackageTable
    emptyHomePackageTable :: HomePackageTable
    emptyHomePackageTable :: HomePackageTable
    emptyHomePackageTable  = forall key elt. UniqDFM key elt
    emptyUDFM

    lookupHpt :: HomePackageTable -> ModuleName -> Maybe HomeModInfo
    lookupHpt :: HomePackageTable -> ModuleName -> Maybe HomeModInfo
    lookupHpt = forall key elt.
    Uniquable key =>
    UniqDFM key elt -> key -> Maybe elt
    lookupUDFM

    lookupHptDirectly :: HomePackageTable -> Unique -> Maybe HomeModInfo
    lookupHptDirectly :: HomePackageTable -> Unique -> Maybe HomeModInfo
    lookupHptDirectly = forall key elt. UniqDFM key elt -> Unique -> Maybe elt
    lookupUDFM_Directly

    eltsHpt :: HomePackageTable -> [HomeModInfo]
    eltsHpt :: HomePackageTable -> [HomeModInfo]
    eltsHpt = forall key elt. UniqDFM key elt -> [elt]
    eltsUDFM

    filterHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> HomePackageTable
    filterHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> HomePackageTable
    filterHpt = forall elt key. (elt -> Bool) -> UniqDFM key elt -> UniqDFM key elt
    filterUDFM

    allHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> Bool
    allHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> Bool
    allHpt = forall elt key. (elt -> Bool) -> UniqDFM key elt -> Bool
    allUDFM

    anyHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> Bool
    anyHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> Bool
    anyHpt = forall elt key. (elt -> Bool) -> UniqDFM key elt -> Bool
    anyUDFM

    mapHpt :: (HomeModInfo -> HomeModInfo) -> HomePackageTable -> HomePackageTable
    mapHpt :: (HomeModInfo -> HomeModInfo)
    -> HomePackageTable -> HomePackageTable
    mapHpt = forall elt1 elt2 key.
    (elt1 -> elt2) -> UniqDFM key elt1 -> UniqDFM key elt2
    mapUDFM

    delFromHpt :: HomePackageTable -> ModuleName -> HomePackageTable
    delFromHpt :: HomePackageTable -> ModuleName -> HomePackageTable
    delFromHpt = forall key elt.
    Uniquable key =>
    UniqDFM key elt -> key -> UniqDFM key elt
    delFromUDFM

    addToHpt :: HomePackageTable -> ModuleName -> HomeModInfo -> HomePackageTable
    addToHpt :: HomePackageTable -> ModuleName -> HomeModInfo -> HomePackageTable
    addToHpt = forall key elt.
    Uniquable key =>
    UniqDFM key elt -> key -> elt -> UniqDFM key elt
    addToUDFM

    addListToHpt
      :: HomePackageTable -> [(ModuleName, HomeModInfo)] -> HomePackageTable
    addListToHpt :: HomePackageTable -> [(ModuleName, HomeModInfo)] -> HomePackageTable
    addListToHpt = forall key elt.
    Uniquable key =>
    UniqDFM key elt -> [(key, elt)] -> UniqDFM key elt
    addListToUDFM

    listToHpt :: [(ModuleName, HomeModInfo)] -> HomePackageTable
    listToHpt :: [(ModuleName, HomeModInfo)] -> HomePackageTable
    listToHpt = forall key elt. Uniquable key => [(key, elt)] -> UniqDFM key elt
    listToUDFM

    lookupHptByModule :: HomePackageTable -> Module -> Maybe HomeModInfo
    -- The HPT is indexed by ModuleName, not Module,
    -- we must check for a hit on the right Module
    lookupHptByModule :: HomePackageTable -> Module -> Maybe HomeModInfo
    lookupHptByModule HomePackageTable
    hpt Module
    mod
      = case HomePackageTable -> ModuleName -> Maybe HomeModInfo
    lookupHpt HomePackageTable
    hpt (forall unit. GenModule unit -> ModuleName
    moduleName Module
    mod) of
          Just HomeModInfo
    hm | forall (phase :: ModIfacePhase). ModIface_ phase -> Module
    mi_module (HomeModInfo -> ModIface
    hm_iface HomeModInfo
    hm) forall a. Eq a => a -> a -> Bool
    == Module
    mod -> forall a. a -> Maybe a
    Just HomeModInfo
    hm
          Maybe HomeModInfo
    _otherwise                               -> forall a. Maybe a
    Nothing

    pprHPT :: HomePackageTable -> SDoc
    -- A bit arbitrary for now
    pprHPT :: HomePackageTable -> SDoc
    pprHPT HomePackageTable
    hpt = forall key a. UniqDFM key a -> ([a] -> SDoc) -> SDoc
    pprUDFM HomePackageTable
    hpt forall a b. (a -> b) -> a -> b
    $ \[HomeModInfo]
    hms ->
        [SDoc] -> SDoc
    vcat [ SDoc -> Int -> SDoc -> SDoc
    hang (forall a. Outputable a => a -> SDoc
    ppr (forall (phase :: ModIfacePhase). ModIface_ phase -> Module
    mi_module (HomeModInfo -> ModIface
    hm_iface HomeModInfo
    hm)))
                  Int
    2 (forall a. Outputable a => a -> SDoc
    ppr (ModDetails -> TypeEnv
    md_types (HomeModInfo -> ModDetails
    hm_details HomeModInfo
    hm)))
             | HomeModInfo
    hm <- [HomeModInfo]
    hms ]