{-# LANGUAGE CPP #-}

-- | Compat module for the main Driver types, such as 'HscEnv',
-- 'UnitEnv' and some DynFlags compat functions.
module Development.IDE.GHC.Compat.Env (
    Env.HscEnv(hsc_FC, hsc_NC, hsc_IC, hsc_mod_graph, hsc_HPT, hsc_type_env_var),
    InteractiveContext(..),
    setInteractivePrintName,
    setInteractiveDynFlags,
    Env.hsc_dflags,
    hsc_EPS,
    hsc_logger,
    hsc_tmpfs,
    hsc_unit_env,
    hsc_hooks,
    hscSetHooks,
    TmpFs,
    -- * HomeUnit
    hscHomeUnit,
    HomeUnit,
    setHomeUnitId_,
    Development.IDE.GHC.Compat.Env.mkHomeModule,
    -- * Provide backwards Compatible
    -- types and helper functions.
    Logger(..),
    UnitEnv,
    hscSetUnitEnv,
    hscSetFlags,
    initTempFs,
    -- * Home Unit
    Development.IDE.GHC.Compat.Env.homeUnitId_,
    -- * DynFlags Helper
    setBytecodeLinkerOptions,
    setInterpreterLinkerOptions,
    Development.IDE.GHC.Compat.Env.safeImportsOn,
    -- * Ways
    Ways,
    Way,
    hostFullWays,
    setWays,
    wayGeneralFlags,
    wayUnsetGeneralFlags,
    -- * Backend, backwards compatible
    Backend,
    setBackend,
    Development.IDE.GHC.Compat.Env.platformDefaultBackend,
    ) where

import           GHC                  (setInteractiveDynFlags)

#if MIN_VERSION_ghc(9,0,0)
#if MIN_VERSION_ghc(9,2,0)
import           GHC.Driver.Backend   as Backend
import           GHC.Driver.Env       (HscEnv, hsc_EPS)
import qualified GHC.Driver.Env       as Env
import qualified GHC.Driver.Session   as Session
import           GHC.Platform.Ways    hiding (hostFullWays)
import qualified GHC.Platform.Ways    as Ways
import           GHC.Runtime.Context
import           GHC.Unit.Env         (UnitEnv)
import           GHC.Unit.Home        as Home
import           GHC.Utils.Logger
import           GHC.Utils.TmpFs
#else
import qualified GHC.Driver.Session   as DynFlags
import           GHC.Driver.Types     (HscEnv, InteractiveContext (..), hsc_EPS,
                                       setInteractivePrintName)
import qualified GHC.Driver.Types     as Env
import           GHC.Driver.Ways      hiding (hostFullWays)
import qualified GHC.Driver.Ways      as Ways
#endif
import           GHC.Driver.Hooks     (Hooks)
import           GHC.Driver.Session   hiding (mkHomeModule)
import           GHC.Unit.Module.Name
import           GHC.Unit.Types       (Module, Unit, UnitId, mkModule)
#else
import           DynFlags
import           Hooks
import           HscTypes             as Env
import           Module
#endif

#if MIN_VERSION_ghc(9,0,0)
#if !MIN_VERSION_ghc(9,2,0)
import qualified Data.Set             as Set
#endif
#endif
#if !MIN_VERSION_ghc(9,2,0)
import           Data.IORef
#endif

#if !MIN_VERSION_ghc(9,2,0)
type UnitEnv = ()
newtype Logger = Logger { Logger -> LogAction
log_action :: LogAction }
type TmpFs = ()
#endif

setHomeUnitId_ :: UnitId -> DynFlags -> DynFlags
#if MIN_VERSION_ghc(9,2,0)
setHomeUnitId_ uid df = df { Session.homeUnitId_ = uid }
#elif MIN_VERSION_ghc(9,0,0)
setHomeUnitId_ uid df = df { homeUnitId = uid }
#else
setHomeUnitId_ :: UnitId -> DynFlags -> DynFlags
setHomeUnitId_ UnitId
uid DynFlags
df = DynFlags
df { thisInstalledUnitId :: InstalledUnitId
thisInstalledUnitId = UnitId -> InstalledUnitId
toInstalledUnitId UnitId
uid }
#endif

hscSetFlags :: DynFlags -> HscEnv -> HscEnv
hscSetFlags :: DynFlags -> HscEnv -> HscEnv
hscSetFlags DynFlags
df HscEnv
env = HscEnv
env { hsc_dflags :: DynFlags
Env.hsc_dflags = DynFlags
df }

initTempFs :: HscEnv -> IO HscEnv
initTempFs :: HscEnv -> IO HscEnv
initTempFs HscEnv
env = do
#if MIN_VERSION_ghc(9,2,0)
  tmpFs <- initTmpFs
  pure env { Env.hsc_tmpfs = tmpFs }
#else
  IORef FilesToClean
filesToClean <- FilesToClean -> IO (IORef FilesToClean)
forall a. a -> IO (IORef a)
newIORef FilesToClean
emptyFilesToClean
  IORef (Map FilePath FilePath)
dirsToClean <- Map FilePath FilePath -> IO (IORef (Map FilePath FilePath))
forall a. a -> IO (IORef a)
newIORef Map FilePath FilePath
forall a. Monoid a => a
mempty
  let dflags :: DynFlags
dflags = (HscEnv -> DynFlags
Env.hsc_dflags HscEnv
env){filesToClean :: IORef FilesToClean
filesToClean=IORef FilesToClean
filesToClean, dirsToClean :: IORef (Map FilePath FilePath)
dirsToClean=IORef (Map FilePath FilePath)
dirsToClean, useUnicode :: Bool
useUnicode=Bool
True}
  HscEnv -> IO HscEnv
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HscEnv -> IO HscEnv) -> HscEnv -> IO HscEnv
forall a b. (a -> b) -> a -> b
$ DynFlags -> HscEnv -> HscEnv
hscSetFlags DynFlags
dflags HscEnv
env
#endif

