    {-
    (c) The University of Glasgow, 2000-2006

    -}

    {-# LANGUAGE FlexibleContexts #-}

    -- | Module finder
    module GHC.Unit.Finder (
        FindResult(..),
        InstalledFindResult(..),
        FinderOpts(..),
        FinderCache,
        initFinderCache,
        flushFinderCaches,
        findImportedModule,
        findPluginModule,
        findExactModule,
        findHomeModule,
        findExposedPackageModule,
        mkHomeModLocation,
        mkHomeModLocation2,
        mkHiOnlyModLocation,
        mkHiPath,
        mkObjPath,
        addModuleToFinder,
        addHomeModuleToFinder,
        uncacheModule,
        mkStubPaths,

        findObjectLinkableMaybe,
        findObjectLinkable,

        -- Hash cache
        lookupFileCache
      ) where

    import GHC.Prelude

    import GHC.Platform.Ways

    import GHC.Builtin.Names ( gHC_PRIM )

    import GHC.Unit.Env
    import GHC.Unit.Types
    import GHC.Unit.Module
    import GHC.Unit.Home
    import GHC.Unit.State
    import GHC.Unit.Finder.Types

    import GHC.Data.Maybe    ( expectJust )
    import qualified GHC.Data.ShortText as ST

    import GHC.Utils.Misc
    import GHC.Utils.Outputable as Outputable
    import GHC.Utils.Panic

    import GHC.Linker.Types
    import GHC.Types.PkgQual

    import GHC.Fingerprint
    import Data.IORef
    import System.Directory
    import System.FilePath
    import Control.Monad
    import Data.Time
    import qualified Data.Map as M
    import GHC.Driver.Env
        ( hsc_home_unit_maybe, HscEnv(hsc_FC, hsc_dflags, hsc_unit_env) )
    import GHC.Driver.Config.Finder
    import qualified Data.Set as Set

    type FileExt = String   -- Filename extension
    type BaseName = String  -- Basename of file

    -- -----------------------------------------------------------------------------
    -- The Finder

    -- The Finder provides a thin filesystem abstraction to the rest of
    -- the compiler.  For a given module, it can tell you where the
    -- source, interface, and object files for that module live.

    -- It does *not* know which particular package a module lives in.  Use
    -- Packages.lookupModuleInAllUnits for that.

    -- -----------------------------------------------------------------------------
    -- The finder's cache

    initFinderCache :: IO FinderCache
    initFinderCache :: IO FinderCache
    initFinderCache = IORef FinderCacheState -> IORef FileCacheState -> FinderCache
    FinderCache (IORef FinderCacheState -> IORef FileCacheState -> FinderCache)
    -> IO (IORef FinderCacheState)
    -> IO (IORef FileCacheState -> FinderCache)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> FinderCacheState -> IO (IORef FinderCacheState)
    forall a. a -> IO (IORef a)
    newIORef FinderCacheState
    forall a. InstalledModuleEnv a
    emptyInstalledModuleEnv
                                  IO (IORef FileCacheState -> FinderCache)
    -> IO (IORef FileCacheState) -> IO FinderCache
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> FileCacheState -> IO (IORef FileCacheState)
    forall a. a -> IO (IORef a)
    newIORef FileCacheState
    forall k a. Map k a
    M.empty

    -- remove all the home modules from the cache; package modules are
    -- assumed to not move around during a session; also flush the file hash
    -- cache
    flushFinderCaches :: FinderCache -> UnitEnv -> IO ()
    flushFinderCaches :: FinderCache -> UnitEnv -> IO ()
    flushFinderCaches (FinderCache IORef FinderCacheState
    ref IORef FileCacheState
    file_ref) UnitEnv
    ue = do
      IORef FinderCacheState
    -> (FinderCacheState -> (FinderCacheState, ())) -> IO ()
    forall a b. IORef a -> (a -> (a, b)) -> IO b
    atomicModifyIORef' IORef FinderCacheState
    ref ((FinderCacheState -> (FinderCacheState, ())) -> IO ())
    -> (FinderCacheState -> (FinderCacheState, ())) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \FinderCacheState
    fm -> ((InstalledModule -> InstalledFindResult -> Bool)
    -> FinderCacheState -> FinderCacheState
    forall a.
    (InstalledModule -> a -> Bool)
    -> InstalledModuleEnv a -> InstalledModuleEnv a
    filterInstalledModuleEnv InstalledModule -> InstalledFindResult -> Bool
    is_ext FinderCacheState
    fm, ())
      IORef FileCacheState
    -> (FileCacheState -> (FileCacheState, ())) -> IO ()
    forall a b. IORef a -> (a -> (a, b)) -> IO b
    atomicModifyIORef' IORef FileCacheState
    file_ref ((FileCacheState -> (FileCacheState, ())) -> IO ())
    -> (FileCacheState -> (FileCacheState, ())) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \FileCacheState
    _ -> (FileCacheState
    forall k a. Map k a
    M.empty, ())
     where
      is_ext :: InstalledModule -> InstalledFindResult -> Bool
    is_ext InstalledModule
    mod InstalledFindResult
    _ = Bool -> Bool
    not (UnitEnv -> InstalledModule -> Bool
    isUnitEnvInstalledModule UnitEnv
    ue InstalledModule
    mod)

    addToFinderCache :: FinderCache -> InstalledModule -> InstalledFindResult -> IO ()
    addToFinderCache :: FinderCache -> InstalledModule -> InstalledFindResult -> IO ()
    addToFinderCache (FinderCache IORef FinderCacheState
    ref IORef FileCacheState
    _) InstalledModule
    key InstalledFindResult
    val =
      IORef FinderCacheState
    -> (FinderCacheState -> (FinderCacheState, ())) -> IO ()
    forall a b. IORef a -> (a -> (a, b)) -> IO b
    atomicModifyIORef' IORef FinderCacheState
    ref ((FinderCacheState -> (FinderCacheState, ())) -> IO ())
    -> (FinderCacheState -> (FinderCacheState, ())) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \FinderCacheState
    c -> (FinderCacheState
    -> InstalledModule -> InstalledFindResult -> FinderCacheState
    forall a.
    InstalledModuleEnv a
    -> InstalledModule -> a -> InstalledModuleEnv a
    extendInstalledModuleEnv FinderCacheState
    c InstalledModule
    key InstalledFindResult
    val, ())

    removeFromFinderCache :: FinderCache -> InstalledModule -> IO ()
    removeFromFinderCache :: FinderCache -> InstalledModule -> IO ()
    removeFromFinderCache (FinderCache IORef FinderCacheState
    ref IORef FileCacheState
    _) InstalledModule
    key =
      IORef FinderCacheState
    -> (FinderCacheState -> (FinderCacheState, ())) -> IO ()
    forall a b. IORef a -> (a -> (a, b)) -> IO b
    atomicModifyIORef' IORef FinderCacheState
    ref ((FinderCacheState -> (FinderCacheState, ())) -> IO ())
    -> (FinderCacheState -> (FinderCacheState, ())) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \FinderCacheState
    c -> (FinderCacheState -> InstalledModule -> FinderCacheState
    forall a.
    InstalledModuleEnv a -> InstalledModule -> InstalledModuleEnv a
    delInstalledModuleEnv FinderCacheState
    c InstalledModule
    key, ())

    lookupFinderCache :: FinderCache -> InstalledModule -> IO (Maybe InstalledFindResult)
    lookupFinderCache :: FinderCache -> InstalledModule -> IO (Maybe InstalledFindResult)
    lookupFinderCache (FinderCache IORef FinderCacheState
    ref IORef FileCacheState
    _) InstalledModule
    key = do
       c <- IORef FinderCacheState -> IO FinderCacheState
    forall a. IORef a -> IO a
    readIORef IORef FinderCacheState
    ref
       return $! lookupInstalledModuleEnv c key

    lookupFileCache :: FinderCache -> FilePath -> IO Fingerprint
    lookupFileCache :: FinderCache -> FilePath -> IO Fingerprint
    lookupFileCache (FinderCache IORef FinderCacheState
    _ IORef FileCacheState
    ref) FilePath
    key = do
       c <- IORef FileCacheState -> IO FileCacheState
    forall a. IORef a -> IO a
    readIORef IORef FileCacheState
    ref
       case M.lookup key c of
         Maybe Fingerprint
    Nothing -> do
           hash <- FilePath -> IO Fingerprint
    getFileHash FilePath
    key
           atomicModifyIORef' ref $ \FileCacheState
    c -> (FilePath -> Fingerprint -> FileCacheState -> FileCacheState
    forall k a. Ord k => k -> a -> Map k a -> Map k a
    M.insert FilePath
    key Fingerprint
    hash FileCacheState
    c, ())
           return hash
         Just Fingerprint
    fp -> Fingerprint -> IO Fingerprint
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Fingerprint
    fp

    -- -----------------------------------------------------------------------------
    -- The three external entry points

    -- | Locate a module that was imported by the user.  We have the
    -- module's name, and possibly a package name.  Without a package
    -- name, this function will use the search path and the known exposed
    -- packages to find the module, if a package is specified then only
    -- that package is searched for the module.

    findImportedModule :: HscEnv -> ModuleName -> PkgQual -> IO FindResult
    findImportedModule :: HscEnv -> ModuleName -> PkgQual -> IO FindResult
    findImportedModule HscEnv
    hsc_env ModuleName
    mod PkgQual
    pkg_qual =
      let fc :: FinderCache
    fc        = HscEnv -> FinderCache
    hsc_FC HscEnv
    hsc_env
          mhome_unit :: Maybe HomeUnit
    mhome_unit = HscEnv -> Maybe HomeUnit
    hsc_home_unit_maybe HscEnv
    hsc_env
          dflags :: DynFlags
    dflags    = HscEnv -> DynFlags
    hsc_dflags HscEnv
    hsc_env
          fopts :: FinderOpts
    fopts     = DynFlags -> FinderOpts
    initFinderOpts DynFlags
    dflags
      in do
        FinderCache
    -> FinderOpts
    -> UnitEnv
    -> Maybe HomeUnit
    -> ModuleName
    -> PkgQual
    -> IO FindResult
    findImportedModuleNoHsc FinderCache
    fc FinderOpts
    fopts (HscEnv -> UnitEnv
    hsc_unit_env HscEnv
    hsc_env) Maybe HomeUnit
    mhome_unit ModuleName
    mod PkgQual
    pkg_qual

    findImportedModuleNoHsc
      :: FinderCache
      -> FinderOpts
      -> UnitEnv
      -> Maybe HomeUnit
      -> ModuleName
      -> PkgQual
      -> IO FindResult
    findImportedModuleNoHsc :: FinderCache
    -> FinderOpts
    -> UnitEnv
    -> Maybe HomeUnit
    -> ModuleName
    -> PkgQual
    -> IO FindResult
    findImportedModuleNoHsc FinderCache
    fc FinderOpts
    fopts UnitEnv
    ue Maybe HomeUnit
    mhome_unit ModuleName
    mod_name PkgQual
    mb_pkg =
      case PkgQual
    mb_pkg of
        PkgQual
    NoPkgQual  -> IO FindResult
    unqual_import
        ThisPkg UnitId
    uid | (HomeUnit -> UnitId
    forall u. GenHomeUnit u -> UnitId
    homeUnitId (HomeUnit -> UnitId) -> Maybe HomeUnit -> Maybe UnitId
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe HomeUnit
    mhome_unit) Maybe UnitId -> Maybe UnitId -> Bool
    forall a. Eq a => a -> a -> Bool
    == UnitId -> Maybe UnitId
    forall a. a -> Maybe a
    Just UnitId
    uid -> IO FindResult
    home_import
                    | Just FinderOpts
    os <- UnitId -> [(UnitId, FinderOpts)] -> Maybe FinderOpts
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup UnitId
    uid [(UnitId, FinderOpts)]
    other_fopts -> (UnitId, FinderOpts) -> IO FindResult
    home_pkg_import (UnitId
    uid, FinderOpts
    os)
                    | Bool
    otherwise -> FilePath -> SDoc -> IO FindResult
    forall a. HasCallStack => FilePath -> SDoc -> a
    pprPanic FilePath
    "findImportModule" (ModuleName -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr ModuleName
    mod_name SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ PkgQual -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr PkgQual
    mb_pkg SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ Maybe UnitId -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (HomeUnit -> UnitId
    forall u. GenHomeUnit u -> UnitId
    homeUnitId (HomeUnit -> UnitId) -> Maybe HomeUnit -> Maybe UnitId
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe HomeUnit
    mhome_unit) SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ UnitId -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr UnitId
    uid SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ [UnitId] -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (((UnitId, FinderOpts) -> UnitId)
    -> [(UnitId, FinderOpts)] -> [UnitId]
    forall a b. (a -> b) -> [a] -> [b]
    map (UnitId, FinderOpts) -> UnitId
    forall a b. (a, b) -> a
    fst [(UnitId, FinderOpts)]
    all_opts))
        OtherPkg UnitId
    _ -> IO FindResult
    pkg_import
      where
        all_opts :: [(UnitId, FinderOpts)]
    all_opts = case Maybe HomeUnit
    mhome_unit of
                    Maybe HomeUnit
    Nothing -> [(UnitId, FinderOpts)]
    other_fopts
                    Just HomeUnit
    home_unit -> (HomeUnit -> UnitId
    forall u. GenHomeUnit u -> UnitId
    homeUnitId HomeUnit
    home_unit, FinderOpts
    fopts) (UnitId, FinderOpts)
    -> [(UnitId, FinderOpts)] -> [(UnitId, FinderOpts)]
    forall a. a -> [a] -> [a]
    : [(UnitId, FinderOpts)]
    other_fopts

        home_import :: IO FindResult
    home_import = case Maybe HomeUnit
    mhome_unit of
                       Just HomeUnit
    home_unit -> FinderCache
    -> FinderOpts -> HomeUnit -> ModuleName -> IO FindResult
    findHomeModule FinderCache
    fc FinderOpts
    fopts HomeUnit
    home_unit ModuleName
    mod_name
                       Maybe HomeUnit
    Nothing -> FindResult -> IO FindResult
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (FindResult -> IO FindResult) -> FindResult -> IO FindResult
    forall a b. (a -> b) -> a -> b
    $ Unit -> FindResult
    NoPackage (FilePath -> Unit
    forall a. HasCallStack => FilePath -> a
    panic FilePath
    "findImportedModule: no home-unit")

        home_pkg_import :: (UnitId, FinderOpts) -> IO FindResult
    home_pkg_import (UnitId
    uid, FinderOpts
    opts)
          -- If the module is reexported, then look for it as if it was from the perspective
          -- of that package which reexports it.
          | ModuleName
    mod_name ModuleName -> Set ModuleName -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `Set.member` FinderOpts -> Set ModuleName
    finder_reexportedModules FinderOpts
    opts =
            FinderCache
    -> FinderOpts
    -> UnitEnv
    -> Maybe HomeUnit
    -> ModuleName
    -> PkgQual
    -> IO FindResult
    findImportedModuleNoHsc FinderCache
    fc FinderOpts
    opts UnitEnv
    ue (HomeUnit -> Maybe HomeUnit
    forall a. a -> Maybe a
    Just (HomeUnit -> Maybe HomeUnit) -> HomeUnit -> Maybe HomeUnit
    forall a b. (a -> b) -> a -> b
    $ UnitId -> Maybe (UnitId, GenInstantiations UnitId) -> HomeUnit
    forall u. UnitId -> Maybe (u, GenInstantiations u) -> GenHomeUnit u
    DefiniteHomeUnit UnitId
    uid Maybe (UnitId, GenInstantiations UnitId)
    forall a. Maybe a
    Nothing) ModuleName
    mod_name PkgQual
    NoPkgQual
          | ModuleName
    mod_name ModuleName -> Set ModuleName -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `Set.member` FinderOpts -> Set ModuleName
    finder_hiddenModules FinderOpts
    opts =
            FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (UnitId -> FindResult
    mkHomeHidden UnitId
    uid)
          | Bool
    otherwise =
            FinderCache -> FinderOpts -> UnitId -> ModuleName -> IO FindResult
    findHomePackageModule FinderCache
    fc FinderOpts
    opts UnitId
    uid ModuleName
    mod_name

        -- Do not be smart and change this to `foldr orIfNotFound home_import hs` as
        -- that is not the same!! home_import is first because we need to look within ourselves
        -- first before looking at the packages in order.
        any_home_import :: IO FindResult
    any_home_import = (IO FindResult -> IO FindResult -> IO FindResult)
    -> [IO FindResult] -> IO FindResult
    forall a. (a -> a -> a) -> [a] -> a
    forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
    foldr1 IO FindResult -> IO FindResult -> IO FindResult
    forall (m :: * -> *).
    Monad m =>
    m FindResult -> m FindResult -> m FindResult
    orIfNotFound (IO FindResult
    home_importIO FindResult -> [IO FindResult] -> [IO FindResult]
    forall a. a -> [a] -> [a]
    : ((UnitId, FinderOpts) -> IO FindResult)
    -> [(UnitId, FinderOpts)] -> [IO FindResult]
    forall a b. (a -> b) -> [a] -> [b]
    map (UnitId, FinderOpts) -> IO FindResult
    home_pkg_import [(UnitId, FinderOpts)]
    other_fopts)

        pkg_import :: IO FindResult
    pkg_import    = FinderCache
    -> FinderOpts
    -> UnitState
    -> ModuleName
    -> PkgQual
    -> IO FindResult
    findExposedPackageModule FinderCache
    fc FinderOpts
    fopts UnitState
    units  ModuleName
    mod_name PkgQual
    mb_pkg

        unqual_import :: IO FindResult
    unqual_import = IO FindResult
    any_home_import
                        IO FindResult -> IO FindResult -> IO FindResult
    forall (m :: * -> *).
    Monad m =>
    m FindResult -> m FindResult -> m FindResult
    `orIfNotFound`
                        FinderCache
    -> FinderOpts
    -> UnitState
    -> ModuleName
    -> PkgQual
    -> IO FindResult
    findExposedPackageModule FinderCache
    fc FinderOpts
    fopts UnitState
    units ModuleName
    mod_name PkgQual
    NoPkgQual

        units :: UnitState
    units     = case Maybe HomeUnit
    mhome_unit of
                      Maybe HomeUnit
    Nothing -> HasDebugCallStack => UnitEnv -> UnitState
    UnitEnv -> UnitState
    ue_units UnitEnv
    ue
                      Just HomeUnit
    home_unit -> HomeUnitEnv -> UnitState
    homeUnitEnv_units (HomeUnitEnv -> UnitState) -> HomeUnitEnv -> UnitState
    forall a b. (a -> b) -> a -> b
    $ HasDebugCallStack => UnitId -> UnitEnv -> HomeUnitEnv
    UnitId -> UnitEnv -> HomeUnitEnv
    ue_findHomeUnitEnv (HomeUnit -> UnitId
    forall u. GenHomeUnit u -> UnitId
    homeUnitId HomeUnit
    home_unit) UnitEnv
    ue
        hpt_deps :: [UnitId]
        hpt_deps :: [UnitId]
    hpt_deps  = UnitState -> [UnitId]
    homeUnitDepends UnitState
    units
        other_fopts :: [(UnitId, FinderOpts)]
    other_fopts  = (UnitId -> (UnitId, FinderOpts))
    -> [UnitId] -> [(UnitId, FinderOpts)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\UnitId
    uid -> (UnitId
    uid, DynFlags -> FinderOpts
    initFinderOpts (HomeUnitEnv -> DynFlags
    homeUnitEnv_dflags (HasDebugCallStack => UnitId -> UnitEnv -> HomeUnitEnv
    UnitId -> UnitEnv -> HomeUnitEnv
    ue_findHomeUnitEnv UnitId
    uid UnitEnv
    ue)))) [UnitId]
    hpt_deps

    -- | Locate a plugin module requested by the user, for a compiler
    -- plugin.  This consults the same set of exposed packages as
    -- 'findImportedModule', unless @-hide-all-plugin-packages@ or
    -- @-plugin-package@ are specified.
    findPluginModule :: FinderCache -> FinderOpts -> UnitState -> Maybe HomeUnit -> ModuleName -> IO FindResult
    findPluginModule :: FinderCache
    -> FinderOpts
    -> UnitState
    -> Maybe HomeUnit
    -> ModuleName
    -> IO FindResult
    findPluginModule FinderCache
    fc FinderOpts
    fopts UnitState
    units (Just HomeUnit
    home_unit) ModuleName
    mod_name =
      FinderCache
    -> FinderOpts -> HomeUnit -> ModuleName -> IO FindResult
    findHomeModule FinderCache
    fc FinderOpts
    fopts HomeUnit
    home_unit ModuleName
    mod_name
      IO FindResult -> IO FindResult -> IO FindResult
    forall (m :: * -> *).
    Monad m =>
    m FindResult -> m FindResult -> m FindResult
    `orIfNotFound`
      FinderCache
    -> FinderOpts -> UnitState -> ModuleName -> IO FindResult
    findExposedPluginPackageModule FinderCache
    fc FinderOpts
    fopts UnitState
    units ModuleName
    mod_name
    findPluginModule FinderCache
    fc FinderOpts
    fopts UnitState
    units Maybe HomeUnit
    Nothing ModuleName
    mod_name =
      FinderCache
    -> FinderOpts -> UnitState -> ModuleName -> IO FindResult
    findExposedPluginPackageModule FinderCache
    fc FinderOpts
    fopts UnitState
    units ModuleName
    mod_name

    -- | Locate a specific 'Module'.  The purpose of this function is to
    -- create a 'ModLocation' for a given 'Module', that is to find out
    -- where the files associated with this module live.  It is used when
    -- reading the interface for a module mentioned by another interface,
    -- for example (a "system import").

    findExactModule :: FinderCache -> FinderOpts ->  UnitEnvGraph FinderOpts -> UnitState -> Maybe HomeUnit -> InstalledModule -> IO InstalledFindResult
    findExactModule :: FinderCache
    -> FinderOpts
    -> UnitEnvGraph FinderOpts
    -> UnitState
    -> Maybe HomeUnit
    -> InstalledModule
    -> IO InstalledFindResult
    findExactModule FinderCache
    fc FinderOpts
    fopts UnitEnvGraph FinderOpts
    other_fopts UnitState
    unit_state Maybe HomeUnit
    mhome_unit InstalledModule
    mod = do
      case Maybe HomeUnit
    mhome_unit of
        Just HomeUnit
    home_unit
         | HomeUnit -> InstalledModule -> Bool
    forall u. GenHomeUnit u -> InstalledModule -> Bool
    isHomeInstalledModule HomeUnit
    home_unit InstalledModule
    mod
            -> FinderCache
    -> FinderOpts -> UnitId -> ModuleName -> IO InstalledFindResult
    findInstalledHomeModule FinderCache
    fc FinderOpts
    fopts (HomeUnit -> UnitId
    forall u. GenHomeUnit u -> UnitId
    homeUnitId HomeUnit
    home_unit) (InstalledModule -> ModuleName
    forall unit. GenModule unit -> ModuleName
    moduleName InstalledModule
    mod)
         | Just FinderOpts
    home_fopts <- UnitId -> UnitEnvGraph FinderOpts -> Maybe FinderOpts
    forall v. UnitId -> UnitEnvGraph v -> Maybe v
    unitEnv_lookup_maybe (InstalledModule -> UnitId
    forall unit. GenModule unit -> unit
    moduleUnit InstalledModule
    mod) UnitEnvGraph FinderOpts
    other_fopts
            -> FinderCache
    -> FinderOpts -> UnitId -> ModuleName -> IO InstalledFindResult
    findInstalledHomeModule FinderCache
    fc FinderOpts
    home_fopts (InstalledModule -> UnitId
    forall unit. GenModule unit -> unit
    moduleUnit InstalledModule
    mod) (InstalledModule -> ModuleName
    forall unit. GenModule unit -> ModuleName
    moduleName InstalledModule
    mod)
        Maybe HomeUnit
    _ -> FinderCache
    -> UnitState
    -> FinderOpts
    -> InstalledModule
    -> IO InstalledFindResult
    findPackageModule FinderCache
    fc UnitState
    unit_state FinderOpts
    fopts InstalledModule
    mod

    -- -----------------------------------------------------------------------------
    -- Helpers

    -- | Given a monadic actions @this@ and @or_this@, first execute
    -- @this@.  If the returned 'FindResult' is successful, return
    -- it; otherwise, execute @or_this@.  If both failed, this function
    -- also combines their failure messages in a reasonable way.
    orIfNotFound :: Monad m => m FindResult -> m FindResult -> m FindResult
    orIfNotFound :: forall (m :: * -> *).
    Monad m =>
    m FindResult -> m FindResult -> m FindResult
    orIfNotFound m FindResult
    this m FindResult
    or_this = do
      res <- m FindResult
    this
      case res of
        NotFound { fr_paths :: FindResult -> [FilePath]
    fr_paths = [FilePath]
    paths1, fr_mods_hidden :: FindResult -> [Unit]
    fr_mods_hidden = [Unit]
    mh1
                 , fr_pkgs_hidden :: FindResult -> [Unit]
    fr_pkgs_hidden = [Unit]
    ph1, fr_unusables :: FindResult -> [UnusableUnit]
    fr_unusables = [UnusableUnit]
    u1, fr_suggestions :: FindResult -> [ModuleSuggestion]
    fr_suggestions = [ModuleSuggestion]
    s1 }
         -> do res2 <- m FindResult
    or_this
               case res2 of
                 NotFound { fr_paths :: FindResult -> [FilePath]
    fr_paths = [FilePath]
    paths2, fr_pkg :: FindResult -> Maybe Unit
    fr_pkg = Maybe Unit
    mb_pkg2, fr_mods_hidden :: FindResult -> [Unit]
    fr_mods_hidden = [Unit]
    mh2
                          , fr_pkgs_hidden :: FindResult -> [Unit]
    fr_pkgs_hidden = [Unit]
    ph2, fr_unusables :: FindResult -> [UnusableUnit]
    fr_unusables = [UnusableUnit]
    u2
                          , fr_suggestions :: FindResult -> [ModuleSuggestion]
    fr_suggestions = [ModuleSuggestion]
    s2 }
                  -> FindResult -> m FindResult
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (NotFound { fr_paths :: [FilePath]
    fr_paths = [FilePath]
    paths1 [FilePath] -> [FilePath] -> [FilePath]
    forall a. [a] -> [a] -> [a]
    ++ [FilePath]
    paths2
                                      , fr_pkg :: Maybe Unit
    fr_pkg = Maybe Unit
    mb_pkg2 -- snd arg is the package search
                                      , fr_mods_hidden :: [Unit]
    fr_mods_hidden = [Unit]
    mh1 [Unit] -> [Unit] -> [Unit]
    forall a. [a] -> [a] -> [a]
    ++ [Unit]
    mh2
                                      , fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = [Unit]
    ph1 [Unit] -> [Unit] -> [Unit]
    forall a. [a] -> [a] -> [a]
    ++ [Unit]
    ph2
                                      , fr_unusables :: [UnusableUnit]
    fr_unusables = [UnusableUnit]
    u1 [UnusableUnit] -> [UnusableUnit] -> [UnusableUnit]
    forall a. [a] -> [a] -> [a]
    ++ [UnusableUnit]
    u2
                                      , fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = [ModuleSuggestion]
    s1  [ModuleSuggestion] -> [ModuleSuggestion] -> [ModuleSuggestion]
    forall a. [a] -> [a] -> [a]
    ++ [ModuleSuggestion]
    s2 })
                 FindResult
    _other -> FindResult -> m FindResult
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return FindResult
    res2
        FindResult
    _other -> FindResult -> m FindResult
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return FindResult
    res

    -- | Helper function for 'findHomeModule': this function wraps an IO action
    -- which would look up @mod_name@ in the file system (the home package),
    -- and first consults the 'hsc_FC' cache to see if the lookup has already
    -- been done.  Otherwise, do the lookup (with the IO action) and save
    -- the result in the finder cache and the module location cache (if it
    -- was successful.)
    homeSearchCache :: FinderCache -> UnitId -> ModuleName -> IO InstalledFindResult -> IO InstalledFindResult
    homeSearchCache :: FinderCache
    -> UnitId
    -> ModuleName
    -> IO InstalledFindResult
    -> IO InstalledFindResult
    homeSearchCache FinderCache
    fc UnitId
    home_unit ModuleName
    mod_name IO InstalledFindResult
    do_this = do
      let mod :: InstalledModule
    mod = UnitId -> ModuleName -> InstalledModule
    forall u. u -> ModuleName -> GenModule u
    mkModule UnitId
    home_unit ModuleName
    mod_name
      FinderCache
    -> InstalledModule
    -> IO InstalledFindResult
    -> IO InstalledFindResult
    modLocationCache FinderCache
    fc InstalledModule
    mod IO InstalledFindResult
    do_this

    findExposedPackageModule :: FinderCache -> FinderOpts -> UnitState -> ModuleName -> PkgQual -> IO FindResult
    findExposedPackageModule :: FinderCache
    -> FinderOpts
    -> UnitState
    -> ModuleName
    -> PkgQual
    -> IO FindResult
    findExposedPackageModule FinderCache
    fc FinderOpts
    fopts UnitState
    units ModuleName
    mod_name PkgQual
    mb_pkg =
      FinderCache -> FinderOpts -> LookupResult -> IO FindResult
    findLookupResult FinderCache
    fc FinderOpts
    fopts
        (LookupResult -> IO FindResult) -> LookupResult -> IO FindResult
    forall a b. (a -> b) -> a -> b
    $ UnitState -> ModuleName -> PkgQual -> LookupResult
    lookupModuleWithSuggestions UnitState
    units ModuleName
    mod_name PkgQual
    mb_pkg

    findExposedPluginPackageModule :: FinderCache -> FinderOpts -> UnitState -> ModuleName -> IO FindResult
    findExposedPluginPackageModule :: FinderCache
    -> FinderOpts -> UnitState -> ModuleName -> IO FindResult
    findExposedPluginPackageModule FinderCache
    fc FinderOpts
    fopts UnitState
    units ModuleName
    mod_name =
      FinderCache -> FinderOpts -> LookupResult -> IO FindResult
    findLookupResult FinderCache
    fc FinderOpts
    fopts
        (LookupResult -> IO FindResult) -> LookupResult -> IO FindResult
    forall a b. (a -> b) -> a -> b
    $ UnitState -> ModuleName -> PkgQual -> LookupResult
    lookupPluginModuleWithSuggestions UnitState
    units ModuleName
    mod_name PkgQual
    NoPkgQual

    findLookupResult :: FinderCache -> FinderOpts -> LookupResult -> IO FindResult
    findLookupResult :: FinderCache -> FinderOpts -> LookupResult -> IO FindResult
    findLookupResult FinderCache
    fc FinderOpts
    fopts LookupResult
    r = case LookupResult
    r of
         LookupFound Module
    m (UnitInfo, ModuleOrigin)
    pkg_conf -> do
           let im :: InstalledModule
    im = (InstalledModule, Maybe InstantiatedModule) -> InstalledModule
    forall a b. (a, b) -> a
    fst (Module -> (InstalledModule, Maybe InstantiatedModule)
    getModuleInstantiation Module
    m)
           r' <- FinderCache
    -> FinderOpts
    -> InstalledModule
    -> UnitInfo
    -> IO InstalledFindResult
    findPackageModule_ FinderCache
    fc FinderOpts
    fopts InstalledModule
    im ((UnitInfo, ModuleOrigin) -> UnitInfo
    forall a b. (a, b) -> a
    fst (UnitInfo, ModuleOrigin)
    pkg_conf)
           case r' of
            -- TODO: ghc -M is unlikely to do the right thing
            -- with just the location of the thing that was
            -- instantiated; you probably also need all of the
            -- implicit locations from the instances
            InstalledFound ModLocation
    loc   InstalledModule
    _ -> FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ModLocation -> Module -> FindResult
    Found ModLocation
    loc Module
    m)
            InstalledNoPackage   UnitId
    _ -> FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Unit -> FindResult
    NoPackage (Module -> Unit
    forall unit. GenModule unit -> unit
    moduleUnit Module
    m))
            InstalledNotFound [FilePath]
    fp Maybe UnitId
    _ -> FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (NotFound{ fr_paths :: [FilePath]
    fr_paths = [FilePath]
    fp, fr_pkg :: Maybe Unit
    fr_pkg = Unit -> Maybe Unit
    forall a. a -> Maybe a
    Just (Module -> Unit
    forall unit. GenModule unit -> unit
    moduleUnit Module
    m)
                                             , fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = []
                                             , fr_mods_hidden :: [Unit]
    fr_mods_hidden = []
                                             , fr_unusables :: [UnusableUnit]
    fr_unusables = []
                                             , fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = []})
         LookupMultiple [(Module, ModuleOrigin)]
    rs ->
           FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([(Module, ModuleOrigin)] -> FindResult
    FoundMultiple [(Module, ModuleOrigin)]
    rs)
         LookupHidden [(Module, ModuleOrigin)]
    pkg_hiddens [(Module, ModuleOrigin)]
    mod_hiddens ->
           FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (NotFound{ fr_paths :: [FilePath]
    fr_paths = [], fr_pkg :: Maybe Unit
    fr_pkg = Maybe Unit
    forall a. Maybe a
    Nothing
                           , fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = ((Module, ModuleOrigin) -> Unit)
    -> [(Module, ModuleOrigin)] -> [Unit]
    forall a b. (a -> b) -> [a] -> [b]
    map (Module -> Unit
    forall unit. GenModule unit -> unit
    moduleUnit(Module -> Unit)
    -> ((Module, ModuleOrigin) -> Module)
    -> (Module, ModuleOrigin)
    -> Unit
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .(Module, ModuleOrigin) -> Module
    forall a b. (a, b) -> a
    fst) [(Module, ModuleOrigin)]
    pkg_hiddens
                           , fr_mods_hidden :: [Unit]
    fr_mods_hidden = ((Module, ModuleOrigin) -> Unit)
    -> [(Module, ModuleOrigin)] -> [Unit]
    forall a b. (a -> b) -> [a] -> [b]
    map (Module -> Unit
    forall unit. GenModule unit -> unit
    moduleUnit(Module -> Unit)
    -> ((Module, ModuleOrigin) -> Module)
    -> (Module, ModuleOrigin)
    -> Unit
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .(Module, ModuleOrigin) -> Module
    forall a b. (a, b) -> a
    fst) [(Module, ModuleOrigin)]
    mod_hiddens
                           , fr_unusables :: [UnusableUnit]
    fr_unusables = []
                           , fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = [] })
         LookupUnusable [(Module, ModuleOrigin)]
    unusable ->
           let unusables' :: [UnusableUnit]
    unusables' = ((Module, ModuleOrigin) -> UnusableUnit)
    -> [(Module, ModuleOrigin)] -> [UnusableUnit]
    forall a b. (a -> b) -> [a] -> [b]
    map (Module, ModuleOrigin) -> UnusableUnit
    forall {a}. (a, ModuleOrigin) -> UnusableUnit
    get_unusable [(Module, ModuleOrigin)]
    unusable
               get_unusable :: (a, ModuleOrigin) -> UnusableUnit
    get_unusable (a
    _, ModUnusable UnusableUnit
    r) = UnusableUnit
    r
               get_unusable (a
    _, ModuleOrigin
    r)             =
                 FilePath -> SDoc -> UnusableUnit
    forall a. HasCallStack => FilePath -> SDoc -> a
    pprPanic FilePath
    "findLookupResult: unexpected origin" (ModuleOrigin -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr ModuleOrigin
    r)
           in FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (NotFound{ fr_paths :: [FilePath]
    fr_paths = [], fr_pkg :: Maybe Unit
    fr_pkg = Maybe Unit
    forall a. Maybe a
    Nothing
                              , fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = []
                              , fr_mods_hidden :: [Unit]
    fr_mods_hidden = []
                              , fr_unusables :: [UnusableUnit]
    fr_unusables = [UnusableUnit]
    unusables'
                              , fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = [] })
         LookupNotFound [ModuleSuggestion]
    suggest -> do
           let suggest' :: [ModuleSuggestion]
    suggest'
                 | FinderOpts -> Bool
    finder_enableSuggestions FinderOpts
    fopts = [ModuleSuggestion]
    suggest
                 | Bool
    otherwise = []
           FindResult -> IO FindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (NotFound{ fr_paths :: [FilePath]
    fr_paths = [], fr_pkg :: Maybe Unit
    fr_pkg = Maybe Unit
    forall a. Maybe a
    Nothing
                           , fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = []
                           , fr_mods_hidden :: [Unit]
    fr_mods_hidden = []
                           , fr_unusables :: [UnusableUnit]
    fr_unusables = []
                           , fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = [ModuleSuggestion]
    suggest' })

    modLocationCache :: FinderCache -> InstalledModule -> IO InstalledFindResult -> IO InstalledFindResult
    modLocationCache :: FinderCache
    -> InstalledModule
    -> IO InstalledFindResult
    -> IO InstalledFindResult
    modLocationCache FinderCache
    fc InstalledModule
    mod IO InstalledFindResult
    do_this = do
      m <- FinderCache -> InstalledModule -> IO (Maybe InstalledFindResult)
    lookupFinderCache FinderCache
    fc InstalledModule
    mod
      case m of
        Just InstalledFindResult
    result -> InstalledFindResult -> IO InstalledFindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return InstalledFindResult
    result
        Maybe InstalledFindResult
    Nothing     -> do
            result <- IO InstalledFindResult
    do_this
            addToFinderCache fc mod result
            return result

    addModuleToFinder :: FinderCache -> Module -> ModLocation -> IO ()
    addModuleToFinder :: FinderCache -> Module -> ModLocation -> IO ()
    addModuleToFinder FinderCache
    fc Module
    mod ModLocation
    loc = do
      let imod :: InstalledModule
    imod = Unit -> UnitId
    toUnitId (Unit -> UnitId) -> Module -> InstalledModule
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Module
    mod
      FinderCache -> InstalledModule -> InstalledFindResult -> IO ()
    addToFinderCache FinderCache
    fc InstalledModule
    imod (ModLocation -> InstalledModule -> InstalledFindResult
    InstalledFound ModLocation
    loc InstalledModule
    imod)

    -- This returns a module because it's more convenient for users
    addHomeModuleToFinder :: FinderCache -> HomeUnit -> ModuleName -> ModLocation -> IO Module
    addHomeModuleToFinder :: FinderCache -> HomeUnit -> ModuleName -> ModLocation -> IO Module
    addHomeModuleToFinder FinderCache
    fc HomeUnit
    home_unit ModuleName
    mod_name ModLocation
    loc = do
      let mod :: InstalledModule
    mod = HomeUnit -> ModuleName -> InstalledModule
    forall u. GenHomeUnit u -> ModuleName -> InstalledModule
    mkHomeInstalledModule HomeUnit
    home_unit ModuleName
    mod_name
      FinderCache -> InstalledModule -> InstalledFindResult -> IO ()
    addToFinderCache FinderCache
    fc InstalledModule
    mod (ModLocation -> InstalledModule -> InstalledFindResult
    InstalledFound ModLocation
    loc InstalledModule
    mod)
      Module -> IO Module
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (HomeUnit -> ModuleName -> Module
    mkHomeModule HomeUnit
    home_unit ModuleName
    mod_name)

    uncacheModule :: FinderCache -> HomeUnit -> ModuleName -> IO ()
    uncacheModule :: FinderCache -> HomeUnit -> ModuleName -> IO ()
    uncacheModule FinderCache
    fc HomeUnit
    home_unit ModuleName
    mod_name = do
      let mod :: InstalledModule
    mod = HomeUnit -> ModuleName -> InstalledModule
    forall u. GenHomeUnit u -> ModuleName -> InstalledModule
    mkHomeInstalledModule HomeUnit
    home_unit ModuleName
    mod_name
      FinderCache -> InstalledModule -> IO ()
    removeFromFinderCache FinderCache
    fc InstalledModule
    mod

    -- -----------------------------------------------------------------------------
    --      The internal workers

    findHomeModule :: FinderCache -> FinderOpts -> HomeUnit -> ModuleName -> IO FindResult
    findHomeModule :: FinderCache
    -> FinderOpts -> HomeUnit -> ModuleName -> IO FindResult
    findHomeModule FinderCache
    fc FinderOpts
    fopts  HomeUnit
    home_unit ModuleName
    mod_name = do
      let uid :: Unit
    uid       = HomeUnit -> Unit
    homeUnitAsUnit HomeUnit
    home_unit
      r <- FinderCache
    -> FinderOpts -> UnitId -> ModuleName -> IO InstalledFindResult
    findInstalledHomeModule FinderCache
    fc FinderOpts
    fopts (HomeUnit -> UnitId
    forall u. GenHomeUnit u -> UnitId
    homeUnitId HomeUnit
    home_unit) ModuleName
    mod_name
      return $ case r of
        InstalledFound ModLocation
    loc InstalledModule
    _ -> ModLocation -> Module -> FindResult
    Found ModLocation
    loc (HomeUnit -> ModuleName -> Module
    mkHomeModule HomeUnit
    home_unit ModuleName
    mod_name)
        InstalledNoPackage UnitId
    _ -> Unit -> FindResult
    NoPackage Unit
    uid -- impossible
        InstalledNotFound [FilePath]
    fps Maybe UnitId
    _ -> NotFound {
            fr_paths :: [FilePath]
    fr_paths = [FilePath]
    fps,
            fr_pkg :: Maybe Unit
    fr_pkg = Unit -> Maybe Unit
    forall a. a -> Maybe a
    Just Unit
    uid,
            fr_mods_hidden :: [Unit]
    fr_mods_hidden = [],
            fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = [],
            fr_unusables :: [UnusableUnit]
    fr_unusables = [],
            fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = []
          }

    mkHomeHidden :: UnitId -> FindResult
    mkHomeHidden :: UnitId -> FindResult
    mkHomeHidden UnitId
    uid =
      NotFound { fr_paths :: [FilePath]
    fr_paths = []
               , fr_pkg :: Maybe Unit
    fr_pkg = Unit -> Maybe Unit
    forall a. a -> Maybe a
    Just (Definite UnitId -> Unit
    forall uid. Definite uid -> GenUnit uid
    RealUnit (UnitId -> Definite UnitId
    forall unit. unit -> Definite unit
    Definite UnitId
    uid))
               , fr_mods_hidden :: [Unit]
    fr_mods_hidden = [Definite UnitId -> Unit
    forall uid. Definite uid -> GenUnit uid
    RealUnit (UnitId -> Definite UnitId
    forall unit. unit -> Definite unit
    Definite UnitId
    uid)]
               , fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = []
               , fr_unusables :: [UnusableUnit]
    fr_unusables = []
               , fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = []}

    findHomePackageModule :: FinderCache -> FinderOpts -> UnitId -> ModuleName -> IO FindResult
    findHomePackageModule :: FinderCache -> FinderOpts -> UnitId -> ModuleName -> IO FindResult
    findHomePackageModule FinderCache
    fc FinderOpts
    fopts  UnitId
    home_unit ModuleName
    mod_name = do
      let uid :: Unit
    uid       = Definite UnitId -> Unit
    forall uid. Definite uid -> GenUnit uid
    RealUnit (UnitId -> Definite UnitId
    forall unit. unit -> Definite unit
    Definite UnitId
    home_unit)
      r <- FinderCache
    -> FinderOpts -> UnitId -> ModuleName -> IO InstalledFindResult
    findInstalledHomeModule FinderCache
    fc FinderOpts
    fopts UnitId
    home_unit ModuleName
    mod_name
      return $ case r of
        InstalledFound ModLocation
    loc InstalledModule
    _ -> ModLocation -> Module -> FindResult
    Found ModLocation
    loc (Unit -> ModuleName -> Module
    forall u. u -> ModuleName -> GenModule u
    mkModule Unit
    uid ModuleName
    mod_name)
        InstalledNoPackage UnitId
    _ -> Unit -> FindResult
    NoPackage Unit
    uid -- impossible
        InstalledNotFound [FilePath]
    fps Maybe UnitId
    _ -> NotFound {
            fr_paths :: [FilePath]
    fr_paths = [FilePath]
    fps,
            fr_pkg :: Maybe Unit
    fr_pkg = Unit -> Maybe Unit
    forall a. a -> Maybe a
    Just Unit
    uid,
            fr_mods_hidden :: [Unit]
    fr_mods_hidden = [],
            fr_pkgs_hidden :: [Unit]
    fr_pkgs_hidden = [],
            fr_unusables :: [UnusableUnit]
    fr_unusables = [],
            fr_suggestions :: [ModuleSuggestion]
    fr_suggestions = []
          }

    -- | Implements the search for a module name in the home package only.  Calling
    -- this function directly is usually *not* what you want; currently, it's used
    -- as a building block for the following operations:
    --
    --  1. When you do a normal package lookup, we first check if the module
    --  is available in the home module, before looking it up in the package
    --  database.
    --
    --  2. When you have a package qualified import with package name "this",
    --  we shortcut to the home module.
    --
    --  3. When we look up an exact 'Module', if the unit id associated with
    --  the module is the current home module do a look up in the home module.
    --
    --  4. Some special-case code in GHCi (ToDo: Figure out why that needs to
    --  call this.)
    findInstalledHomeModule :: FinderCache -> FinderOpts -> UnitId -> ModuleName -> IO InstalledFindResult
    findInstalledHomeModule :: FinderCache
    -> FinderOpts -> UnitId -> ModuleName -> IO InstalledFindResult
    findInstalledHomeModule FinderCache
    fc FinderOpts
    fopts UnitId
    home_unit ModuleName
    mod_name = do
      FinderCache
    -> UnitId
    -> ModuleName
    -> IO InstalledFindResult
    -> IO InstalledFindResult
    homeSearchCache FinderCache
    fc UnitId
    home_unit ModuleName
    mod_name (IO InstalledFindResult -> IO InstalledFindResult)
    -> IO InstalledFindResult -> IO InstalledFindResult
    forall a b. (a -> b) -> a -> b
    $
       let
         maybe_working_dir :: Maybe FilePath
    maybe_working_dir = FinderOpts -> Maybe FilePath
    finder_workingDirectory FinderOpts
    fopts
         home_path :: [FilePath]
    home_path = case Maybe FilePath
    maybe_working_dir of
                      Maybe FilePath
    Nothing -> FinderOpts -> [FilePath]
    finder_importPaths FinderOpts
    fopts
                      Just FilePath
    fp -> FilePath -> [FilePath] -> [FilePath]
    augmentImports FilePath
    fp (FinderOpts -> [FilePath]
    finder_importPaths FinderOpts
    fopts)
         hi_dir_path :: [FilePath]
    hi_dir_path =
          case FinderOpts -> Maybe FilePath
    finder_hiDir FinderOpts
    fopts of
            Just FilePath
    hiDir -> case Maybe FilePath
    maybe_working_dir of
                            Maybe FilePath
    Nothing -> [FilePath
    hiDir]
                            Just FilePath
    fp -> [FilePath
    fp FilePath -> FilePath -> FilePath
    </> FilePath
    hiDir]
            Maybe FilePath
    Nothing -> [FilePath]
    home_path
         hisuf :: FilePath
    hisuf = FinderOpts -> FilePath
    finder_hiSuf FinderOpts
    fopts
         mod :: InstalledModule
    mod = UnitId -> ModuleName -> InstalledModule
    forall u. u -> ModuleName -> GenModule u
    mkModule UnitId
    home_unit ModuleName
    mod_name

         source_exts :: [(FilePath, FilePath -> FilePath -> ModLocation)]
    source_exts =
          [ (FilePath
    "hs",    FinderOpts
    -> ModuleName -> FilePath -> FilePath -> FilePath -> ModLocation
    mkHomeModLocationSearched FinderOpts
    fopts ModuleName
    mod_name FilePath
    "hs")
          , (FilePath
    "lhs",   FinderOpts
    -> ModuleName -> FilePath -> FilePath -> FilePath -> ModLocation
    mkHomeModLocationSearched FinderOpts
    fopts ModuleName
    mod_name FilePath
    "lhs")
          , (FilePath
    "hsig",  FinderOpts
    -> ModuleName -> FilePath -> FilePath -> FilePath -> ModLocation
    mkHomeModLocationSearched FinderOpts
    fopts ModuleName
    mod_name FilePath
    "hsig")
          , (FilePath
    "lhsig", FinderOpts
    -> ModuleName -> FilePath -> FilePath -> FilePath -> ModLocation
    mkHomeModLocationSearched FinderOpts
    fopts ModuleName
    mod_name FilePath
    "lhsig")
          ]

         -- we use mkHomeModHiOnlyLocation instead of mkHiOnlyModLocation so that
         -- when hiDir field is set in dflags, we know to look there (see #16500)
         hi_exts :: [(FilePath, FilePath -> FilePath -> ModLocation)]
    hi_exts = [ (FilePath
    hisuf,                FinderOpts -> ModuleName -> FilePath -> FilePath -> ModLocation
    mkHomeModHiOnlyLocation FinderOpts
    fopts ModuleName
    mod_name)
                   , (FilePath -> FilePath
    addBootSuffix FilePath
    hisuf,  FinderOpts -> ModuleName -> FilePath -> FilePath -> ModLocation
    mkHomeModHiOnlyLocation FinderOpts
    fopts ModuleName
    mod_name)
                   ]

            -- In compilation manager modes, we look for source files in the home
            -- package because we can compile these automatically.  In one-shot
            -- compilation mode we look for .hi and .hi-boot files only.
         ([FilePath]
    search_dirs, [(FilePath, FilePath -> FilePath -> ModLocation)]
    exts)
              | FinderOpts -> Bool
    finder_lookupHomeInterfaces FinderOpts
    fopts = ([FilePath]
    hi_dir_path, [(FilePath, FilePath -> FilePath -> ModLocation)]
    hi_exts)
              | Bool
    otherwise                         = ([FilePath]
    home_path, [(FilePath, FilePath -> FilePath -> ModLocation)]
    source_exts)
       in

       -- special case for GHC.Prim; we won't find it in the filesystem.
       -- This is important only when compiling the base package (where GHC.Prim
       -- is a home module).
       if InstalledModule
    mod InstalledModule -> Module -> Bool
    `installedModuleEq` Module
    gHC_PRIM
             then InstalledFindResult -> IO InstalledFindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ModLocation -> InstalledModule -> InstalledFindResult
    InstalledFound (FilePath -> ModLocation
    forall a. HasCallStack => FilePath -> a
    error FilePath
    "GHC.Prim ModLocation") InstalledModule
    mod)
             else [FilePath]
    -> InstalledModule
    -> [(FilePath, FilePath -> FilePath -> ModLocation)]
    -> IO InstalledFindResult
    searchPathExts [FilePath]
    search_dirs InstalledModule
    mod [(FilePath, FilePath -> FilePath -> ModLocation)]
    exts

    -- | Prepend the working directory to the search path.
    augmentImports :: FilePath -> [FilePath] -> [FilePath]
    augmentImports :: FilePath -> [FilePath] -> [FilePath]
    augmentImports FilePath
    _work_dir [] = []
    augmentImports FilePath
    work_dir (FilePath
    fp:[FilePath]
    fps) | FilePath -> Bool
    isAbsolute FilePath
    fp = FilePath
    fp FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : FilePath -> [FilePath] -> [FilePath]
    augmentImports FilePath
    work_dir [FilePath]
    fps
                                     | Bool
    otherwise     = (FilePath
    work_dir FilePath -> FilePath -> FilePath
    </> FilePath
    fp) FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : FilePath -> [FilePath] -> [FilePath]
    augmentImports FilePath
    work_dir [FilePath]
    fps

    -- | Search for a module in external packages only.
    findPackageModule :: FinderCache -> UnitState -> FinderOpts -> InstalledModule -> IO InstalledFindResult
    findPackageModule :: FinderCache
    -> UnitState
    -> FinderOpts
    -> InstalledModule
    -> IO InstalledFindResult
    findPackageModule FinderCache
    fc UnitState
    unit_state FinderOpts
    fopts InstalledModule
    mod = do
      let pkg_id :: UnitId
    pkg_id = InstalledModule -> UnitId
    forall unit. GenModule unit -> unit
    moduleUnit InstalledModule
    mod
      case UnitState -> UnitId -> Maybe UnitInfo
    lookupUnitId UnitState
    unit_state UnitId
    pkg_id of
         Maybe UnitInfo
    Nothing -> InstalledFindResult -> IO InstalledFindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (UnitId -> InstalledFindResult
    InstalledNoPackage UnitId
    pkg_id)
         Just UnitInfo
    u  -> FinderCache
    -> FinderOpts
    -> InstalledModule
    -> UnitInfo
    -> IO InstalledFindResult
    findPackageModule_ FinderCache
    fc FinderOpts
    fopts InstalledModule
    mod UnitInfo
    u

    -- | Look up the interface file associated with module @mod@.  This function
    -- requires a few invariants to be upheld: (1) the 'Module' in question must
    -- be the module identifier of the *original* implementation of a module,
    -- not a reexport (this invariant is upheld by "GHC.Unit.State") and (2)
    -- the 'UnitInfo' must be consistent with the unit id in the 'Module'.
    -- The redundancy is to avoid an extra lookup in the package state
    -- for the appropriate config.
    findPackageModule_ :: FinderCache -> FinderOpts -> InstalledModule -> UnitInfo -> IO InstalledFindResult
    findPackageModule_ :: FinderCache
    -> FinderOpts
    -> InstalledModule
    -> UnitInfo
    -> IO InstalledFindResult
    findPackageModule_ FinderCache
    fc FinderOpts
    fopts InstalledModule
    mod UnitInfo
    pkg_conf = do
      Bool -> SDoc -> IO ()
    forall (m :: * -> *).
    (HasCallStack, Applicative m) =>
    Bool -> SDoc -> m ()
    massertPpr (InstalledModule -> UnitId
    forall unit. GenModule unit -> unit
    moduleUnit InstalledModule
    mod UnitId -> UnitId -> Bool
    forall a. Eq a => a -> a -> Bool
    == UnitInfo -> UnitId
    forall srcpkgid srcpkgname uid modulename mod.
    GenericUnitInfo srcpkgid srcpkgname uid modulename mod -> uid
    unitId UnitInfo
    pkg_conf)
                 (UnitId -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (InstalledModule -> UnitId
    forall unit. GenModule unit -> unit
    moduleUnit InstalledModule
    mod) SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> UnitId -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (UnitInfo -> UnitId
    forall srcpkgid srcpkgname uid modulename mod.
    GenericUnitInfo srcpkgid srcpkgname uid modulename mod -> uid
    unitId UnitInfo
    pkg_conf))
      FinderCache
    -> InstalledModule
    -> IO InstalledFindResult
    -> IO InstalledFindResult
    modLocationCache FinderCache
    fc InstalledModule
    mod (IO InstalledFindResult -> IO InstalledFindResult)
    -> IO InstalledFindResult -> IO InstalledFindResult
    forall a b. (a -> b) -> a -> b
    $

        -- special case for GHC.Prim; we won't find it in the filesystem.
        if InstalledModule
    mod InstalledModule -> Module -> Bool
    `installedModuleEq` Module
    gHC_PRIM
              then InstalledFindResult -> IO InstalledFindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ModLocation -> InstalledModule -> InstalledFindResult
    InstalledFound (FilePath -> ModLocation
    forall a. HasCallStack => FilePath -> a
    error FilePath
    "GHC.Prim ModLocation") InstalledModule
    mod)
              else

        let
           tag :: FilePath
    tag = Ways -> FilePath
    waysBuildTag (FinderOpts -> Ways
    finder_ways FinderOpts
    fopts)

                 -- hi-suffix for packages depends on the build tag.
           package_hisuf :: FilePath
    package_hisuf | FilePath -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null FilePath
    tag  = FilePath
    "hi"
                         | Bool
    otherwise = FilePath
    tag FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    "_hi"

           package_dynhisuf :: FilePath
    package_dynhisuf = Ways -> FilePath
    waysBuildTag (Way -> Ways -> Ways
    addWay Way
    WayDyn (FinderOpts -> Ways
    finder_ways FinderOpts
    fopts)) FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    "_hi"

           mk_hi_loc :: FilePath -> FilePath -> ModLocation
    mk_hi_loc = FinderOpts
    -> FilePath -> FilePath -> FilePath -> FilePath -> ModLocation
    mkHiOnlyModLocation FinderOpts
    fopts FilePath
    package_hisuf FilePath
    package_dynhisuf

           import_dirs :: [FilePath]
    import_dirs = (FilePathST -> FilePath) -> [FilePathST] -> [FilePath]
    forall a b. (a -> b) -> [a] -> [b]
    map FilePathST -> FilePath
    ST.unpack ([FilePathST] -> [FilePath]) -> [FilePathST] -> [FilePath]
    forall a b. (a -> b) -> a -> b
    $ UnitInfo -> [FilePathST]
    forall srcpkgid srcpkgname uid modulename mod.
    GenericUnitInfo srcpkgid srcpkgname uid modulename mod
    -> [FilePathST]
    unitImportDirs UnitInfo
    pkg_conf
            -- we never look for a .hi-boot file in an external package;
            -- .hi-boot files only make sense for the home package.
        in
        case [FilePath]
    import_dirs of
          [FilePath
    one] | FinderOpts -> Bool
    finder_bypassHiFileCheck FinderOpts
    fopts ->
                -- there's only one place that this .hi file can be, so
                -- don't bother looking for it.
                let basename :: FilePath
    basename = ModuleName -> FilePath
    moduleNameSlashes (InstalledModule -> ModuleName
    forall unit. GenModule unit -> ModuleName
    moduleName InstalledModule
    mod)
                    loc :: ModLocation
    loc = FilePath -> FilePath -> ModLocation
    mk_hi_loc FilePath
    one FilePath
    basename
                in InstalledFindResult -> IO InstalledFindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (InstalledFindResult -> IO InstalledFindResult)
    -> InstalledFindResult -> IO InstalledFindResult
    forall a b. (a -> b) -> a -> b
    $ ModLocation -> InstalledModule -> InstalledFindResult
    InstalledFound ModLocation
    loc InstalledModule
    mod
          [FilePath]
    _otherwise ->
                [FilePath]
    -> InstalledModule
    -> [(FilePath, FilePath -> FilePath -> ModLocation)]
    -> IO InstalledFindResult
    searchPathExts [FilePath]
    import_dirs InstalledModule
    mod [(FilePath
    package_hisuf, FilePath -> FilePath -> ModLocation
    mk_hi_loc)]

    -- -----------------------------------------------------------------------------
    -- General path searching

    searchPathExts :: [FilePath]      -- paths to search
                   -> InstalledModule -- module name
                   -> [ (
                         FileExt,                             -- suffix
                         FilePath -> BaseName -> ModLocation  -- action
                        )
                      ]
                   -> IO InstalledFindResult

    searchPathExts :: [FilePath]
    -> InstalledModule
    -> [(FilePath, FilePath -> FilePath -> ModLocation)]
    -> IO InstalledFindResult
    searchPathExts [FilePath]
    paths InstalledModule
    mod [(FilePath, FilePath -> FilePath -> ModLocation)]
    exts = [(FilePath, ModLocation)] -> IO InstalledFindResult
    search [(FilePath, ModLocation)]
    to_search
      where
        basename :: FilePath
    basename = ModuleName -> FilePath
    moduleNameSlashes (InstalledModule -> ModuleName
    forall unit. GenModule unit -> ModuleName
    moduleName InstalledModule
    mod)

        to_search :: [(FilePath, ModLocation)]
        to_search :: [(FilePath, ModLocation)]
    to_search = [ (FilePath
    file, FilePath -> FilePath -> ModLocation
    fn FilePath
    path FilePath
    basename)
                    | FilePath
    path <- [FilePath]
    paths,
                      (FilePath
    ext,FilePath -> FilePath -> ModLocation
    fn) <- [(FilePath, FilePath -> FilePath -> ModLocation)]
    exts,
                      let base :: FilePath
    base | FilePath
    path FilePath -> FilePath -> Bool
    forall a. Eq a => a -> a -> Bool
    == FilePath
    "." = FilePath
    basename
                               | Bool
    otherwise   = FilePath
    path FilePath -> FilePath -> FilePath
    </> FilePath
    basename
                          file :: FilePath
    file = FilePath
    base FilePath -> FilePath -> FilePath
    <.> FilePath
    ext
                    ]

        search :: [(FilePath, ModLocation)] -> IO InstalledFindResult
    search [] = InstalledFindResult -> IO InstalledFindResult
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([FilePath] -> Maybe UnitId -> InstalledFindResult
    InstalledNotFound (((FilePath, ModLocation) -> FilePath)
    -> [(FilePath, ModLocation)] -> [FilePath]
    forall a b. (a -> b) -> [a] -> [b]
    map (FilePath, ModLocation) -> FilePath
    forall a b. (a, b) -> a
    fst [(FilePath, ModLocation)]
    to_search) (UnitId -> Maybe UnitId
    forall a. a -> Maybe a
    Just (InstalledModule -> UnitId
    forall unit. GenModule unit -> unit
    moduleUnit InstalledModule
    mod)))

        search ((FilePath
    file, ModLocation
    loc) : [(FilePath, ModLocation)]
    rest) = do
          b <- FilePath -> IO Bool
    doesFileExist FilePath
    file
          if b
            then return $ InstalledFound loc mod
            else search rest

    mkHomeModLocationSearched :: FinderOpts -> ModuleName -> FileExt
                              -> FilePath -> BaseName -> ModLocation
    mkHomeModLocationSearched :: FinderOpts
    -> ModuleName -> FilePath -> FilePath -> FilePath -> ModLocation
    mkHomeModLocationSearched FinderOpts
    fopts ModuleName
    mod FilePath
    suff FilePath
    path FilePath
    basename =
      FinderOpts -> ModuleName -> FilePath -> FilePath -> ModLocation
    mkHomeModLocation2 FinderOpts
    fopts ModuleName
    mod (FilePath
    path FilePath -> FilePath -> FilePath
    </> FilePath
    basename) FilePath
    suff

    -- -----------------------------------------------------------------------------
    -- Constructing a home module location

    -- This is where we construct the ModLocation for a module in the home
    -- package, for which we have a source file.  It is called from three
    -- places:
    --
    --  (a) Here in the finder, when we are searching for a module to import,
    --      using the search path (-i option).
    --
    --  (b) The compilation manager, when constructing the ModLocation for
    --      a "root" module (a source file named explicitly on the command line
    --      or in a :load command in GHCi).
    --
    --  (c) The driver in one-shot mode, when we need to construct a
    --      ModLocation for a source file named on the command-line.
    --
    -- Parameters are:
    --
    -- mod
    --      The name of the module
    --
    -- path
    --      (a): The search path component where the source file was found.
    --      (b) and (c): "."
    --
    -- src_basename
    --      (a): (moduleNameSlashes mod)
    --      (b) and (c): The filename of the source file, minus its extension
    --
    -- ext
    --      The filename extension of the source file (usually "hs" or "lhs").

    mkHomeModLocation :: FinderOpts -> ModuleName -> FilePath -> ModLocation
    mkHomeModLocation :: FinderOpts -> ModuleName -> FilePath -> ModLocation
    mkHomeModLocation FinderOpts
    dflags ModuleName
    mod FilePath
    src_filename =
       let (FilePath
    basename,FilePath
    extension) = FilePath -> (FilePath, FilePath)
    splitExtension FilePath
    src_filename
       in FinderOpts -> ModuleName -> FilePath -> FilePath -> ModLocation
    mkHomeModLocation2 FinderOpts
    dflags ModuleName
    mod FilePath
    basename FilePath
    extension

    mkHomeModLocation2 :: FinderOpts
                       -> ModuleName
                       -> FilePath  -- Of source module, without suffix
                       -> String    -- Suffix
                       -> ModLocation
    mkHomeModLocation2 :: FinderOpts -> ModuleName -> FilePath -> FilePath -> ModLocation
    mkHomeModLocation2 FinderOpts
    fopts ModuleName
    mod FilePath
    src_basename FilePath
    ext =
       let mod_basename :: FilePath
    mod_basename = ModuleName -> FilePath
    moduleNameSlashes ModuleName
    mod

           obj_fn :: FilePath
    obj_fn = FinderOpts -> FilePath -> FilePath -> FilePath
    mkObjPath  FinderOpts
    fopts FilePath
    src_basename FilePath
    mod_basename
           dyn_obj_fn :: FilePath
    dyn_obj_fn = FinderOpts -> FilePath -> FilePath -> FilePath
    mkDynObjPath  FinderOpts
    fopts FilePath
    src_basename FilePath
    mod_basename
           hi_fn :: FilePath
    hi_fn  = FinderOpts -> FilePath -> FilePath -> FilePath
    mkHiPath   FinderOpts
    fopts FilePath
    src_basename FilePath
    mod_basename
           dyn_hi_fn :: FilePath
    dyn_hi_fn  = FinderOpts -> FilePath -> FilePath -> FilePath
    mkDynHiPath   FinderOpts
    fopts FilePath
    src_basename FilePath
    mod_basename
           hie_fn :: FilePath
    hie_fn = FinderOpts -> FilePath -> FilePath -> FilePath
    mkHiePath  FinderOpts
    fopts FilePath
    src_basename FilePath
    mod_basename

       in (ModLocation{ ml_hs_file :: Maybe FilePath
    ml_hs_file   = FilePath -> Maybe FilePath
    forall a. a -> Maybe a
    Just (FilePath
    src_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    ext),
                            ml_hi_file :: FilePath
    ml_hi_file   = FilePath
    hi_fn,
                            ml_dyn_hi_file :: FilePath
    ml_dyn_hi_file = FilePath
    dyn_hi_fn,
                            ml_obj_file :: FilePath
    ml_obj_file  = FilePath
    obj_fn,
                            ml_dyn_obj_file :: FilePath
    ml_dyn_obj_file = FilePath
    dyn_obj_fn,
                            ml_hie_file :: FilePath
    ml_hie_file  = FilePath
    hie_fn })

    mkHomeModHiOnlyLocation :: FinderOpts
                            -> ModuleName
                            -> FilePath
                            -> BaseName
                            -> ModLocation
    mkHomeModHiOnlyLocation :: FinderOpts -> ModuleName -> FilePath -> FilePath -> ModLocation
    mkHomeModHiOnlyLocation FinderOpts
    fopts ModuleName
    mod FilePath
    path FilePath
    basename =
       let loc :: ModLocation
    loc = FinderOpts -> ModuleName -> FilePath -> FilePath -> ModLocation
    mkHomeModLocation2 FinderOpts
    fopts ModuleName
    mod (FilePath
    path FilePath -> FilePath -> FilePath
    </> FilePath
    basename) FilePath
    ""
       in ModLocation
    loc { ml_hs_file = Nothing }

    -- This function is used to make a ModLocation for a package module. Hence why
    -- we explicitly pass in the interface file suffixes.
    mkHiOnlyModLocation :: FinderOpts -> Suffix -> Suffix -> FilePath -> String
                        -> ModLocation
    mkHiOnlyModLocation :: FinderOpts
    -> FilePath -> FilePath -> FilePath -> FilePath -> ModLocation
    mkHiOnlyModLocation FinderOpts
    fopts FilePath
    hisuf FilePath
    dynhisuf FilePath
    path FilePath
    basename
     = let full_basename :: FilePath
    full_basename = FilePath
    path FilePath -> FilePath -> FilePath
    </> FilePath
    basename
           obj_fn :: FilePath
    obj_fn = FinderOpts -> FilePath -> FilePath -> FilePath
    mkObjPath FinderOpts
    fopts FilePath
    full_basename FilePath
    basename
           dyn_obj_fn :: FilePath
    dyn_obj_fn = FinderOpts -> FilePath -> FilePath -> FilePath
    mkDynObjPath FinderOpts
    fopts FilePath
    full_basename FilePath
    basename
           hie_fn :: FilePath
    hie_fn = FinderOpts -> FilePath -> FilePath -> FilePath
    mkHiePath FinderOpts
    fopts FilePath
    full_basename FilePath
    basename
       in ModLocation{    ml_hs_file :: Maybe FilePath
    ml_hs_file   = Maybe FilePath
    forall a. Maybe a
    Nothing,
                                 ml_hi_file :: FilePath
    ml_hi_file   = FilePath
    full_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    hisuf,
                                    -- Remove the .hi-boot suffix from
                                    -- hi_file, if it had one.  We always
                                    -- want the name of the real .hi file
                                    -- in the ml_hi_file field.
                                 ml_dyn_obj_file :: FilePath
    ml_dyn_obj_file = FilePath
    dyn_obj_fn,
                                 -- MP: TODO
                                 ml_dyn_hi_file :: FilePath
    ml_dyn_hi_file  = FilePath
    full_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    dynhisuf,
                                 ml_obj_file :: FilePath
    ml_obj_file  = FilePath
    obj_fn,
                                 ml_hie_file :: FilePath
    ml_hie_file  = FilePath
    hie_fn
                      }

    -- | Constructs the filename of a .o file for a given source file.
    -- Does /not/ check whether the .o file exists
    mkObjPath
      :: FinderOpts
      -> FilePath           -- the filename of the source file, minus the extension
      -> String             -- the module name with dots replaced by slashes
      -> FilePath
    mkObjPath :: FinderOpts -> FilePath -> FilePath -> FilePath
    mkObjPath FinderOpts
    fopts FilePath
    basename FilePath
    mod_basename = FilePath
    obj_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    osuf
      where
                    odir :: Maybe FilePath
    odir = FinderOpts -> Maybe FilePath
    finder_objectDir FinderOpts
    fopts
                    osuf :: FilePath
    osuf = FinderOpts -> FilePath
    finder_objectSuf FinderOpts
    fopts

                    obj_basename :: FilePath
    obj_basename | Just FilePath
    dir <- Maybe FilePath
    odir = FilePath
    dir FilePath -> FilePath -> FilePath
    </> FilePath
    mod_basename
                                 | Bool
    otherwise        = FilePath
    basename

    -- | Constructs the filename of a .dyn_o file for a given source file.
    -- Does /not/ check whether the .dyn_o file exists
    mkDynObjPath
      :: FinderOpts
      -> FilePath           -- the filename of the source file, minus the extension
      -> String             -- the module name with dots replaced by slashes
      -> FilePath
    mkDynObjPath :: FinderOpts -> FilePath -> FilePath -> FilePath
    mkDynObjPath FinderOpts
    fopts FilePath
    basename FilePath
    mod_basename = FilePath
    obj_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    dynosuf
      where
                    odir :: Maybe FilePath
    odir = FinderOpts -> Maybe FilePath
    finder_objectDir FinderOpts
    fopts
                    dynosuf :: FilePath
    dynosuf = FinderOpts -> FilePath
    finder_dynObjectSuf FinderOpts
    fopts

                    obj_basename :: FilePath
    obj_basename | Just FilePath
    dir <- Maybe FilePath
    odir = FilePath
    dir FilePath -> FilePath -> FilePath
    </> FilePath
    mod_basename
                                 | Bool
    otherwise        = FilePath
    basename

    -- | Constructs the filename of a .hi file for a given source file.
    -- Does /not/ check whether the .hi file exists
    mkHiPath
      :: FinderOpts
      -> FilePath           -- the filename of the source file, minus the extension
      -> String             -- the module name with dots replaced by slashes
      -> FilePath
    mkHiPath :: FinderOpts -> FilePath -> FilePath -> FilePath
    mkHiPath FinderOpts
    fopts FilePath
    basename FilePath
    mod_basename = FilePath
    hi_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    hisuf
     where
                    hidir :: Maybe FilePath
    hidir = FinderOpts -> Maybe FilePath
    finder_hiDir FinderOpts
    fopts
                    hisuf :: FilePath
    hisuf = FinderOpts -> FilePath
    finder_hiSuf FinderOpts
    fopts

                    hi_basename :: FilePath
    hi_basename | Just FilePath
    dir <- Maybe FilePath
    hidir = FilePath
    dir FilePath -> FilePath -> FilePath
    </> FilePath
    mod_basename
                                | Bool
    otherwise         = FilePath
    basename

    -- | Constructs the filename of a .dyn_hi file for a given source file.
    -- Does /not/ check whether the .dyn_hi file exists
    mkDynHiPath
      :: FinderOpts
      -> FilePath           -- the filename of the source file, minus the extension
      -> String             -- the module name with dots replaced by slashes
      -> FilePath
    mkDynHiPath :: FinderOpts -> FilePath -> FilePath -> FilePath
    mkDynHiPath FinderOpts
    fopts FilePath
    basename FilePath
    mod_basename = FilePath
    hi_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    dynhisuf
     where
                    hidir :: Maybe FilePath
    hidir = FinderOpts -> Maybe FilePath
    finder_hiDir FinderOpts
    fopts
                    dynhisuf :: FilePath
    dynhisuf = FinderOpts -> FilePath
    finder_dynHiSuf FinderOpts
    fopts

                    hi_basename :: FilePath
    hi_basename | Just FilePath
    dir <- Maybe FilePath
    hidir = FilePath
    dir FilePath -> FilePath -> FilePath
    </> FilePath
    mod_basename
                                | Bool
    otherwise         = FilePath
    basename

    -- | Constructs the filename of a .hie file for a given source file.
    -- Does /not/ check whether the .hie file exists
    mkHiePath
      :: FinderOpts
      -> FilePath           -- the filename of the source file, minus the extension
      -> String             -- the module name with dots replaced by slashes
      -> FilePath
    mkHiePath :: FinderOpts -> FilePath -> FilePath -> FilePath
    mkHiePath FinderOpts
    fopts FilePath
    basename FilePath
    mod_basename = FilePath
    hie_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    hiesuf
     where
                    hiedir :: Maybe FilePath
    hiedir = FinderOpts -> Maybe FilePath
    finder_hieDir FinderOpts
    fopts
                    hiesuf :: FilePath
    hiesuf = FinderOpts -> FilePath
    finder_hieSuf FinderOpts
    fopts

                    hie_basename :: FilePath
    hie_basename | Just FilePath
    dir <- Maybe FilePath
    hiedir = FilePath
    dir FilePath -> FilePath -> FilePath
    </> FilePath
    mod_basename
                                 | Bool
    otherwise          = FilePath
    basename

    -- -----------------------------------------------------------------------------
    -- Filenames of the stub files

    -- We don't have to store these in ModLocations, because they can be derived
    -- from other available information, and they're only rarely needed.

    mkStubPaths
      :: FinderOpts
      -> ModuleName
      -> ModLocation
      -> FilePath

    mkStubPaths :: FinderOpts -> ModuleName -> ModLocation -> FilePath
    mkStubPaths FinderOpts
    fopts ModuleName
    mod ModLocation
    location
      = let
            stubdir :: Maybe FilePath
    stubdir = FinderOpts -> Maybe FilePath
    finder_stubDir FinderOpts
    fopts

            mod_basename :: FilePath
    mod_basename = ModuleName -> FilePath
    moduleNameSlashes ModuleName
    mod
            src_basename :: FilePath
    src_basename = FilePath -> FilePath
    dropExtension (FilePath -> FilePath) -> FilePath -> FilePath
    forall a b. (a -> b) -> a -> b
    $ FilePath -> Maybe FilePath -> FilePath
    forall a. HasCallStack => FilePath -> Maybe a -> a
    expectJust FilePath
    "mkStubPaths"
                                                      (ModLocation -> Maybe FilePath
    ml_hs_file ModLocation
    location)

            stub_basename0 :: FilePath
    stub_basename0
                | Just FilePath
    dir <- Maybe FilePath
    stubdir = FilePath
    dir FilePath -> FilePath -> FilePath
    </> FilePath
    mod_basename
                | Bool
    otherwise           = FilePath
    src_basename

            stub_basename :: FilePath
    stub_basename = FilePath
    stub_basename0 FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    "_stub"
         in
            FilePath
    stub_basename FilePath -> FilePath -> FilePath
    <.> FilePath
    "h"

    -- -----------------------------------------------------------------------------
    -- findLinkable isn't related to the other stuff in here,
    -- but there's no other obvious place for it

    findObjectLinkableMaybe :: Module -> ModLocation -> IO (Maybe Linkable)
    findObjectLinkableMaybe :: Module -> ModLocation -> IO (Maybe Linkable)
    findObjectLinkableMaybe Module
    mod ModLocation
    locn
       = do let obj_fn :: FilePath
    obj_fn = ModLocation -> FilePath
    ml_obj_file ModLocation
    locn
            maybe_obj_time <- FilePath -> IO (Maybe UTCTime)
    modificationTimeIfExists FilePath
    obj_fn
            case maybe_obj_time of
              Maybe UTCTime
    Nothing -> Maybe Linkable -> IO (Maybe Linkable)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe Linkable
    forall a. Maybe a
    Nothing
              Just UTCTime
    obj_time -> (Linkable -> Maybe Linkable) -> IO Linkable -> IO (Maybe Linkable)
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM Linkable -> Maybe Linkable
    forall a. a -> Maybe a
    Just (Module -> FilePath -> UTCTime -> IO Linkable
    findObjectLinkable Module
    mod FilePath
    obj_fn UTCTime
    obj_time)

    -- Make an object linkable when we know the object file exists, and we know
    -- its modification time.
    findObjectLinkable :: Module -> FilePath -> UTCTime -> IO Linkable
    findObjectLinkable :: Module -> FilePath -> UTCTime -> IO Linkable
    findObjectLinkable Module
    mod FilePath
    obj_fn UTCTime
    obj_time = Linkable -> IO Linkable
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (UTCTime -> Module -> [Unlinked] -> Linkable
    LM UTCTime
    obj_time Module
    mod [FilePath -> Unlinked
    DotO FilePath
    obj_fn])
      -- We used to look for _stub.o files here, but that was a bug (#706)
      -- Now GHC merges the stub.o into the main .o (#3687)