{-# LANGUAGE LambdaCase #-} -- | GHC API utilities for inspecting the GHC session module GHC.Driver.Session.Inspect where import GHC.Prelude import GHC.Data.Maybe import Control.Monad import GHC.ByteCode.Types import GHC.Core.FamInstEnv import GHC.Core.InstEnv import GHC.Driver.Env import GHC.Driver.Main import GHC.Driver.Monad import GHC.Driver.Session import GHC.Rename.Names import GHC.Runtime.Context import GHC.Runtime.Interpreter import GHC.Types.Avail import GHC.Types.Name import GHC.Types.Name.Ppr import GHC.Types.Name.Reader import GHC.Types.Name.Set import GHC.Types.PkgQual import GHC.Types.SafeHaskell import GHC.Types.SrcLoc import GHC.Types.TyThing import GHC.Types.TypeEnv import GHC.Unit.External import GHC.Unit.Home.ModInfo import GHC.Unit.Module import GHC.Unit.Module.Graph import GHC.Unit.Module.ModDetails import GHC.Unit.Module.ModIface import GHC.Utils.Misc import GHC.Utils.Outputable import qualified GHC.Unit.Home.Graph as HUG -- %************************************************************************ -- %* * -- Inspecting the session -- %* * -- %************************************************************************ -- | Get the module dependency graph. getModuleGraph :: GhcMonad m => m ModuleGraph -- ToDo: DiGraph ModSummary getModuleGraph = liftM hsc_mod_graph getSession {-# DEPRECATED isLoaded "Prefer 'isLoadedModule' and 'isLoadedHomeModule'" #-} -- | Return @True@ \<==> module is loaded. isLoaded :: GhcMonad m => ModuleName -> m Bool isLoaded m = withSession $ \hsc_env -> liftIO $ do hmis <- HUG.lookupAllHug (hsc_HUG hsc_env) m return $! not (null hmis) -- | Check whether a 'ModuleName' is found in the 'HomePackageTable' -- for the given 'UnitId'. isLoadedModule :: GhcMonad m => UnitId -> ModuleName -> m Bool isLoadedModule uid m = withSession $ \hsc_env -> liftIO $ do hmi <- HUG.lookupHug (hsc_HUG hsc_env) uid m return $! isJust hmi -- | Check whether 'Module' is part of the 'HomeUnitGraph'. -- -- Similar to 'isLoadedModule', but for 'Module's. isLoadedHomeModule :: GhcMonad m => Module -> m Bool isLoadedHomeModule m = withSession $ \hsc_env -> liftIO $ do hmi <- HUG.lookupHugByModule m (hsc_HUG hsc_env) return $! isJust hmi -- | Return the bindings for the current interactive session. getBindings :: GhcMonad m => m [TyThing] getBindings = withSession $ \hsc_env -> return $ icInScopeTTs $ hsc_IC hsc_env -- | Return the instances for the current interactive session. getInsts :: GhcMonad m => m ([ClsInst], [FamInst]) getInsts = withSession $ \hsc_env -> let (inst_env, fam_env) = ic_instances (hsc_IC hsc_env) in return (instEnvElts inst_env, fam_env) getNamePprCtx :: GhcMonad m => m NamePprCtx getNamePprCtx = withSession $ \hsc_env -> do return $ icNamePprCtx (hsc_unit_env hsc_env) (hsc_IC hsc_env) -- | Container for information about a 'Module'. data ModuleInfo = ModuleInfo { minf_type_env :: TypeEnv, minf_exports :: [AvailInfo], minf_instances :: [ClsInst], minf_iface :: Maybe ModIface, minf_safe :: SafeHaskellMode, minf_modBreaks :: Maybe InternalModBreaks } -- We don't want HomeModInfo here, because a ModuleInfo applies -- to package modules too. -- | Request information about a loaded 'Module' getModuleInfo :: GhcMonad m => Module -> m (Maybe ModuleInfo) -- XXX: Maybe X getModuleInfo mdl = withSession $ \hsc_env -> do if HUG.memberHugUnit (moduleUnit mdl) (hsc_HUG hsc_env) then liftIO $ getHomeModuleInfo hsc_env mdl else liftIO $ getPackageModuleInfo hsc_env mdl getPackageModuleInfo :: HscEnv -> Module -> IO (Maybe ModuleInfo) getPackageModuleInfo hsc_env mdl = do eps <- hscEPS hsc_env iface <- hscGetModuleInterface hsc_env mdl let avails = mi_exports iface pte = eps_PTE eps tys = [ ty | name <- concatMap availNames avails, Just ty <- [lookupTypeEnv pte name] ] return (Just (ModuleInfo { minf_type_env = mkTypeEnv tys, minf_exports = avails, minf_instances = error "getModuleInfo: instances for package module unimplemented", minf_iface = Just iface, minf_safe = getSafeMode $ mi_trust iface, minf_modBreaks = Nothing })) availsToGlobalRdrEnv :: HasDebugCallStack => HscEnv -> Module -> [AvailInfo] -> IfGlobalRdrEnv availsToGlobalRdrEnv hsc_env mod avails = forceGlobalRdrEnv rdr_env -- See Note [Forcing GREInfo] in GHC.Types.GREInfo. where rdr_env = mkGlobalRdrEnv (gresFromAvails hsc_env (Just imp_spec) avails) -- We're building a GlobalRdrEnv as if the user imported -- all the specified modules into the global interactive module imp_spec = ImpSpec { is_decl = decl, is_item = ImpAll} decl = ImpDeclSpec { is_mod = mod, is_as = moduleName mod, is_qual = False, is_isboot = NotBoot, is_pkg_qual = NoPkgQual, is_dloc = srcLocSpan interactiveSrcLoc, is_level = NormalLevel } getHomeModuleInfo :: HscEnv -> Module -> IO (Maybe ModuleInfo) getHomeModuleInfo hsc_env mdl = HUG.lookupHugByModule mdl (hsc_HUG hsc_env) >>= \case Nothing -> return Nothing Just hmi -> do let details = hm_details hmi iface = hm_iface hmi return (Just (ModuleInfo { minf_type_env = md_types details, minf_exports = md_exports details, -- NB: already forced. See Note [Forcing GREInfo] in GHC.Types.GREInfo. minf_instances = instEnvElts $ md_insts details, minf_iface = Just iface, minf_safe = getSafeMode $ mi_trust iface, minf_modBreaks = getModBreaks hmi })) -- | The list of top-level entities defined in a module modInfoTyThings :: ModuleInfo -> [TyThing] modInfoTyThings minf = typeEnvElts (minf_type_env minf) modInfoExports :: ModuleInfo -> [Name] modInfoExports minf = concatMap availNames $! minf_exports minf modInfoExportsWithSelectors :: ModuleInfo -> [Name] modInfoExportsWithSelectors minf = concatMap availNames $! minf_exports minf -- | Returns the instances defined by the specified module. -- Warning: currently unimplemented for package modules. modInfoInstances :: ModuleInfo -> [ClsInst] modInfoInstances = minf_instances modInfoIsExportedName :: ModuleInfo -> Name -> Bool modInfoIsExportedName minf name = elemNameSet name (availsToNameSet (minf_exports minf)) mkNamePprCtxForModule :: GhcMonad m => Module -> ModuleInfo -> m NamePprCtx mkNamePprCtxForModule mod minf = withSession $ \hsc_env -> do let name_ppr_ctx = mkNamePprCtx ptc (hsc_unit_env hsc_env) (availsToGlobalRdrEnv hsc_env mod (minf_exports minf)) ptc = initPromotionTickContext (hsc_dflags hsc_env) return name_ppr_ctx modInfoLookupName :: GhcMonad m => ModuleInfo -> Name -> m (Maybe TyThing) -- XXX: returns a Maybe X modInfoLookupName minf name = withSession $ \hsc_env -> do case lookupTypeEnv (minf_type_env minf) name of Just tyThing -> return (Just tyThing) Nothing -> liftIO (lookupType hsc_env name) modInfoIface :: ModuleInfo -> Maybe ModIface modInfoIface = minf_iface -- | Retrieve module safe haskell mode modInfoSafe :: ModuleInfo -> SafeHaskellMode modInfoSafe = minf_safe modInfoModBreaks :: ModuleInfo -> Maybe InternalModBreaks modInfoModBreaks = minf_modBreaks