hscSetUnitEnv :: UnitEnv -> HscEnv -> HscEnv
#if MIN_VERSION_ghc(9,2,0)
hscSetUnitEnv ue env = env { Env.hsc_unit_env = ue }
#else
hscSetUnitEnv :: UnitEnv -> HscEnv -> HscEnv
hscSetUnitEnv UnitEnv
_ HscEnv
env  = HscEnv
env
#endif

hsc_unit_env :: HscEnv -> UnitEnv
hsc_unit_env :: HscEnv -> UnitEnv
hsc_unit_env =
#if MIN_VERSION_ghc(9,2,0)
  Env.hsc_unit_env
#else
  UnitEnv -> HscEnv -> UnitEnv
forall a b. a -> b -> a
const ()
#endif

hsc_tmpfs :: HscEnv -> TmpFs
hsc_tmpfs :: HscEnv -> UnitEnv
hsc_tmpfs =
#if MIN_VERSION_ghc(9,2,0)
  Env.hsc_tmpfs
#else
  UnitEnv -> HscEnv -> UnitEnv
forall a b. a -> b -> a
const ()
#endif

hsc_logger :: HscEnv -> Logger
hsc_logger :: HscEnv -> Logger
hsc_logger =
#if MIN_VERSION_ghc(9,2,0)
  Env.hsc_logger
#else
  LogAction -> Logger
Logger (LogAction -> Logger) -> (HscEnv -> LogAction) -> HscEnv -> Logger
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DynFlags -> LogAction
DynFlags.log_action (DynFlags -> LogAction)
-> (HscEnv -> DynFlags) -> HscEnv -> LogAction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HscEnv -> DynFlags
Env.hsc_dflags
#endif

hsc_hooks :: HscEnv -> Hooks
hsc_hooks :: HscEnv -> Hooks
hsc_hooks =
#if MIN_VERSION_ghc(9,2,0)
  Env.hsc_hooks
#else
  DynFlags -> Hooks
hooks (DynFlags -> Hooks) -> (HscEnv -> DynFlags) -> HscEnv -> Hooks
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HscEnv -> DynFlags
Env.hsc_dflags
#endif

hscSetHooks :: Hooks -> HscEnv -> HscEnv
hscSetHooks :: Hooks -> HscEnv -> HscEnv
hscSetHooks Hooks
hooks HscEnv
env =
#if MIN_VERSION_ghc(9,2,0)
  env { Env.hsc_hooks = hooks }
#else
  DynFlags -> HscEnv -> HscEnv
hscSetFlags ((HscEnv -> DynFlags
Env.hsc_dflags HscEnv
env) { hooks :: Hooks
hooks = Hooks
hooks}) HscEnv
env
#endif

homeUnitId_ :: DynFlags -> UnitId
homeUnitId_ :: DynFlags -> UnitId
homeUnitId_ =
#if MIN_VERSION_ghc(9,2,0)
  Session.homeUnitId_
#elif MIN_VERSION_ghc(9,0,0)
  homeUnitId
#else
  DynFlags -> UnitId
thisPackage
#endif

safeImportsOn :: DynFlags -> Bool
safeImportsOn :: DynFlags -> Bool
safeImportsOn =
#if MIN_VERSION_ghc(9,2,0)
  Session.safeImportsOn
