summaryrefslogtreecommitdiff
path: root/compiler/GHC/Unit/Module/Graph.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Unit/Module/Graph.hs')
-rw-r--r--compiler/GHC/Unit/Module/Graph.hs133
1 files changed, 120 insertions, 13 deletions
diff --git a/compiler/GHC/Unit/Module/Graph.hs b/compiler/GHC/Unit/Module/Graph.hs
index faa3ae9b1a..5b5d152711 100644
--- a/compiler/GHC/Unit/Module/Graph.hs
+++ b/compiler/GHC/Unit/Module/Graph.hs
@@ -1,17 +1,26 @@
+{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
module GHC.Unit.Module.Graph
( ModuleGraph
+ , ModuleGraphNode(..)
, emptyMG
, mkModuleGraph
+ , mkModuleGraph'
, extendMG
+ , extendMGInst
+ , extendMG'
+ , filterToposortToModules
, mapMG
, mgModSummaries
+ , mgModSummaries'
+ , mgExtendedModSummaries
, mgElemModule
, mgLookupModule
, mgBootModules
, needsTemplateHaskellOrQQ
, isTemplateHaskellOrQQNonBoot
+ , showModMsg
)
where
@@ -19,21 +28,50 @@ import GHC.Prelude
import qualified GHC.LanguageExtensions as LangExt
+import GHC.Data.Maybe
+import GHC.Data.Graph.Directed ( SCC(..) )
+
+import GHC.Driver.Backend
+import GHC.Driver.Ppr
import GHC.Driver.Session
+import GHC.Types.SourceFile ( hscSourceString )
+
import GHC.Unit.Module.ModSummary
import GHC.Unit.Module.Env
import GHC.Unit.Types
-
-
--- | A ModuleGraph contains all the nodes from the home package (only).
--- There will be a node for each source module, plus a node for each hi-boot
--- module.
+import GHC.Utils.Outputable
+
+import System.FilePath
+
+-- | A '@ModuleGraphNode@' is a node in the '@ModuleGraph@'.
+-- Edges between nodes mark dependencies arising from module imports
+-- and dependencies arising from backpack instantiations.
+data ModuleGraphNode
+ -- | Instantiation nodes track the instantiation of other units
+ -- (backpack dependencies) with the holes (signatures) of the current package.
+ = InstantiationNode InstantiatedUnit
+ -- | There is a module summary node for each module, signature, and boot module being built.
+ | ModuleNode ExtendedModSummary
+
+instance Outputable ModuleGraphNode where
+ ppr = \case
+ InstantiationNode iuid -> ppr iuid
+ ModuleNode ems -> ppr ems
+
+-- | A '@ModuleGraph@' contains all the nodes from the home package (only). See
+-- '@ModuleGraphNode@' for information about the nodes.
+--
+-- Modules need to be compiled. hs-boots need to be typechecked before
+-- the associated "real" module so modules with {-# SOURCE #-} imports can be
+-- built. Instantiations also need to be typechecked to ensure that the module
+-- fits the signature. Substantiation typechecking is roughly comparable to the
+-- check that the module and its hs-boot agree.
--
-- The graph is not necessarily stored in topologically-sorted order. Use
-- 'GHC.topSortModuleGraph' and 'GHC.Data.Graph.Directed.flattenSCC' to achieve this.
data ModuleGraph = ModuleGraph
- { mg_mss :: [ModSummary]
+ { mg_mss :: [ModuleGraphNode]
, mg_non_boot :: ModuleEnv ModSummary
-- a map of all non-boot ModSummaries keyed by Modules
, mg_boot :: ModuleSet
@@ -56,7 +94,9 @@ needsTemplateHaskellOrQQ mg = mg_needs_th_or_qq mg
-- To preserve invariants 'f' can't change the isBoot status.
mapMG :: (ModSummary -> ModSummary) -> ModuleGraph -> ModuleGraph
mapMG f mg@ModuleGraph{..} = mg
- { mg_mss = map f mg_mss
+ { mg_mss = flip fmap mg_mss $ \case
+ InstantiationNode iuid -> InstantiationNode iuid
+ ModuleNode (ExtendedModSummary ms bds) -> ModuleNode (ExtendedModSummary (f ms) bds)
, mg_non_boot = mapModuleEnv f mg_non_boot
}
@@ -64,7 +104,13 @@ mgBootModules :: ModuleGraph -> ModuleSet
mgBootModules ModuleGraph{..} = mg_boot
mgModSummaries :: ModuleGraph -> [ModSummary]
-mgModSummaries = mg_mss
+mgModSummaries mg = [ m | ModuleNode (ExtendedModSummary m _) <- mgModSummaries' mg ]
+
+mgExtendedModSummaries :: ModuleGraph -> [ExtendedModSummary]
+mgExtendedModSummaries mg = [ ems | ModuleNode ems <- mgModSummaries' mg ]
+
+mgModSummaries' :: ModuleGraph -> [ModuleGraphNode]
+mgModSummaries' = mg_mss
mgElemModule :: ModuleGraph -> Module -> Bool
mgElemModule ModuleGraph{..} m = elemModuleEnv m mg_non_boot
@@ -82,11 +128,11 @@ isTemplateHaskellOrQQNonBoot ms =
|| xopt LangExt.QuasiQuotes (ms_hspp_opts ms)) &&
(isBootSummary ms == NotBoot)
--- | Add a ModSummary to ModuleGraph. Assumes that the new ModSummary is
+-- | Add an ExtendedModSummary to ModuleGraph. Assumes that the new ModSummary is
-- not an element of the ModuleGraph.
-extendMG :: ModuleGraph -> ModSummary -> ModuleGraph
-extendMG ModuleGraph{..} ms = ModuleGraph
- { mg_mss = ms:mg_mss
+extendMG :: ModuleGraph -> ExtendedModSummary -> ModuleGraph
+extendMG ModuleGraph{..} ems@(ExtendedModSummary ms _) = ModuleGraph
+ { mg_mss = ModuleNode ems : mg_mss
, mg_non_boot = case isBootSummary ms of
IsBoot -> mg_non_boot
NotBoot -> extendModuleEnv mg_non_boot (ms_mod ms) ms
@@ -96,6 +142,67 @@ extendMG ModuleGraph{..} ms = ModuleGraph
, mg_needs_th_or_qq = mg_needs_th_or_qq || isTemplateHaskellOrQQNonBoot ms
}
-mkModuleGraph :: [ModSummary] -> ModuleGraph
+extendMGInst :: ModuleGraph -> InstantiatedUnit -> ModuleGraph
+extendMGInst mg depUnitId = mg
+ { mg_mss = InstantiationNode depUnitId : mg_mss mg
+ }
+
+extendMG' :: ModuleGraph -> ModuleGraphNode -> ModuleGraph
+extendMG' mg = \case
+ InstantiationNode depUnitId -> extendMGInst mg depUnitId
+ ModuleNode ems -> extendMG mg ems
+
+mkModuleGraph :: [ExtendedModSummary] -> ModuleGraph
mkModuleGraph = foldr (flip extendMG) emptyMG
+mkModuleGraph' :: [ModuleGraphNode] -> ModuleGraph
+mkModuleGraph' = foldr (flip extendMG') emptyMG
+
+-- | This function filters out all the instantiation nodes from each SCC of a
+-- topological sort. Use this with care, as the resulting "strongly connected components"
+-- may not really be strongly connected in a direct way, as instantiations have been
+-- removed. It would probably be best to eliminate uses of this function where possible.
+filterToposortToModules
+ :: [SCC ModuleGraphNode] -> [SCC ModSummary]
+filterToposortToModules = mapMaybe $ mapMaybeSCC $ \case
+ InstantiationNode _ -> Nothing
+ ModuleNode (ExtendedModSummary node _) -> Just node
+ where
+ -- This higher order function is somewhat bogus,
+ -- as the definition of "strongly connected component"
+ -- is not necessarily respected.
+ mapMaybeSCC :: (a -> Maybe b) -> SCC a -> Maybe (SCC b)
+ mapMaybeSCC f = \case
+ AcyclicSCC a -> AcyclicSCC <$> f a
+ CyclicSCC as -> case mapMaybe f as of
+ [] -> Nothing
+ [a] -> Just $ AcyclicSCC a
+ as -> Just $ CyclicSCC as
+
+showModMsg :: DynFlags -> Bool -> ModuleGraphNode -> SDoc
+showModMsg _ _ (InstantiationNode indef_unit) =
+ ppr $ instUnitInstanceOf indef_unit
+showModMsg dflags recomp (ModuleNode (ExtendedModSummary mod_summary _)) =
+ if gopt Opt_HideSourcePaths dflags
+ then text mod_str
+ else hsep $
+ [ text (mod_str ++ replicate (max 0 (16 - length mod_str)) ' ')
+ , char '('
+ , text (op $ msHsFilePath mod_summary) <> char ','
+ ] ++
+ if gopt Opt_BuildDynamicToo dflags
+ then [ text obj_file <> char ','
+ , text dyn_file
+ , char ')'
+ ]
+ else [ text obj_file, char ')' ]
+ where
+ op = normalise
+ mod = moduleName (ms_mod mod_summary)
+ mod_str = showPpr dflags mod ++ hscSourceString (ms_hsc_src mod_summary)
+ dyn_file = op $ msDynObjFilePath mod_summary dflags
+ obj_file = case backend dflags of
+ Interpreter | recomp -> "interpreted"
+ NoBackend -> "nothing"
+ _ -> (op $ msObjFilePath mod_summary)
+