{-# 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
#if MIN_VERSION_ghc(9,3,0)
              , hsc_type_env_vars
#else
              , hsc_type_env_var
#endif
              ),
    Env.hsc_HPT,
    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)

-- See Note [Guidelines For Using CPP In GHCIDE Import Statements]

import           GHC.Driver.Hooks                    (Hooks)
import           GHC.Driver.Session                  hiding (mkHomeModule)
import           GHC.Unit.Types                      (Module, UnitId)

#if !MIN_VERSION_ghc(9,2,0)
import qualified Data.Set                            as Set
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
import           GHC.Unit.Types                      (Unit, mkModule)
#endif

#if !MIN_VERSION_ghc(9,5,0)
import           GHC.Unit.Module.Name
#endif

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

#if MIN_VERSION_ghc(9,2,0)
import           GHC.Driver.Backend                  as Backend
import qualified GHC.Driver.Env                      as Env
import qualified GHC.Driver.Session                  as Session
import           GHC.Platform.Ways
import           GHC.Runtime.Context
import           GHC.Unit.Env                        (UnitEnv)
import           GHC.Unit.Home                       as Home
import           GHC.Utils.Logger
import           GHC.Utils.TmpFs
#endif

#if MIN_VERSION_ghc(9,2,0) && !MIN_VERSION_ghc(9,3,0)
import           GHC.Driver.Env                      (HscEnv, hsc_EPS)
#endif

#if MIN_VERSION_ghc(9,3,0)
import           GHC.Driver.Env                      (HscEnv)
#endif

#if MIN_VERSION_ghc(9,5,0)
import           Language.Haskell.Syntax.Module.Name
#endif

#if MIN_VERSION_ghc(9,3,0)
hsc_EPS :: HscEnv -> UnitEnv
hsc_EPS = hsc_unit_env
#endif

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

setHomeUnitId_ :: UnitId -> DynFlags -> DynFlags
#if MIN_VERSION_ghc(9,2,0)
setHomeUnitId_ :: UnitId -> DynFlags -> DynFlags
setHomeUnitId_ UnitId
uid DynFlags
df = DynFlags
df { homeUnitId_ :: UnitId
Session.homeUnitId_ = UnitId
uid }
#else
setHomeUnitId_ uid df = df { homeUnitId = 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
tmpFs <- IO TmpFs
initTmpFs
  forall (f :: * -> *) a. Applicative f => a -> f a
pure HscEnv
env { hsc_tmpfs :: TmpFs
Env.hsc_tmpfs = TmpFs
tmpFs }
#else
  filesToClean <- newIORef emptyFilesToClean
  dirsToClean <- newIORef mempty
  let dflags = (Env.hsc_dflags env){filesToClean=filesToClean, dirsToClean=dirsToClean, useUnicode=True}
  pure $ hscSetFlags dflags env
#endif

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

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

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

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

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

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

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

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

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

hscHomeUnit :: HscEnv -> HomeUnit
hscHomeUnit :: HscEnv -> HomeUnit
hscHomeUnit =
#if MIN_VERSION_ghc(9,2,0)
  HscEnv -> HomeUnit
Env.hsc_home_unit
#else
  homeUnit . Env.hsc_dflags
#endif

mkHomeModule :: HomeUnit -> ModuleName -> Module
mkHomeModule :: HomeUnit -> ModuleName -> Module
mkHomeModule =
#if MIN_VERSION_ghc(9,2,0)
  HomeUnit -> ModuleName -> Module
Home.mkHomeModule
#else
  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,5,0)
  , backend = noBackend
#elif MIN_VERSION_ghc(9,2,0)
  , backend :: Backend
backend = Backend
NoBackend
#else
  , 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,5,0)
   , backend = interpreterBackend
#elif MIN_VERSION_ghc(9,2,0)
  , backend :: Backend
backend = Backend
Interpreter
#else
  , hscTarget = HscInterpreted
#endif
  , ghcMode :: GhcMode
ghcMode = GhcMode
CompManager
    }

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

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

setWays :: Ways -> DynFlags -> DynFlags
setWays :: Ways -> DynFlags -> DynFlags
setWays Ways
newWays DynFlags
flags =
#if MIN_VERSION_ghc(9,2,0)
  DynFlags
flags { targetWays_ :: Ways
Session.targetWays_ = Ways
newWays}
#else
  flags {ways = newWays}
#endif

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

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

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

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