#else
  DynFlags -> Bool
DynFlags.safeImportsOn
#endif

#if MIN_VERSION_ghc(9,0,0) && !MIN_VERSION_ghc(9,2,0)
type HomeUnit = Unit
#elif !MIN_VERSION_ghc(9,0,0)
type HomeUnit = UnitId
#endif

hscHomeUnit :: HscEnv -> HomeUnit
hscHomeUnit :: HscEnv -> UnitId
hscHomeUnit =
#if MIN_VERSION_ghc(9,2,0)
  Env.hsc_home_unit
#elif MIN_VERSION_ghc(9,0,0)
  homeUnit . Env.hsc_dflags
#else
  DynFlags -> UnitId
homeUnitId_ (DynFlags -> UnitId) -> (HscEnv -> DynFlags) -> HscEnv -> UnitId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HscEnv -> DynFlags
hsc_dflags
#endif

mkHomeModule :: HomeUnit -> ModuleName -> Module
mkHomeModule :: UnitId -> ModuleName -> Module
mkHomeModule =
#if MIN_VERSION_ghc(9,2,0)
  Home.mkHomeModule
#else
  UnitId -> ModuleName -> Module
mkModule
#endif

-- | We don't want to generate object code so we compile to bytecode
-- (HscInterpreted) which implies LinkInMemory
-- HscInterpreted
setBytecodeLinkerOptions :: DynFlags -> DynFlags
setBytecodeLinkerOptions :: DynFlags -> DynFlags
setBytecodeLinkerOptions DynFlags
df = DynFlags
df {
    ghcLink :: GhcLink
ghcLink   = GhcLink
LinkInMemory
#if MIN_VERSION_ghc(9,2,0)
  , backend = NoBackend
#else
  , hscTarget :: HscTarget
hscTarget = HscTarget
HscNothing
#endif
  , ghcMode :: GhcMode
ghcMode = GhcMode
CompManager
    }

setInterpreterLinkerOptions :: DynFlags -> DynFlags
setInterpreterLinkerOptions :: DynFlags -> DynFlags
setInterpreterLinkerOptions DynFlags
df = DynFlags
df {
    ghcLink :: GhcLink
ghcLink   = GhcLink
LinkInMemory
#if MIN_VERSION_ghc(9,2,0)
  , backend = Interpreter
#else
  , hscTarget :: HscTarget
hscTarget = HscTarget
HscInterpreted
#endif
  , ghcMode :: GhcMode
ghcMode = GhcMode
CompManager
    }

-- -------------------------------------------------------
-- Ways helpers
-- -------------------------------------------------------

#if !MIN_VERSION_ghc(9,2,0) && MIN_VERSION_ghc(9,0,0)
type Ways = Set.Set Way
#elif !MIN_VERSION_ghc(9,0,0)
type Ways = [Way]
#endif

hostFullWays :: Ways
hostFullWays :: Ways
hostFullWays =
#if MIN_VERSION_ghc(9,0,0)
  Ways.hostFullWays
#else
  Ways
interpWays
#endif

setWays :: Ways -> DynFlags -> DynFlags
setWays :: Ways -> DynFlags -> DynFlags
setWays Ways
ways DynFlags
flags =
#if MIN_VERSION_ghc(9,2,0)
  flags { Session.targetWays_ = ways}
#elif MIN_VERSION_ghc(9,0,0)
  flags {ways = ways}
#else
  DynFlags -> DynFlags
updateWays (DynFlags -> DynFlags) -> DynFlags -> DynFlags
forall a b. (a -> b) -> a -> b
$ DynFlags
flags {ways :: Ways
ways = Ways
ways}
#endif

-- -------------------------------------------------------
-- Backend helpers
-- -------------------------------------------------------

#if !MIN_VERSION_ghc(9,2,0)
type Backend = HscTarget
#endif

platformDefaultBackend :: DynFlags -> Backend
platformDefaultBackend :: DynFlags -> HscTarget
platformDefaultBackend =
#if MIN_VERSION_ghc(9,2,0)
  Backend.platformDefaultBackend . targetPlatform
#elif MIN_VERSION_ghc(8,10,0)
  DynFlags -> HscTarget
defaultObjectTarget
#else
  defaultObjectTarget . DynFlags.targetPlatform
#endif

setBackend :: Backend -> DynFlags -> DynFlags
setBackend :: HscTarget -> DynFlags -> DynFlags
setBackend HscTarget
backend DynFlags
flags =
#if MIN_VERSION_ghc(9,2,0)
  flags { backend = backend }
#else
  DynFlags
flags { hscTarget :: HscTarget
hscTarget = HscTarget
backend }
#endif