-- | Info about modules in the "home" unit.
-- Stored in a 'HomePackageTable'.
module GHC.Unit.Home.ModInfo
   (
     HomeModInfo (..)
   , homeModInfoObject
   , homeModInfoByteCode
   , HomeModLinkable (..)
   , homeModLinkableByteCode
   , homeModLinkableObject
   , emptyHomeModInfoLinkable
   )
where

import GHC.Prelude

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

import GHC.Linker.Types ( Linkable, LinkableWith, ModuleByteCode, LinkablePart (..) )

import GHC.Utils.Outputable
import qualified Data.List.NonEmpty as NE

-- | 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 -> HomeModLinkable
hm_linkable :: !HomeModLinkable
        -- ^ The actual artifact we would like to link to access things in
        -- this module. See Note [Home module build products]
        --
        -- 'hm_linkable' might be empty:
        --
        --   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.
        --
        -- When re-linking a module ('GHC.Driver.Main.HscNoRecomp'), we construct the
        -- 'HomeModInfo' by building a new 'ModDetails' from the old
        -- 'ModIface' (only).
   }

homeModInfoByteCode :: HomeModInfo -> Maybe Linkable
homeModInfoByteCode :: HomeModInfo -> Maybe Linkable
homeModInfoByteCode = HomeModLinkable -> Maybe Linkable
homeModLinkableByteCode (HomeModLinkable -> Maybe Linkable)
-> (HomeModInfo -> HomeModLinkable)
-> HomeModInfo
-> Maybe Linkable
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HomeModInfo -> HomeModLinkable
hm_linkable

homeModInfoObject :: HomeModInfo -> Maybe Linkable
homeModInfoObject :: HomeModInfo -> Maybe Linkable
homeModInfoObject = HomeModLinkable -> Maybe Linkable
homeModLinkableObject (HomeModLinkable -> Maybe Linkable)
-> (HomeModInfo -> HomeModLinkable)
-> HomeModInfo
-> Maybe Linkable
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HomeModInfo -> HomeModLinkable
hm_linkable

emptyHomeModInfoLinkable :: HomeModLinkable
emptyHomeModInfoLinkable :: HomeModLinkable
emptyHomeModInfoLinkable = Maybe (LinkableWith ModuleByteCode)
-> Maybe Linkable -> HomeModLinkable
HomeModLinkable Maybe (LinkableWith ModuleByteCode)
forall a. Maybe a
Nothing Maybe Linkable
forall a. Maybe a
Nothing

-- See Note [Home module build products]
data HomeModLinkable = HomeModLinkable { HomeModLinkable -> Maybe (LinkableWith ModuleByteCode)
homeMod_bytecode :: !(Maybe (LinkableWith ModuleByteCode))
                                       , HomeModLinkable -> Maybe Linkable
homeMod_object   :: !(Maybe Linkable) }

homeModLinkableByteCode :: HomeModLinkable -> Maybe Linkable
homeModLinkableByteCode :: HomeModLinkable -> Maybe Linkable
homeModLinkableByteCode = (LinkableWith ModuleByteCode -> Linkable)
-> Maybe (LinkableWith ModuleByteCode) -> Maybe Linkable
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ModuleByteCode -> NonEmpty LinkablePart)
-> LinkableWith ModuleByteCode -> Linkable
forall a b. (a -> b) -> LinkableWith a -> LinkableWith b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (LinkablePart -> NonEmpty LinkablePart
forall a. a -> NonEmpty a
NE.singleton (LinkablePart -> NonEmpty LinkablePart)
-> (ModuleByteCode -> LinkablePart)
-> ModuleByteCode
-> NonEmpty LinkablePart
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleByteCode -> LinkablePart
ModuleByteCode -> LinkablePart
DotGBC)) (Maybe (LinkableWith ModuleByteCode) -> Maybe Linkable)
-> (HomeModLinkable -> Maybe (LinkableWith ModuleByteCode))
-> HomeModLinkable
-> Maybe Linkable
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HomeModLinkable -> Maybe (LinkableWith ModuleByteCode)
homeMod_bytecode

homeModLinkableObject :: HomeModLinkable -> Maybe Linkable
homeModLinkableObject :: HomeModLinkable -> Maybe Linkable
homeModLinkableObject = HomeModLinkable -> Maybe Linkable
homeMod_object

instance Outputable HomeModLinkable where
  ppr :: HomeModLinkable -> SDoc
ppr (HomeModLinkable Maybe (LinkableWith ModuleByteCode)
l1 Maybe Linkable
l2) = Maybe (LinkableWith ModuleByteCode) -> SDoc
forall a. Outputable a => a -> SDoc
ppr Maybe (LinkableWith ModuleByteCode)
l1 SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ Maybe Linkable -> SDoc
forall a. Outputable a => a -> SDoc
ppr Maybe Linkable
l2

{-
Note [Home module build products]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When compiling a home module we can produce some combination of the following
build products.

1. A byte code linkable, for use with the byte code interpreter.
2. An object file linkable, for linking a final executable or the byte code interpreter

What we have produced is recorded in the `HomeModLinkable` type. In the case
that these linkables are produced they are stored in the relevant field so that
subsequent modules can retrieve and use them as necessary.

* `-fbyte-code` will *only* produce a byte code linkable. This is the default in GHCi.
* `-fobject-code` will *only* produce an object file linkable. This is the default in -c and --make mode.
* `-fbyte-code-and-object-code` produces both a byte-code and object file linkable. So both fields are populated.

Why would you want to produce both an object file and byte code linkable? If you
also want to use `-fprefer-byte-code` then you should probably also use this
flag to make sure that byte code is generated for your modules.

-}