GHC/Driver/Env/Types.hs

    {-# LANGUAGE DeriveFunctor #-}
    module GHC.Driver.Env.Types
      ( Hsc(..)
      , HscEnv(..)
      ) where

    import {-# SOURCE #-} GHC.Driver.Hooks
    import GHC.Driver.Session ( DynFlags, HasDynFlags(..) )
    import GHC.Prelude
    import GHC.Runtime.Context
    import GHC.Runtime.Interpreter.Types ( Interp )
    import GHC.Types.Error ( WarningMessages )
    import GHC.Types.Name.Cache
    import GHC.Types.Target
    import GHC.Types.TypeEnv
    import GHC.Unit.External
    import GHC.Unit.Finder.Types
    import GHC.Unit.Home.ModInfo
    import GHC.Unit.Module.Graph
    import GHC.Unit.Env
    import GHC.Unit.State
    import GHC.Unit.Types
    import GHC.Utils.Logger
    import GHC.Utils.TmpFs
    import {-# SOURCE #-} GHC.Driver.Plugins

    import Control.Monad ( ap )
    import Control.Monad.IO.Class
    import Data.IORef

    -- | The Hsc monad: Passing an environment and warning state
    newtype Hsc a = Hsc (HscEnv -> WarningMessages -> IO (a, WarningMessages))
        deriving (Functor)

    instance Applicative Hsc where
        pure a = Hsc $ \_ w -> return (a, w)
        (<*>) = ap

    instance Monad Hsc where
        Hsc m >>= k = Hsc $ \e w -> do (a, w1) <- m e w
                                       case k a of
                                           Hsc k' -> k' e w1

    instance MonadIO Hsc where
        liftIO io = Hsc $ \_ w -> do a <- io; return (a, w)

    instance HasDynFlags Hsc where
        getDynFlags = Hsc $ \e w -> return (hsc_dflags e, w)

    instance HasLogger Hsc where
        getLogger = Hsc $ \e w -> return (hsc_logger e, w)

    -- | HscEnv is like 'GHC.Driver.Monad.Session', except that some of the fields are immutable.
    -- An HscEnv is used to compile a single module from plain Haskell source
    -- code (after preprocessing) to either C, assembly or C--. It's also used
    -- to store the dynamic linker state to allow for multiple linkers in the
    -- same address space.
    -- Things like the module graph don't change during a single compilation.
    --
    -- Historical note: \"hsc\" used to be the name of the compiler binary,
    -- when there was a separate driver and compiler.  To compile a single
    -- module, the driver would invoke hsc on the source code... so nowadays
    -- we think of hsc as the layer of the compiler that deals with compiling
    -- a single module.
    data HscEnv
      = HscEnv {
            hsc_dflags :: DynFlags,
                    -- ^ The dynamic flag settings

            hsc_targets :: [Target],
                    -- ^ The targets (or roots) of the current session

            hsc_mod_graph :: ModuleGraph,
                    -- ^ The module graph of the current session

            hsc_IC :: InteractiveContext,
                    -- ^ The context for evaluating interactive statements

            hsc_HPT    :: HomePackageTable,
                    -- ^ The home package table describes already-compiled
                    -- home-package modules, /excluding/ the module we
                    -- are compiling right now.
                    -- (In one-shot mode the current module is the only
                    -- home-package module, so hsc_HPT is empty.  All other
                    -- modules count as \"external-package\" modules.
                    -- However, even in GHCi mode, hi-boot interfaces are
                    -- demand-loaded into the external-package table.)
                    --
                    -- 'hsc_HPT' is not mutable because we only demand-load
                    -- external packages; the home package is eagerly
                    -- loaded, module by module, by the compilation manager.
                    --
                    -- The HPT may contain modules compiled earlier by @--make@
                    -- but not actually below the current module in the dependency
                    -- graph.
                    --
                    -- (This changes a previous invariant: changed Jan 05.)

            hsc_EPS :: {-# UNPACK #-} !(IORef ExternalPackageState),
                    -- ^ Information about the currently loaded external packages.
                    -- This is mutable because packages will be demand-loaded during
                    -- a compilation run as required.

            hsc_NC  :: {-# UNPACK #-} !(IORef NameCache),
                    -- ^ As with 'hsc_EPS', this is side-effected by compiling to
                    -- reflect sucking in interface files.  They cache the state of
                    -- external interface files, in effect.

            hsc_FC   :: {-# UNPACK #-} !(IORef FinderCache),
                    -- ^ The cached result of performing finding in the file system

            hsc_type_env_var :: Maybe (Module, IORef TypeEnv)
                    -- ^ Used for one-shot compilation only, to initialise
                    -- the 'IfGblEnv'. See 'GHC.Tc.Utils.tcg_type_env_var' for
                    -- 'GHC.Tc.Utils.TcGblEnv'.  See also Note [hsc_type_env_var hack]

            , hsc_interp :: Maybe Interp
                    -- ^ target code interpreter (if any) to use for TH and GHCi.
                    -- See Note [Target code interpreter]

            , hsc_plugins :: ![LoadedPlugin]
                    -- ^ plugins dynamically loaded after processing arguments. What
                    -- will be loaded here is directed by DynFlags.pluginModNames.
                    -- Arguments are loaded from DynFlags.pluginModNameOpts.
                    --
                    -- The purpose of this field is to cache the plugins so they
                    -- don't have to be loaded each time they are needed.  See
                    -- 'GHC.Runtime.Loader.initializePlugins'.

            , hsc_static_plugins :: ![StaticPlugin]
                    -- ^ static plugins which do not need dynamic loading. These plugins are
                    -- intended to be added by GHC API users directly to this list.
                    --
                    -- To add dynamically loaded plugins through the GHC API see
                    -- 'addPluginModuleName' instead.

            , hsc_unit_dbs :: !(Maybe [UnitDatabase UnitId])
                    -- ^ Stack of unit databases for the target platform.
                    --
                    -- This field is populated with the result of `initUnits`.
                    --
                    -- 'Nothing' means the databases have never been read from disk.
                    --
                    -- Usually we don't reload the databases from disk if they are
                    -- cached, even if the database flags changed!

            , hsc_unit_env :: UnitEnv
                    -- ^ Unit environment (unit state, home unit, etc.).
                    --
                    -- Initialized from the databases cached in 'hsc_unit_dbs' and
                    -- from the DynFlags.

            , hsc_logger :: !Logger
                    -- ^ Logger

            , hsc_hooks :: !Hooks
                    -- ^ Hooks

            , hsc_tmpfs :: !TmpFs
                    -- ^ Temporary files
     }