ghcide-1.9.0.0: src/Development/IDE/GHC/Compat/Units.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE PatternSynonyms #-}
-- | Compat module for 'UnitState' and 'UnitInfo'.
module Development.IDE.GHC.Compat.Units (
-- * UnitState
UnitState,
#if MIN_VERSION_ghc(9,3,0)
initUnits,
#endif
oldInitUnits,
unitState,
getUnitName,
explicitUnits,
preloadClosureUs,
listVisibleModuleNames,
LookupResult(..),
lookupModuleWithSuggestions,
-- * UnitInfoMap
UnitInfoMap,
getUnitInfoMap,
lookupUnit,
lookupUnit',
-- * UnitInfo
UnitInfo,
unitExposedModules,
unitDepends,
unitHaddockInterfaces,
unitInfoId,
unitPackageNameString,
unitPackageVersion,
-- * UnitId helpers
UnitId,
Unit,
unitString,
stringToUnit,
#if !MIN_VERSION_ghc(9,0,0)
pattern RealUnit,
#endif
definiteUnitId,
defUnitId,
installedModule,
-- * Module
toUnitId,
Development.IDE.GHC.Compat.Units.moduleUnitId,
moduleUnit,
-- * ExternalPackageState
ExternalPackageState(..),
-- * Utils
filterInplaceUnits,
FinderCache,
showSDocForUser',
) where
import Control.Monad
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map
#if MIN_VERSION_ghc(9,3,0)
import GHC.Unit.Home.ModInfo
#endif
#if MIN_VERSION_ghc(9,0,0)
#if MIN_VERSION_ghc(9,2,0)
import qualified GHC.Data.ShortText as ST
#if !MIN_VERSION_ghc(9,3,0)
import GHC.Driver.Env (hsc_unit_dbs)
#endif
import GHC.Driver.Ppr
import GHC.Unit.Env
import GHC.Unit.External
import GHC.Unit.Finder
#else
import GHC.Driver.Types
#endif
import GHC.Data.FastString
import qualified GHC.Driver.Session as DynFlags
import GHC.Types.Unique.Set
import qualified GHC.Unit.Info as UnitInfo
import GHC.Unit.State (LookupResult, UnitInfo,
UnitState (unitInfoMap))
import qualified GHC.Unit.State as State
import GHC.Unit.Types hiding (moduleUnit, toUnitId)
import qualified GHC.Unit.Types as Unit
import GHC.Utils.Outputable
#else
import qualified DynFlags
import FastString
import GhcPlugins (SDoc, showSDocForUser)
import HscTypes
import Module hiding (moduleUnitId)
import qualified Module
import Packages (InstalledPackageInfo (haddockInterfaces, packageName),
LookupResult, PackageConfig,
PackageConfigMap,
PackageState,
getPackageConfigMap,
lookupPackage')
import qualified Packages
#endif
import Development.IDE.GHC.Compat.Core
import Development.IDE.GHC.Compat.Env
#if MIN_VERSION_ghc(9,0,0) && !MIN_VERSION_ghc(9,2,0)
import Data.Map (Map)
#endif
import Data.Either
import Data.Version
import qualified GHC
#if MIN_VERSION_ghc(9,0,0)
type PreloadUnitClosure = UniqSet UnitId
#if MIN_VERSION_ghc(9,2,0)
type UnitInfoMap = State.UnitInfoMap
#else
type UnitInfoMap = Map UnitId UnitInfo
#endif
#else
type UnitState = PackageState
type UnitInfo = PackageConfig
type UnitInfoMap = PackageConfigMap
type PreloadUnitClosure = ()
type Unit = UnitId
#endif
#if !MIN_VERSION_ghc(9,0,0)
unitString :: Unit -> String
unitString = Module.unitIdString
stringToUnit :: String -> Unit
stringToUnit = Module.stringToUnitId
#endif
unitState :: HscEnv -> UnitState
#if MIN_VERSION_ghc(9,2,0)
unitState = ue_units . hsc_unit_env
#elif MIN_VERSION_ghc(9,0,0)
unitState = DynFlags.unitState . hsc_dflags
#else
unitState = DynFlags.pkgState . hsc_dflags
#endif
#if MIN_VERSION_ghc(9,3,0)
createUnitEnvFromFlags :: NE.NonEmpty DynFlags -> HomeUnitGraph
createUnitEnvFromFlags unitDflags =
let
newInternalUnitEnv dflags = mkHomeUnitEnv dflags emptyHomePackageTable Nothing
unitEnvList = NE.map (\dflags -> (homeUnitId_ dflags, newInternalUnitEnv dflags)) unitDflags
in
unitEnv_new (Map.fromList (NE.toList (unitEnvList)))
initUnits :: [DynFlags] -> HscEnv -> IO HscEnv
initUnits unitDflags env = do
let dflags0 = hsc_dflags env
-- additionally, set checked dflags so we don't lose fixes
let initial_home_graph = createUnitEnvFromFlags (dflags0 NE.:| unitDflags)
home_units = unitEnv_keys initial_home_graph
home_unit_graph <- forM initial_home_graph $ \homeUnitEnv -> do
let cached_unit_dbs = homeUnitEnv_unit_dbs homeUnitEnv
dflags = homeUnitEnv_dflags homeUnitEnv
old_hpt = homeUnitEnv_hpt homeUnitEnv
(dbs,unit_state,home_unit,mconstants) <- State.initUnits (hsc_logger env) dflags cached_unit_dbs home_units
updated_dflags <- DynFlags.updatePlatformConstants dflags mconstants
pure HomeUnitEnv
{ homeUnitEnv_units = unit_state
, homeUnitEnv_unit_dbs = Just dbs
, homeUnitEnv_dflags = updated_dflags
, homeUnitEnv_hpt = old_hpt
, homeUnitEnv_home_unit = Just home_unit
}
let dflags1 = homeUnitEnv_dflags $ unitEnv_lookup (homeUnitId_ dflags0) home_unit_graph
let unit_env = UnitEnv
{ ue_platform = targetPlatform dflags1
, ue_namever = GHC.ghcNameVersion dflags1
, ue_home_unit_graph = home_unit_graph
, ue_current_unit = homeUnitId_ dflags0
, ue_eps = ue_eps (hsc_unit_env env)
}
pure $ hscSetFlags dflags1 $ hscSetUnitEnv unit_env env
#endif
-- | oldInitUnits only needs to modify DynFlags for GHC <9.2
-- For GHC >= 9.2, we need to set the hsc_unit_env also, that is
-- done later by initUnits
oldInitUnits :: DynFlags -> IO DynFlags
#if MIN_VERSION_ghc(9,2,0)
oldInitUnits = pure
#elif MIN_VERSION_ghc(9,0,0)
oldInitUnits dflags = do
newFlags <- State.initUnits dflags
pure newFlags
#else
oldInitUnits dflags = do
newFlags <- fmap fst $ Packages.initPackages dflags
pure newFlags
#endif
explicitUnits :: UnitState -> [Unit]
explicitUnits ue =
#if MIN_VERSION_ghc(9,3,0)
map fst $ State.explicitUnits ue
#elif MIN_VERSION_ghc(9,0,0)
State.explicitUnits ue
#else
Packages.explicitPackages ue
#endif
listVisibleModuleNames :: HscEnv -> [ModuleName]
listVisibleModuleNames env =
#if MIN_VERSION_ghc(9,0,0)
State.listVisibleModuleNames $ unitState env
#else
Packages.listVisibleModuleNames $ hsc_dflags env
#endif
getUnitName :: HscEnv -> UnitId -> Maybe PackageName
getUnitName env i =
#if MIN_VERSION_ghc(9,0,0)
State.unitPackageName <$> State.lookupUnitId (unitState env) i
#else
packageName <$> Packages.lookupPackage (hsc_dflags env) (definiteUnitId (defUnitId i))
#endif
lookupModuleWithSuggestions
:: HscEnv
-> ModuleName
#if MIN_VERSION_ghc(9,3,0)
-> GHC.PkgQual
#else
-> Maybe FastString
#endif
-> LookupResult
lookupModuleWithSuggestions env modname mpkg =
#if MIN_VERSION_ghc(9,0,0)
State.lookupModuleWithSuggestions (unitState env) modname mpkg
#else
Packages.lookupModuleWithSuggestions (hsc_dflags env) modname mpkg
#endif
getUnitInfoMap :: HscEnv -> UnitInfoMap
getUnitInfoMap =
#if MIN_VERSION_ghc(9,2,0)
unitInfoMap . ue_units . hsc_unit_env
#elif MIN_VERSION_ghc(9,0,0)
unitInfoMap . unitState
#else
Packages.getPackageConfigMap . hsc_dflags
#endif
lookupUnit :: HscEnv -> Unit -> Maybe UnitInfo
#if MIN_VERSION_ghc(9,0,0)
lookupUnit env pid = State.lookupUnit (unitState env) pid
#else
lookupUnit env pid = Packages.lookupPackage (hsc_dflags env) pid
#endif
lookupUnit' :: Bool -> UnitInfoMap -> PreloadUnitClosure -> Unit -> Maybe UnitInfo
#if MIN_VERSION_ghc(9,0,0)
lookupUnit' = State.lookupUnit'
#else
lookupUnit' b pcm _ u = Packages.lookupPackage' b pcm u
#endif
preloadClosureUs :: HscEnv -> PreloadUnitClosure
#if MIN_VERSION_ghc(9,2,0)
preloadClosureUs = State.preloadClosure . unitState
#elif MIN_VERSION_ghc(9,0,0)
preloadClosureUs = State.preloadClosure . unitState
#else
preloadClosureUs = const ()
#endif
unitExposedModules :: UnitInfo -> [(ModuleName, Maybe Module)]
unitExposedModules ue =
#if MIN_VERSION_ghc(9,0,0)
UnitInfo.unitExposedModules ue
#else
Packages.exposedModules ue
#endif
unitDepends :: UnitInfo -> [UnitId]
#if MIN_VERSION_ghc(9,0,0)
unitDepends = State.unitDepends
#else
unitDepends = fmap (Module.DefiniteUnitId. defUnitId') . Packages.depends
#endif
unitPackageNameString :: UnitInfo -> String
unitPackageNameString =
#if MIN_VERSION_ghc(9,0,0)
UnitInfo.unitPackageNameString
#else
Packages.packageNameString
#endif
unitPackageVersion :: UnitInfo -> Version
unitPackageVersion =
#if MIN_VERSION_ghc(9,0,0)
UnitInfo.unitPackageVersion
#else
Packages.packageVersion
#endif
unitInfoId :: UnitInfo -> Unit
unitInfoId =
#if MIN_VERSION_ghc(9,0,0)
UnitInfo.mkUnit
#else
Packages.packageConfigId
#endif
unitHaddockInterfaces :: UnitInfo -> [FilePath]
unitHaddockInterfaces =
#if MIN_VERSION_ghc(9,2,0)
fmap ST.unpack . UnitInfo.unitHaddockInterfaces
#elif MIN_VERSION_ghc(9,0,0)
UnitInfo.unitHaddockInterfaces
#else
haddockInterfaces
#endif
-- ------------------------------------------------------------------
-- Backwards Compatible UnitState
-- ------------------------------------------------------------------
-- ------------------------------------------------------------------
-- Patterns and helpful definitions
-- ------------------------------------------------------------------
#if MIN_VERSION_ghc(9,2,0)
definiteUnitId :: Definite uid -> GenUnit uid
definiteUnitId = RealUnit
defUnitId :: unit -> Definite unit
defUnitId = Definite
installedModule :: unit -> ModuleName -> GenModule unit
installedModule = Module
#elif MIN_VERSION_ghc(9,0,0)
definiteUnitId = RealUnit
defUnitId = Definite
installedModule = Module
#else
pattern RealUnit :: Module.DefUnitId -> UnitId
pattern RealUnit x = Module.DefiniteUnitId x
definiteUnitId :: Module.DefUnitId -> UnitId
definiteUnitId = Module.DefiniteUnitId
defUnitId :: UnitId -> Module.DefUnitId
defUnitId = Module.DefUnitId . Module.toInstalledUnitId
defUnitId' :: Module.InstalledUnitId -> Module.DefUnitId
defUnitId' = Module.DefUnitId
installedModule :: UnitId -> ModuleName -> Module.InstalledModule
installedModule uid modname = Module.InstalledModule (Module.toInstalledUnitId uid) modname
#endif
toUnitId :: Unit -> UnitId
toUnitId =
#if MIN_VERSION_ghc(9,0,0)
Unit.toUnitId
#else
id
#endif
moduleUnitId :: Module -> UnitId
moduleUnitId =
#if MIN_VERSION_ghc(9,0,0)
Unit.toUnitId . Unit.moduleUnit
#else
Module.moduleUnitId
#endif
moduleUnit :: Module -> Unit
moduleUnit =
#if MIN_VERSION_ghc(9,0,0)
Unit.moduleUnit
#else
Module.moduleUnitId
#endif
filterInplaceUnits :: [UnitId] -> [PackageFlag] -> ([UnitId], [PackageFlag])
filterInplaceUnits us packageFlags =
partitionEithers (map isInplace packageFlags)
where
isInplace :: PackageFlag -> Either UnitId PackageFlag
isInplace p@(ExposePackage _ (UnitIdArg u) _) =
#if MIN_VERSION_ghc(9,0,0)
if toUnitId u `elem` us
then Left $ toUnitId u
else Right p
#else
if u `elem` us
then Left u
else Right p
#endif
isInplace p = Right p
showSDocForUser' :: HscEnv -> GHC.PrintUnqualified -> SDoc -> String
#if MIN_VERSION_ghc(9,2,0)
showSDocForUser' env = showSDocForUser (hsc_dflags env) (unitState env)
#else
showSDocForUser' env = showSDocForUser (hsc_dflags env)
#endif