Rodrigo Mesquita pushed to branch wip/romes/27461 at Glasgow Haskell Compiler / GHC

Commits:

20 changed files:

Changes:

  • changelog.d/downsweep-refactor
    1
    +section: compiler
    
    2
    +synopsis: Significantly improve the performance of downsweep
    
    3
    +issues: #27461
    
    4
    +mrs: !16330
    
    5
    +description: {
    
    6
    +    Rewrite the downsweep pass to make the control flow clearer and fix the
    
    7
    +    caching strategy. Allocations during downsweep in multi-home-unit-heavy and
    
    8
    +    module-heavy tests are reduced by -30% to -60%
    
    9
    +}

  • compiler/GHC/Driver/Backpack.hs
    ... ... @@ -906,7 +906,7 @@ hsModuleToModSummary home_keys pn hsc_src modname
    906 906
         extra_sig_imports <- liftIO $ findExtraSigImports hsc_env hsc_src modname
    
    907 907
     
    
    908 908
         let normal_imports = map convImport (generated_imports ++ ord_idecls)
    
    909
    -    (implicit_sigs, inst_deps) <- liftIO $ implicitRequirementsShallow hsc_env normal_imports
    
    909
    +    inst_deps <- liftIO $ implicitRequirementsShallow hsc_env normal_imports
    
    910 910
     
    
    911 911
         -- So that Finder can find it, even though it doesn't exist...
    
    912 912
         this_mod <- liftIO $ do
    
    ... ... @@ -927,8 +927,7 @@ hsModuleToModSummary home_keys pn hsc_src modname
    927 927
                                -- We have to do something special here:
    
    928 928
                                -- due to merging, requirements may end up with
    
    929 929
                                -- extra imports
    
    930
    -                           ++ ((,,) NormalLevel NoPkgQual . noLoc <$> extra_sig_imports)
    
    931
    -                           ++ ((,,) NormalLevel NoPkgQual . noLoc <$> implicit_sigs),
    
    930
    +                           ++ ((,,) NormalLevel NoPkgQual . noLoc <$> extra_sig_imports),
    
    932 931
                 -- This is our hack to get the parse tree to the right spot
    
    933 932
                 ms_parsed_mod = Just (HsParsedModule {
    
    934 933
                         hpm_module = hsmod,
    

  • compiler/GHC/Driver/Downsweep.hs
    ... ... @@ -5,6 +5,8 @@
    5 5
     {-# LANGUAGE RecordWildCards #-}
    
    6 6
     {-# LANGUAGE BlockArguments #-}
    
    7 7
     {-# LANGUAGE ViewPatterns #-}
    
    8
    +
    
    9
    +-- | See Note [The ModuleGraph]
    
    8 10
     module GHC.Driver.Downsweep
    
    9 11
       ( downsweep
    
    10 12
       , downsweepThunk
    
    ... ... @@ -91,7 +93,7 @@ import GHC.Unit.Module.Deps
    91 93
     import qualified GHC.Unit.Home.Graph as HUG
    
    92 94
     import GHC.Unit.Module.Stage
    
    93 95
     
    
    94
    -import Data.Either ( rights, partitionEithers, lefts )
    
    96
    +import Data.Either ( partitionEithers, lefts )
    
    95 97
     import qualified Data.Map as Map
    
    96 98
     import qualified Data.Set as Set
    
    97 99
     
    
    ... ... @@ -111,19 +113,39 @@ import Control.Monad.Trans.Reader
    111 113
     import qualified Data.Map.Strict as M
    
    112 114
     import Control.Monad.Trans.Class
    
    113 115
     import System.IO.Unsafe (unsafeInterleaveIO)
    
    116
    +import Data.IORef
    
    117
    +import qualified Data.List.NonEmpty as NE
    
    114 118
     
    
    115 119
     {-
    
    116
    -Note [Downsweep and the ModuleGraph]
    
    117
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    120
    +Note [The ModuleGraph]
    
    121
    +~~~~~~~~~~~~~~~~~~~~~~
    
    122
    +The 'ModuleGraph' stores the relationship between all the modules, units, and
    
    123
    +instantiations in the current session, allowing e.g. to answer questions about
    
    124
    +the transitive closure of the imports.
    
    125
    +
    
    126
    +* A /node/ of the `ModuleGraph`, of type `ModuleGraphNode`, corresponds
    
    127
    +  1-1 with a home-package module of source code, N.hs or N.hs-boot.
    
    128
    +  See the haddocks of `ModuleGraphNode`.
    
    129
    +
    
    130
    +  The `ModuleNodeInfo` field of the `ModuleGraphNode` contains a `ModSummary`
    
    131
    +  that in turn describes where the source file is (its `ModLocation`), when it
    
    132
    +  was read, its contents etc. See Note [Module Types in the ModuleGraph].
    
    133
    +
    
    134
    +  Each node has a distinct `NodeKey` (an instance of Ord); the function
    
    135
    +        mkNodeKey :: ModuleGraphNode -> NodeKey
    
    136
    +  get the `NodeKey` of a node
    
    118 137
     
    
    119
    -The ModuleGraph stores the relationship between all the modules, units, and
    
    120
    -instantiations in the current session.
    
    138
    +* An /edge/ of the `ModuleGraph` from N1 to N2 typically corresponds to a
    
    139
    +  direct import of module N2 in module N1: one edge for each import.
    
    140
    +  Imports of modules from non-home-packages are featured in the `ModuleGraph`
    
    141
    +  as `UnitNode`s, or `InstantiationNodes` when backpack is involved.
    
    121 142
     
    
    122
    -When we do downsweep, we build up a new ModuleGraph, starting from the root
    
    123
    -modules. By following all the dependencies we construct a graph which allows
    
    124
    -us to answer questions about the transitive closure of the imports.
    
    143
    +  Each node contains a list of all its out-edges or, more precisely, of the
    
    144
    +  `NodeKey`s of its direct dependencies.
    
    125 145
     
    
    126
    -The module graph is accessible in the HscEnv.
    
    146
    +Because a node in the `ModuleGraph` describes the precise dependencies of the module, each node has its
    
    147
    +own `UnitId`.  Remember, a single module can be compiled against many different versions of a library; but
    
    148
    +once we fix its dependencies we can compile it, and give it a `UnitId`.  See Note [About units] in GHC.Unit.
    
    127 149
     
    
    128 150
     When is this graph constructed?
    
    129 151
     
    
    ... ... @@ -140,17 +162,54 @@ When is this graph constructed?
    140 162
     
    
    141 163
     The result is having a uniform graph available for the whole compilation pipeline.
    
    142 164
     
    
    143
    --}
    
    165
    +See Note [Downsweep Control Flow and Caching] for implementation details of
    
    166
    +the algorithm and caching.
    
    167
    +
    
    168
    +Note [Downsweep: building and maintaining the module graph]
    
    169
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    170
    +The module graph can be built from scratch by starting from a set of /root nodes/
    
    171
    +and exploring their dependencies. This is done by `GHC.Driver.Downsweep.downsweep`.
    
    172
    +
    
    173
    +Another scenario is when we already /have/ a `ModuleGraph` and want to update
    
    174
    +it (e.g. to reflect any file-system changes that have taken place since the
    
    175
    +last invocation of `downsweep`) or augment it by exploring new roots (e.g. for
    
    176
    +incrementally constructing a ModuleGraph using the GHC API; See #27054). So
    
    177
    +`downsweep` takes a `Maybe ModuleGraph` as one of its arguments.
    
    178
    +
    
    179
    +Downsweep iteratively *expands* each so-called 'DownsweepNode' into a list of
    
    180
    +its dependencies, and recursively traverses all reachable nodes in a
    
    181
    +depth-first order using 'dfsBuild'. A 'DownsweepNode' is *expanded* by 'dsNodeExpand':
    
    144 182
     
    
    145
    --- This caches the answer to the question, if we are in this unit, what does
    
    146
    --- an import of this module mean.
    
    147
    -type DownsweepCache = M.Map (UnitId, PkgQual, ModuleNameWithIsBoot) [Either DriverMessages ModuleNodeInfo]
    
    183
    +  dsNodeExpand :: DownsweepNode -> DownsweepM (NodeRes (ModuleGraphNode, [DownsweepNode]))
    
    148 184
     
    
    149
    -moduleGraphNodeMap :: ModuleGraph -> M.Map NodeKey ModuleGraphNode
    
    150
    -moduleGraphNodeMap graph
    
    151
    -    = M.fromList [(mkNodeKey node, node) | node <- mgModSummaries' graph]
    
    185
    +Most notably:
    
    152 186
     
    
    187
    +  - 'DSMod' (Module-based) nodes can be expanded by preprocessing and
    
    188
    +  parsing the module header, then listing the imports (direct and SOURCE imports)
    
    189
    +  (see 'expandModuleSummary' and 'expandFixedModuleNode')
    
    190
    +
    
    191
    +  - 'DSUnit' is expanded by finding the unit dependencies of that unit by id
    
    192
    +  (see 'expandUnitNode').
    
    193
    +
    
    194
    +Besides its dependencies, expanding a 'DownsweepNode' produces a
    
    195
    +'ModuleGraphNode'. The final 'ModuleGraph' is constructed from the list of
    
    196
    +'ModuleGraphNode's accumulated by expanding all reachable 'DownsweepNode's.
    
    197
    +
    
    198
    +A 'ModuleGraphNode' is essentially the resolved version of 'DownsweepNode':
    
    199
    +it records the payload (e.g. a Module) *and* its dependencies, unlike
    
    200
    +'DownsweepNode' which has the just the payload that is used as a seed (and
    
    201
    +potentially some context information, like the current home-unit)
    
    202
    +
    
    203
    +TL;DR: We recursively traverse 'DownsweepNodes' to discover and build the 'ModuleGraph'.
    
    204
    +
    
    205
    +See also Note [Downsweep Control Flow and Caching] for implementation details.
    
    206
    +See Note [The ModuleGraph] for an overview when we do downsweep.
    
    207
    +-}
    
    208
    +
    
    209
    +-----------------------------------------------------------------------------
    
    210
    +-- * Top-level entry to downsweep
    
    153 211
     -----------------------------------------------------------------------------
    
    212
    +
    
    154 213
     --
    
    155 214
     -- | Downsweep (dependency analysis) for --make mode
    
    156 215
     --
    
    ... ... @@ -162,7 +221,7 @@ moduleGraphNodeMap graph
    162 221
     -- cache to avoid recalculating a module summary if the source is
    
    163 222
     -- unchanged.
    
    164 223
     --
    
    165
    --- Downsweeping can start from scratch for from a given module graph. In the
    
    224
    +-- Downsweeping can start from scratch or from a given module graph. In the
    
    166 225
     -- latter case, the given graph is fully included in the resulting graph, even
    
    167 226
     -- if parts of it are not reachable from any of the given roots. When an import
    
    168 227
     -- is processed, the source of the imported module is not consulted if this
    
    ... ... @@ -178,6 +237,8 @@ moduleGraphNodeMap graph
    178 237
     --
    
    179 238
     -- It will also turn on code generation for any modules that need it by calling
    
    180 239
     -- 'enableCodeGenForTH'.
    
    240
    +--
    
    241
    +-- See also Note [The ModuleGraph]
    
    181 242
     downsweep :: HscEnv
    
    182 243
               -> (GhcMessage -> AnyGhcDiagnostic)
    
    183 244
               -> Maybe Messager
    
    ... ... @@ -195,8 +256,11 @@ downsweep :: HscEnv
    195 256
                     -- (Modules, IsBoot) identifiers, unless the Bool is true in
    
    196 257
                     -- which case there can be repeats
    
    197 258
     downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allow_dup_roots = do
    
    198
    -  n_jobs <- mkWorkerLimit (hsc_dflags hsc_env)
    
    199
    -  (root_errs, root_summaries) <- rootSummariesParallel n_jobs hsc_env diag_wrapper msg summary
    
    259
    +  n_jobs     <- mkWorkerLimit (hsc_dflags hsc_env)
    
    260
    +  summ_cache <- newIORef (mkModSummaryCache (zip old_summaries (repeat SummOld)))
    
    261
    +  imps_cache <- newIORef Map.empty
    
    262
    +  (root_errs, root_summaries) <- rootSummariesParallel n_jobs hsc_env diag_wrapper msg
    
    263
    +                                   (getRootSummary excl_mods summ_cache imps_cache)
    
    200 264
       let closure_errs = checkHomeUnitsClosed unit_env
    
    201 265
           unit_env = hsc_unit_env hsc_env
    
    202 266
     
    
    ... ... @@ -204,9 +268,13 @@ downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allo
    204 268
     
    
    205 269
       case all_errs of
    
    206 270
         [] -> do
    
    207
    -       (downsweep_errs, downsweep_nodes) <- downsweepFromRootNodes hsc_env old_summary_map maybe_base_graph excl_mods allow_dup_roots DownsweepUseCompile (map ModuleNodeCompile root_summaries) []
    
    271
    +       (downsweep_errs, downsweep_nodes) <-
    
    272
    +          downsweepFromRootNodes hsc_env summ_cache imps_cache maybe_base_graph
    
    273
    +            excl_mods allow_dup_roots DownsweepUseCompile (map ModuleNodeCompile root_summaries) []
    
    208 274
     
    
    209
    -       let (other_errs, unit_nodes) = partitionEithers $ HUG.unitEnv_foldWithKey (\nodes uid hue -> nodes ++ unitModuleNodes downsweep_nodes uid hue) [] (hsc_HUG hsc_env)
    
    275
    +       let (other_errs, unit_nodes) = partitionEithers $
    
    276
    +              HUG.unitEnv_foldWithKey (\nodes uid hue -> nodes ++ unitModuleNodes downsweep_nodes uid hue) []
    
    277
    +                                      (hsc_HUG hsc_env)
    
    210 278
     
    
    211 279
            let all_nodes = downsweep_nodes ++ unit_nodes
    
    212 280
            let all_errs = downsweep_errs ++ other_errs
    
    ... ... @@ -222,22 +290,40 @@ downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allo
    222 290
            return (all_errs, th_configured_nodes)
    
    223 291
         _  -> return (all_errs, emptyMG)
    
    224 292
       where
    
    225
    -    summary = getRootSummary excl_mods old_summary_map
    
    226
    -
    
    227
    -    -- A cache from file paths to the already summarised modules. The same file
    
    228
    -    -- can be used in multiple units so the map is also keyed by which unit the
    
    229
    -    -- file was used in.
    
    230
    -    -- Reuse these if we can because the most expensive part of downsweep is
    
    231
    -    -- reading the headers.
    
    232
    -    old_summary_map :: M.Map (UnitId, OsPath) ModSummary
    
    233
    -    old_summary_map =
    
    234
    -      M.fromList [((ms_unitid ms, msHsFileOsPath ms), ms) | ms <- old_summaries]
    
    235
    -
    
    236 293
         -- Dependencies arising on a unit (backpack and module linking deps)
    
    237 294
         unitModuleNodes :: [ModuleGraphNode] -> UnitId -> HomeUnitEnv -> [Either (Messages DriverMessage) ModuleGraphNode]
    
    238 295
         unitModuleNodes summaries uid hue =
    
    239 296
           maybeToList (linkNodes summaries uid hue)
    
    240 297
     
    
    298
    +    -- The linking plan for each module. If we need to do linking for a home unit
    
    299
    +    -- then this function returns a graph node which depends on all the modules in the home unit.
    
    300
    +
    
    301
    +    -- At the moment nothing can depend on these LinkNodes.
    
    302
    +    linkNodes :: [ModuleGraphNode] -> UnitId -> HomeUnitEnv -> Maybe (Either (Messages DriverMessage) ModuleGraphNode)
    
    303
    +    linkNodes summaries uid hue =
    
    304
    +      let dflags = homeUnitEnv_dflags hue
    
    305
    +          ofile = outputFile_ dflags
    
    306
    +
    
    307
    +          unit_nodes :: [NodeKey]
    
    308
    +          unit_nodes = map mkNodeKey (filter ((== uid) . mgNodeUnitId) summaries)
    
    309
    +      -- Issue a warning for the confusing case where the user
    
    310
    +      -- said '-o foo' but we're not going to do any linking.
    
    311
    +      -- We attempt linking if either (a) one of the modules is
    
    312
    +      -- called Main, or (b) the user said -no-hs-main, indicating
    
    313
    +      -- that main() is going to come from somewhere else.
    
    314
    +      --
    
    315
    +          no_hs_main = gopt Opt_NoHsMain dflags
    
    316
    +
    
    317
    +          main_sum = any (== NodeKey_Module (ModNodeKeyWithUid (GWIB (mainModuleNameIs dflags) NotBoot) uid)) unit_nodes
    
    318
    +
    
    319
    +          do_linking =  main_sum || no_hs_main || ghcLink dflags == LinkDynLib || ghcLink dflags == LinkStaticLib || ghcLink dflags == LinkBytecodeLib
    
    320
    +
    
    321
    +      in if | isExecutableLink (ghcLink dflags) && isJust ofile && not do_linking ->
    
    322
    +                Just (Left $ singleMessage $ mkPlainErrorMsgEnvelope noSrcSpan (DriverRedirectedNoMain $ mainModuleNameIs dflags))
    
    323
    +            -- This should be an error, not a warning (#10895).
    
    324
    +            | ghcLink dflags /= NoLink, do_linking -> Just (Right (LinkNode unit_nodes uid))
    
    325
    +            | otherwise  -> Nothing
    
    326
    +
    
    241 327
     -- | Calculate the module graph starting from a single ModSummary. The result is a
    
    242 328
     -- thunk, which when forced will perform the downsweep. This is useful in oneshot
    
    243 329
     -- mode where the module graph may never be needed.
    
    ... ... @@ -245,7 +331,9 @@ downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allo
    245 331
     downsweepThunk :: HscEnv -> ModSummary -> IO ModuleGraph
    
    246 332
     downsweepThunk hsc_env mod_summary = unsafeInterleaveIO $ do
    
    247 333
       debugTraceMsg (hsc_logger hsc_env) 3 $ text "Computing Module Graph thunk..."
    
    248
    -  ~(errs, mg) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed [ModuleNodeCompile mod_summary] []
    
    334
    +  summs <- newIORef (mkModSummaryCache [(mod_summary,SummOld)])
    
    335
    +  imps  <- newIORef mempty
    
    336
    +  ~(errs, mg) <- downsweepFromRootNodes hsc_env summs imps Nothing [] True DownsweepUseFixed [ModuleNodeCompile mod_summary] []
    
    249 337
       let dflags = hsc_dflags hsc_env
    
    250 338
       liftIO $ printOrThrowDiagnostics (hsc_logger hsc_env)
    
    251 339
                                        (initPrintConfig dflags)
    
    ... ... @@ -269,82 +357,19 @@ downsweepInteractiveImports hsc_env ic = unsafeInterleaveIO $ do
    269 357
       debugTraceMsg (hsc_logger hsc_env) 3 $ (text "Computing Interactive Module Graph thunk...")
    
    270 358
       let imps = ic_imports (hsc_IC hsc_env)
    
    271 359
     
    
    272
    -  let interactive_mn = icInteractiveModule ic
    
    273
    -  -- No sensible value for ModLocation.. if you hit this panic then you probably
    
    274
    -  -- need to add proper support for modules without any source files to the driver.
    
    275
    -  let ml = pprPanic "modLocation" (ppr interactive_mn <+> ppr imps)
    
    276
    -  let key = moduleToMnk interactive_mn NotBoot
    
    277
    -  let node_type = ModuleNodeFixed key ml
    
    360
    +      interactive_mn = icInteractiveModule ic
    
    278 361
     
    
    279 362
       -- The existing nodes in the module graph. This will be populated when GHCi runs
    
    280 363
       -- :load. Any home package modules need to already be in here.
    
    281
    -  let cached_nodes = Map.fromList [ (mkNodeKey n, n) | n <- mg_mss (hsc_mod_graph hsc_env) ]
    
    282
    -
    
    283
    -  (module_edges, graph) <- loopFromInteractive hsc_env (map mkEdge imps) cached_nodes
    
    284
    -  let interactive_node = ModuleNode module_edges node_type
    
    285
    -
    
    286
    -  let all_nodes  = M.elems graph
    
    287
    -  return $ mkModuleGraph (interactive_node : all_nodes)
    
    288
    -
    
    289
    -  where
    
    290
    - --
    
    291
    -    mkEdge :: InteractiveImport -> Either ModuleNodeEdge (UnitId, ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))
    
    292
    -    -- A simple edge to a module from the same home unit
    
    293
    -    mkEdge (IIModule n) =
    
    294
    -      let
    
    295
    -        mod_node_key = ModNodeKeyWithUid
    
    296
    -          { mnkModuleName = GWIB (moduleName n) NotBoot
    
    297
    -          , mnkUnitId =
    
    298
    -              -- 'toUnitId' is safe here, as we can't import modules that
    
    299
    -              -- don't have a 'UnitId'.
    
    300
    -              toUnitId (moduleUnit n)
    
    301
    -          }
    
    302
    -        mod_node_edge =
    
    303
    -          ModuleNodeEdge NormalLevel (NodeKey_Module mod_node_key)
    
    304
    -      in Left mod_node_edge
    
    305
    -    -- A complete import statement
    
    306
    -    mkEdge (IIDecl i) =
    
    307
    -      let lvl = convImportLevel (ideclLevelSpec i)
    
    308
    -          wanted_mod = unLoc (ideclName i)
    
    309
    -          is_boot = ideclSource i
    
    310
    -          mb_pkg = renameRawPkgQual (hsc_unit_env hsc_env) (unLoc $ ideclName i) (ideclPkgQual i)
    
    311
    -          unitId = homeUnitId $ hsc_home_unit hsc_env
    
    312
    -      in Right (unitId, lvl, mb_pkg, GWIB (noLoc wanted_mod) is_boot)
    
    313
    -
    
    314
    -loopFromInteractive :: HscEnv
    
    315
    -                    -> [Either ModuleNodeEdge (UnitId, ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))]
    
    316
    -                    -> M.Map NodeKey ModuleGraphNode
    
    317
    -                    -> IO ([ModuleNodeEdge],M.Map NodeKey ModuleGraphNode)
    
    318
    -loopFromInteractive _ [] cached_nodes = return ([], cached_nodes)
    
    319
    -loopFromInteractive hsc_env (edge:edges) cached_nodes =
    
    320
    -  case edge of
    
    321
    -    Left edge -> do
    
    322
    -        (edges, cached_nodes') <- loopFromInteractive hsc_env edges cached_nodes
    
    323
    -        return (edge : edges, cached_nodes')
    
    324
    -    Right (unitId, lvl, mb_pkg, GWIB wanted_mod is_boot) -> do
    
    325
    -      let home_unit = ue_unitHomeUnit unitId (hsc_unit_env hsc_env)
    
    326
    -      let k _ loc mod =
    
    327
    -            let key = moduleToMnk mod is_boot
    
    328
    -            in return $ FoundHome (ModuleNodeFixed key loc)
    
    329
    -      found <- liftIO $ summariseModuleDispatch k hsc_env home_unit is_boot wanted_mod mb_pkg []
    
    330
    -      case found of
    
    331
    -        -- Case 1: Home modules have to already be in the cache.
    
    332
    -        FoundHome (ModuleNodeFixed mod _) -> do
    
    333
    -          let edge = ModuleNodeEdge lvl (NodeKey_Module mod)
    
    334
    -          -- Note: Does not perform any further downsweep as the module must already be in the cache.
    
    335
    -          (edges, cached_nodes') <- loopFromInteractive hsc_env edges cached_nodes
    
    336
    -          return (edge : edges, cached_nodes')
    
    337
    -        -- Case 2: External units may not be in the cache, if we haven't already initialised the
    
    338
    -        -- module graph. We can construct the module graph for those here by calling loopUnit.
    
    339
    -        External uid -> do
    
    340
    -          let hsc_env' = hscSetActiveHomeUnit home_unit hsc_env
    
    341
    -              cached_nodes' = loopUnit hsc_env' cached_nodes [uid]
    
    342
    -              edge = ModuleNodeEdge lvl (NodeKey_ExternalUnit uid)
    
    343
    -          (edges, cached_nodes') <- loopFromInteractive hsc_env edges cached_nodes'
    
    344
    -          return (edge : edges, cached_nodes')
    
    345
    -        -- And if it's not found.. just carry on and hope.
    
    346
    -        _ -> loopFromInteractive hsc_env edges cached_nodes
    
    364
    +  let cached_nodes = Map.fromList [ (mkNodeKey n, NSuccess n) | n <- mg_mss (hsc_mod_graph hsc_env) ]
    
    347 365
     
    
    366
    +  summ_cache <- newIORef mempty
    
    367
    +  imps_cache <- newIORef mempty
    
    368
    +  let env = DownsweepEnv hsc_env DownsweepUseFixed{-or DownsweepUseCompile?-} summ_cache imps_cache []
    
    369
    +  graph <- runDownsweepM env do
    
    370
    +    loopFromInteractive cached_nodes interactive_mn imps
    
    371
    +  let all_nodes  = [s | NSuccess s <- M.elems graph ]
    
    372
    +  return $ mkModuleGraph all_nodes
    
    348 373
     
    
    349 374
     -- | Create a module graph from a list of installed modules.
    
    350 375
     -- This is used by the loader when we need to load modules but there
    
    ... ... @@ -373,7 +398,9 @@ downsweepInstalledModules hsc_env mods = do
    373 398
                 _ -> throwGhcException $ ProgramError $ showSDoc (hsc_dflags hsc_env) $ text "downsweepInstalledModules: Could not find installed module" <+> ppr i
    
    374 399
     
    
    375 400
         nodes <- mapM process installed_mods
    
    376
    -    (errs, mg) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed nodes external_uids
    
    401
    +    summs <- newIORef mempty
    
    402
    +    imps  <- newIORef mempty
    
    403
    +    (errs, mg) <- downsweepFromRootNodes hsc_env summs imps Nothing [] True DownsweepUseFixed nodes external_uids
    
    377 404
     
    
    378 405
         -- Similarly here, we should really not get any errors, but print them out if we do.
    
    379 406
         let dflags = hsc_dflags hsc_env
    
    ... ... @@ -384,7 +411,35 @@ downsweepInstalledModules hsc_env mods = do
    384 411
     
    
    385 412
         return (mkModuleGraph mg)
    
    386 413
     
    
    414
    +-----------------------------------------------------------------------------
    
    415
    +-- * Orchestrator: downsweepFromRootNodes
    
    416
    +-----------------------------------------------------------------------------
    
    387 417
     
    
    418
    +type ModSummaryCache = IORef ModSummaryCacheMap
    
    419
    +type ImportsCache    = IORef ImportsCacheMap
    
    420
    +
    
    421
    +-- | A cache from file paths to the already summarised modules. The same file
    
    422
    +-- can be used in multiple units so the map is actually also keyed by which
    
    423
    +-- unit the file was used in.
    
    424
    +--
    
    425
    +-- We want to reuse ModSummaries as far as possible because the most expensive
    
    426
    +-- part of downsweep is reading and parsing the headers.
    
    427
    +--
    
    428
    +-- See Note [Downsweep Control Flow and Caching]
    
    429
    +type ModSummaryCacheMap
    
    430
    +      -- The cache can't be keyed by 'Module' because that isn't sufficient to
    
    431
    +      -- distinguish .hs from .hs-boot files. Use path+unit instead.
    
    432
    +      = ( M.Map (UnitId, OsPath) (Either DriverMessages (ModSummary, SummProvenance)) )
    
    433
    +
    
    434
    +-- | A 'ModSummary's provenance during downsweep: an old previously constructed
    
    435
    +-- ModSummary, that might be potentially outdated, or a freshly constructed one
    
    436
    +-- during this downsweep which is certainly up to date?
    
    437
    +data SummProvenance
    
    438
    +  -- | Constructed during this downsweep: trivially up to date
    
    439
    +  = SummFresh
    
    440
    +  -- | Carried over from a previous run: may be stale, must be hash-checked
    
    441
    +  -- (and considered by -fforce-recomp)
    
    442
    +  | SummOld
    
    388 443
     
    
    389 444
     -- | Whether downsweep should use compiler or fixed nodes. Compile nodes are used
    
    390 445
     -- by --make mode, and fixed nodes by oneshot mode.
    
    ... ... @@ -397,7 +452,8 @@ data DownsweepMode = DownsweepUseCompile | DownsweepUseFixed
    397 452
     -- This function will start at the given roots, and traverse downwards to find
    
    398 453
     -- all the dependencies, all the way to the leaf units.
    
    399 454
     downsweepFromRootNodes :: HscEnv
    
    400
    -                  -> M.Map (UnitId, OsPath) ModSummary
    
    455
    +                  -> ModSummaryCache
    
    456
    +                  -> ImportsCache
    
    401 457
                       -> Maybe ModuleGraph
    
    402 458
                       -> [ModuleName]
    
    403 459
                       -> Bool
    
    ... ... @@ -405,190 +461,347 @@ downsweepFromRootNodes :: HscEnv
    405 461
                       -> [ModuleNodeInfo] -- ^ The starting ModuleNodeInfo
    
    406 462
                       -> [UnitId] -- ^ The starting units
    
    407 463
                       -> IO ([DriverMessages], [ModuleGraphNode])
    
    408
    -downsweepFromRootNodes hsc_env old_summaries maybe_base_graph excl_mods allow_dup_roots mode root_nodes root_uids
    
    409
    -   = do
    
    410
    -       let root_map = mkRootMap root_nodes
    
    411
    -       checkDuplicates root_map
    
    412
    -       let env = DownsweepEnv hsc_env mode old_summaries excl_mods
    
    413
    -       (deps', map0) <- runDownsweepM env  $ do
    
    414
    -                    let base_nodes = maybe M.empty moduleGraphNodeMap maybe_base_graph
    
    415
    -                    (module_deps, map0) <- loopModuleNodeInfos root_nodes (base_nodes, root_map)
    
    416
    -                    let all_deps = loopUnit hsc_env module_deps root_uids
    
    417
    -                    let all_instantiations =  getHomeUnitInstantiations hsc_env
    
    418
    -                    deps' <- loopInstantiations all_instantiations all_deps
    
    419
    -                    return (deps', map0)
    
    420
    -
    
    421
    -
    
    422
    -       let downsweep_errs = lefts $ concat $ M.elems map0
    
    423
    -           downsweep_nodes = M.elems deps'
    
    424
    -
    
    425
    -       return (downsweep_errs, downsweep_nodes)
    
    426
    -     where
    
    427
    -        getHomeUnitInstantiations :: HscEnv -> [(UnitId, InstantiatedUnit)]
    
    428
    -        getHomeUnitInstantiations hsc_env = HUG.unitEnv_foldWithKey (\nodes uid hue -> nodes ++  instantiationNodes uid (homeUnitEnv_units hue)) [] (hsc_HUG hsc_env)
    
    429
    -
    
    430
    -        -- In a root module, the filename is allowed to diverge from the module
    
    431
    -        -- name, so we have to check that there aren't multiple root files
    
    432
    -        -- defining the same module (otherwise the duplicates will be silently
    
    433
    -        -- ignored, leading to confusing behaviour).
    
    434
    -        checkDuplicates
    
    435
    -          :: DownsweepCache
    
    436
    -          -> IO ()
    
    437
    -        checkDuplicates root_map
    
    438
    -           | not allow_dup_roots
    
    439
    -           , dup_root:_ <- dup_roots = liftIO $ multiRootsErr sec dup_root
    
    440
    -           | otherwise = pure ()
    
    441
    -           where
    
    442
    -             sec = initSourceErrorContext (hsc_dflags hsc_env)
    
    443
    -             dup_roots :: [[ModuleNodeInfo]]        -- Each at least of length 2
    
    444
    -             dup_roots = filterOut isSingleton $ map rights (M.elems root_map)
    
    445
    -
    
    446
    -
    
    447
    -calcDeps :: ModSummary -> [(ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))]
    
    448
    -calcDeps ms =
    
    449
    -  -- Add a dependency on the HsBoot file if it exists
    
    450
    -  -- This gets passed to the loopImports function which just ignores it if it
    
    451
    -  -- can't be found.
    
    452
    -  [(NormalLevel, NoPkgQual, GWIB (noLoc $ ms_mod_name ms) IsBoot) | NotBoot <- [isBootSummary ms] ] ++
    
    453
    -  [(lvl, b, c) | (lvl, b, c) <- msDeps ms ]
    
    454
    -
    
    464
    +downsweepFromRootNodes hsc_env summ_cache imps_cache maybe_base_graph excl_mods allow_dup_roots mode root_nodes root_uids = do
    
    465
    +     when (not allow_dup_roots) $
    
    466
    +       case root_duplicates of
    
    467
    +         []           -> return ()
    
    468
    +         (dup_root:_) -> multiRootsErr sec dup_root
    
    469
    +     modifyImpsCache imps_cache (`M.union` mkRootMap root_nodes) -- add root nodes to imports cache
    
    470
    +     let env = DownsweepEnv hsc_env mode summ_cache imps_cache excl_mods
    
    471
    +     deps' <- runDownsweepM env  $ do
    
    472
    +        let base_nodes = maybe M.empty moduleGraphNodeMap maybe_base_graph
    
    473
    +        module_deps <- loopModuleNodeInfos base_nodes root_nodes
    
    474
    +        all_deps    <- loopUnits module_deps (hscActiveUnitId hsc_env) root_uids
    
    475
    +        deps'       <- loopInstantiations all_deps (getHomeUnitInstantiations hsc_env)
    
    476
    +        return deps'
    
    477
    +     f_cache <- readIORef summ_cache
    
    478
    +     let downsweep_errs = lefts (M.elems f_cache)
    
    479
    +         downsweep_nodes = [ s | NSuccess s <- M.elems deps' ]
    
    480
    +
    
    481
    +     return (downsweep_errs, downsweep_nodes)
    
    482
    +  where
    
    483
    +    getHomeUnitInstantiations :: HscEnv -> [(UnitId, InstantiatedUnit)]
    
    484
    +    getHomeUnitInstantiations hsc_env = HUG.unitEnv_foldWithKey
    
    485
    +      (\nodes uid hue -> nodes ++  instantiationNodes uid (homeUnitEnv_units hue)) [] (hsc_HUG hsc_env)
    
    486
    +
    
    487
    +    -- In a root module, the filename is allowed to diverge from the module
    
    488
    +    -- name, so we have to check that there aren't multiple root files
    
    489
    +    -- defining the same module (otherwise the duplicates will be silently
    
    490
    +    -- ignored, leading to confusing behaviour).
    
    491
    +    root_duplicates :: [NE.NonEmpty ModuleNodeInfo]
    
    492
    +    root_duplicates = mapMaybe takes2 (M.elems root_map)
    
    493
    +       where
    
    494
    +         takes2 (a:as@(_:_)) = Just (a NE.:| as) -- Each at least of length 2
    
    495
    +         takes2 _            = Nothing
    
    496
    +
    
    497
    +         root_map = Map.fromListWith (flip (++))
    
    498
    +           [ ((moduleNodeInfoUnitId s, moduleNodeInfoMnwib s), [s])
    
    499
    +           | s <- root_nodes ]
    
    500
    +
    
    501
    +    moduleGraphNodeMap :: ModuleGraph -> M.Map NodeKey (NodeRes ModuleGraphNode)
    
    502
    +    moduleGraphNodeMap graph
    
    503
    +        = M.fromList [(mkNodeKey node, NSuccess node) | node <- mgModSummaries' graph]
    
    504
    +
    
    505
    +    sec = initSourceErrorContext (hsc_dflags hsc_env)
    
    506
    +
    
    507
    +--------------------------------------------------------------------------------
    
    508
    +-- ** 'DownsweepM'
    
    509
    +--------------------------------------------------------------------------------
    
    455 510
     
    
    456 511
     type DownsweepM a = ReaderT DownsweepEnv IO a
    
    457 512
     data DownsweepEnv = DownsweepEnv {
    
    458 513
           downsweep_hsc_env :: HscEnv
    
    459 514
         , _downsweep_mode :: DownsweepMode
    
    460
    -    , _downsweep_old_summaries :: M.Map (UnitId, OsPath) ModSummary
    
    515
    +    , _downsweep_summaries_cache :: ModSummaryCache
    
    516
    +    , downsweep_imports_cache :: ImportsCache
    
    461 517
         , _downsweep_excl_mods :: [ModuleName]
    
    462 518
     }
    
    463 519
     
    
    520
    +mkModSummaryCache :: [(ModSummary, SummProvenance)] -> ModSummaryCacheMap
    
    521
    +mkModSummaryCache summs = foldl' (flip (uncurry addModSummaryCache)) M.empty summs
    
    522
    +
    
    523
    +addModSummaryCache :: ModSummary -> SummProvenance -> ModSummaryCacheMap -> ModSummaryCacheMap
    
    524
    +addModSummaryCache ms pr fe = upd_fe fe
    
    525
    +  where
    
    526
    +    upd_fe fe
    
    527
    +      | Just src_fn_os <- ml_hs_file_ospath (ms_location ms)
    
    528
    +      = M.insert (ms_unitid ms, src_fn_os) (Right (ms, pr)) fe
    
    529
    +      | otherwise = fe
    
    530
    +
    
    531
    +modifySummCache :: ModSummaryCache -> (ModSummaryCacheMap -> ModSummaryCacheMap) -> IO ()
    
    532
    +modifyImpsCache :: ImportsCache    -> (ImportsCacheMap    -> ImportsCacheMap)    -> IO ()
    
    533
    +modifySummCache r f = atomicModifyIORef' r (\c -> (f c, ()))
    
    534
    +modifyImpsCache r f = atomicModifyIORef' r (\c -> (f c, ()))
    
    535
    +
    
    536
    +-- | A cache from a module import (in given home unit context, with a package
    
    537
    +-- qualifier, and the imported module name (with or without SOURCE)) to the
    
    538
    +-- result of summarising that import (see 'summariseModuleDispatch').
    
    539
    +--
    
    540
    +-- See Note [Downsweep Control Flow and Caching]
    
    541
    +type ImportsCacheMap
    
    542
    +      = M.Map (UnitId, PkgQual, ModuleNameWithIsBoot) SummariseResult
    
    543
    +
    
    544
    +-- | Populate the 'ImportsCacheMap' with the root modules.
    
    545
    +mkRootMap :: [ModuleNodeInfo] -> ImportsCacheMap
    
    546
    +mkRootMap summaries = Map.fromList
    
    547
    +  [ ((moduleNodeInfoUnitId s, NoPkgQual, moduleNodeInfoMnwib s), FoundHome s) | s <- summaries ]
    
    548
    +
    
    464 549
     runDownsweepM :: DownsweepEnv -> DownsweepM a -> IO a
    
    465 550
     runDownsweepM env act = runReaderT act env
    
    466 551
     
    
    467
    -
    
    468
    -loopInstantiations :: [(UnitId, InstantiatedUnit)]
    
    469
    -                   -> M.Map NodeKey ModuleGraphNode
    
    470
    -                   -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    471
    -loopInstantiations [] done = pure done
    
    472
    -loopInstantiations ((home_uid, iud) :xs) done = do
    
    473
    -  hsc_env <- asks downsweep_hsc_env
    
    474
    -  let home_unit = ue_unitHomeUnit home_uid (hsc_unit_env hsc_env)
    
    475
    -  let hsc_env' = hscSetActiveHomeUnit home_unit hsc_env
    
    476
    -      done' = loopUnit hsc_env' done [instUnitInstanceOf iud]
    
    477
    -      payload = InstantiationNode home_uid iud
    
    478
    -  loopInstantiations xs (M.insert (mkNodeKey payload) payload done')
    
    479
    -
    
    480
    -
    
    481
    --- This loops over all the mod summaries in the dependency graph, accumulates the actual dependencies for each module/unit
    
    482
    -loopSummaries :: [ModSummary]
    
    483
    -      -> (M.Map NodeKey ModuleGraphNode,
    
    484
    -            DownsweepCache)
    
    485
    -      -> DownsweepM ((M.Map NodeKey ModuleGraphNode), DownsweepCache)
    
    486
    -loopSummaries [] done = pure done
    
    487
    -loopSummaries (ms:next) (done, summarised)
    
    488
    -  | Just {} <- M.lookup k done
    
    489
    -  = loopSummaries next (done, summarised)
    
    490
    -  -- Didn't work out what the imports mean yet, now do that.
    
    491
    -  | otherwise = do
    
    492
    -     (final_deps, done', summarised') <- loopImports (ms_unitid ms) (calcDeps ms) done summarised
    
    493
    -     -- This has the effect of finding a .hs file if we are looking at the .hs-boot file.
    
    494
    -     (_, done'', summarised'') <- loopImports (ms_unitid ms) (maybeToList hs_file_for_boot) done' summarised'
    
    495
    -     loopSummaries next (M.insert k (ModuleNode final_deps (ModuleNodeCompile ms)) done'', summarised'')
    
    552
    +loopDownsweepNodes  :: M.Map NodeKey (NodeRes ModuleGraphNode) -> [DownsweepNode]               -> DownsweepM (M.Map NodeKey (NodeRes ModuleGraphNode))
    
    553
    +loopModuleNodeInfos :: M.Map NodeKey (NodeRes ModuleGraphNode) -> [ModuleNodeInfo]              -> DownsweepM (M.Map NodeKey (NodeRes ModuleGraphNode))
    
    554
    +loopUnits           :: M.Map NodeKey (NodeRes ModuleGraphNode) -> UnitId -> [UnitId]            -> DownsweepM (M.Map NodeKey (NodeRes ModuleGraphNode))
    
    555
    +loopInstantiations  :: M.Map NodeKey (NodeRes ModuleGraphNode) -> [(UnitId, InstantiatedUnit)]  -> DownsweepM (M.Map NodeKey (NodeRes ModuleGraphNode))
    
    556
    +loopFromInteractive :: M.Map NodeKey (NodeRes ModuleGraphNode) -> Module -> [InteractiveImport] -> DownsweepM (M.Map NodeKey (NodeRes ModuleGraphNode))
    
    557
    +loopDownsweepNodes  base_map nodes = dfsBuild (Just base_map) nodes dsNodeInfoKey dsNodeExpand
    
    558
    +loopModuleNodeInfos base_map       = loopDownsweepNodes base_map . map DSMod
    
    559
    +loopUnits           base_map homud = loopDownsweepNodes base_map . map (DSUnit homud)
    
    560
    +loopInstantiations  base_map       = loopDownsweepNodes base_map . map (uncurry DSInst)
    
    561
    +loopFromInteractive base_map m     = loopDownsweepNodes base_map . (:[]) . DSInteractive m
    
    562
    +
    
    563
    +--------------------------------------------------------------------------------
    
    564
    +-- * Expanding 'DownsweepNode's into payload and node dependencies
    
    565
    +--------------------------------------------------------------------------------
    
    566
    +
    
    567
    +-- | A 'DownsweepNode' is the basic block of the downsweep algorithm which
    
    568
    +-- encompasses the types of nodes we can iteratively expand to construct the
    
    569
    +-- full module graph. See 'loopDownsweepNodes'.
    
    570
    +--
    
    571
    +-- See Note [Downsweep Control Flow and Caching]
    
    572
    +data DownsweepNode
    
    573
    +  -- | A module node to expand
    
    574
    +  = DSMod ModuleNodeInfo
    
    575
    +  -- | A unit node to expand
    
    576
    +  | DSUnit
    
    577
    +  { home_context_uid :: UnitId
    
    578
    +  -- ^ The home unit which introduced the dependency on this 'node_uid'. This
    
    579
    +  -- 'node_uid' can only be expanded in the context ('HscEnv') where
    
    580
    +  -- 'home_context_uid' is the active home unit, to make sure the package flags
    
    581
    +  -- are the ones attributed to the home package that introduced this node.
    
    582
    +  , node_uid         :: UnitId
    
    583
    +  -- ^ The unit node to expand
    
    584
    +  }
    
    585
    +  -- | FIXME: document the meaning of 'DSInst'
    
    586
    +  | DSInst
    
    587
    +  { home_context_uid :: UnitId
    
    588
    +  , instantiated_ud  :: InstantiatedUnit
    
    589
    +  }
    
    590
    +  -- | A group of interactive imports from this interactive Module
    
    591
    +  | DSInteractive Module [InteractiveImport]
    
    592
    +
    
    593
    +instance Outputable DownsweepNode where
    
    594
    +  ppr = \case
    
    595
    +    DSMod (ModuleNodeCompile ms) -> text "DSModC" <+> ppr (ms_mod_name ms)
    
    596
    +    DSMod (ModuleNodeFixed key _) -> text "DSModF" <+> ppr key
    
    597
    +    DSUnit{node_uid} -> text "DSUnit" <+> ppr node_uid
    
    598
    +    DSInst{instantiated_ud} -> text "DSInst" <+> ppr instantiated_ud
    
    599
    +    DSInteractive mod ii    -> text "DSInteractive" <+> ppr mod <+> ppr ii
    
    600
    +
    
    601
    +-- | They key by which to cache previously visited 'DownsweepNode's
    
    602
    +dsNodeInfoKey :: DownsweepNode -> NodeKey
    
    603
    +dsNodeInfoKey = \case
    
    604
    +  DSMod (ModuleNodeCompile ms)  -> NodeKey_Module (msKey ms)
    
    605
    +  DSMod (ModuleNodeFixed mod _) -> NodeKey_Module mod
    
    606
    +  DSUnit{node_uid}              -> NodeKey_ExternalUnit node_uid
    
    607
    +  DSInst{instantiated_ud}       -> NodeKey_Unit instantiated_ud
    
    608
    +  DSInteractive mod _imps       -> NodeKey_Module $ moduleToMnk mod NotBoot
    
    609
    +
    
    610
    +dsNodeExpand :: DownsweepNode -> DownsweepM (NodeRes (ModuleGraphNode, [DownsweepNode]))
    
    611
    +dsNodeExpand = \case
    
    612
    +  DSMod (ModuleNodeCompile ms)         -> expandModuleSummary ms
    
    613
    +  DSMod (ModuleNodeFixed key loc)      -> expandFixedModuleNode key loc
    
    614
    +  DSUnit{ node_uid, home_context_uid } -> expandUnitNode node_uid home_context_uid
    
    615
    +  DSInst{ instantiated_ud
    
    616
    +        , home_context_uid }           -> expandInstantiatedUnit instantiated_ud home_context_uid
    
    617
    +  DSInteractive imod iis               -> expandInteractiveImports imod iis
    
    618
    +
    
    619
    +expandModuleSummary :: ModSummary -> DownsweepM (NodeRes (ModuleGraphNode, [DownsweepNode]))
    
    620
    +expandModuleSummary ms = do -- Didn't work out what the imports mean yet, now do that.
    
    621
    +    hsc_env <- asks downsweep_hsc_env
    
    622
    +    let home_uid  = ms_unitid ms
    
    623
    +        home_unit = ue_unitHomeUnit home_uid (hsc_unit_env hsc_env)
    
    624
    +    (final_deps, todo) <- unzip <$> mapM (expandModImport home_uid home_unit) (calcDeps ms)
    
    625
    +
    
    626
    +    -- This has the effect of finding a .hs file if we are looking at the .hs-boot file.
    
    627
    +    boot_todo <-
    
    628
    +      if | HsBootFile <- ms_hsc_src ms
    
    629
    +         -> do
    
    630
    +            r <- downsweepSummarise home_unit NotBoot (noLoc $ ms_mod_name ms) NoPkgQual Nothing
    
    631
    +            case r of
    
    632
    +              FoundHome s -> pure [DSMod s]
    
    633
    +              _           -> pure []
    
    634
    +         | otherwise      -> pure []
    
    635
    +
    
    636
    +    return $ NSuccess
    
    637
    +      ( ModuleNode (catMaybes final_deps) (ModuleNodeCompile ms)
    
    638
    +      , boot_todo ++ concat todo
    
    639
    +      )
    
    496 640
       where
    
    497
    -    k = NodeKey_Module (msKey ms)
    
    498
    -
    
    499
    -    hs_file_for_boot
    
    500
    -      | HsBootFile <- ms_hsc_src ms
    
    501
    -      = Just (NormalLevel, NoPkgQual, (GWIB (noLoc $ ms_mod_name ms) NotBoot))
    
    502
    -      | otherwise
    
    503
    -      = Nothing
    
    504
    -
    
    505
    -loopModuleNodeInfos :: [ModuleNodeInfo] -> (M.Map NodeKey ModuleGraphNode, DownsweepCache) -> DownsweepM (M.Map NodeKey ModuleGraphNode, DownsweepCache)
    
    506
    -loopModuleNodeInfos is cache = foldM (flip loopModuleNodeInfo) cache is
    
    507
    -
    
    508
    -loopModuleNodeInfo :: ModuleNodeInfo -> (M.Map NodeKey ModuleGraphNode, DownsweepCache) -> DownsweepM (M.Map NodeKey ModuleGraphNode, DownsweepCache)
    
    509
    -loopModuleNodeInfo mod_node_info (done, summarised) = do
    
    510
    -  case mod_node_info of
    
    511
    -    ModuleNodeCompile ms -> do
    
    512
    -      loopSummaries [ms] (done, summarised)
    
    513
    -    ModuleNodeFixed mod ml -> do
    
    514
    -      done' <- loopFixedModule mod ml done
    
    515
    -      return (done', summarised)
    
    516
    -
    
    517
    --- NB: loopFixedModule does not take a downsweep cache, because if you
    
    518
    --- ever reach a Fixed node, everything under that also must be fixed.
    
    519
    -loopFixedModule :: ModNodeKeyWithUid -> ModLocation
    
    520
    -                -> M.Map NodeKey ModuleGraphNode
    
    521
    -                -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    522
    -loopFixedModule key loc done = do
    
    523
    -  let nk = NodeKey_Module key
    
    524
    -  hsc_env <- asks downsweep_hsc_env
    
    525
    -  case M.lookup nk done of
    
    526
    -    Just {} -> return done
    
    527
    -    Nothing -> do
    
    528
    -      -- MP: TODO, we should just read the dependency info from the interface rather than either
    
    529
    -      -- a. Loading the whole thing into the EPS (this might never nececssary and causes lots of things to be permanently loaded into memory)
    
    530
    -      -- b. Loading the whole interface into a buffer before discarding it. (wasted allocation and deserialisation)
    
    531
    -      read_result <- liftIO $
    
    532
    -        -- 1. Check if the interface is already loaded into the EPS by some other
    
    533
    -        -- part of the compiler.
    
    534
    -        lookupIfaceByModuleHsc hsc_env (mnkToModule key) >>= \case
    
    535
    -          Just iface -> return (M.Succeeded iface)
    
    536
    -          Nothing -> readIface (hsc_hooks hsc_env) (hsc_logger hsc_env) (hsc_dflags hsc_env) (hsc_NC hsc_env) (mnkToModule key) (ml_hi_file loc)
    
    537
    -      case read_result of
    
    538
    -        M.Succeeded iface -> do
    
    539
    -          -- Computer information about this node
    
    540
    -          let node_deps = ifaceDeps (mi_deps iface)
    
    541
    -              edges = map mkFixedEdge node_deps
    
    542
    -              node = ModuleNode edges (ModuleNodeFixed key loc)
    
    543
    -          foldM (loopFixedNodeKey (mnkUnitId key)) (M.insert nk node done) (bimap snd snd <$> node_deps)
    
    544
    -        -- Ignore any failure, we might try to read a .hi-boot file for
    
    545
    -        -- example, even if there is not one.
    
    546
    -        M.Failed {} ->
    
    547
    -          return done
    
    548
    -
    
    549
    -loopFixedNodeKey :: UnitId -> M.Map NodeKey ModuleGraphNode -> Either ModNodeKeyWithUid UnitId -> DownsweepM  (M.Map NodeKey ModuleGraphNode)
    
    550
    -loopFixedNodeKey _ done (Left key) = do
    
    551
    -  loopFixedImports [key] done
    
    552
    -loopFixedNodeKey home_uid done (Right uid) = do
    
    553
    -  -- Set active unit so that looking loopUnit finds the correct
    
    554
    -  -- -package flags in the unit state.
    
    555
    -  hsc_env <- asks downsweep_hsc_env
    
    556
    -  let hsc_env' = hscSetActiveUnitId home_uid hsc_env
    
    557
    -  return $ loopUnit hsc_env' done [uid]
    
    558
    -
    
    559
    -mkFixedEdge :: Either (ImportLevel, ModNodeKeyWithUid) (ImportLevel, UnitId) -> ModuleNodeEdge
    
    560
    -mkFixedEdge (Left (lvl, key)) = mkModuleEdge lvl (NodeKey_Module key)
    
    561
    -mkFixedEdge (Right (lvl, uid)) = mkModuleEdge lvl (NodeKey_ExternalUnit uid)
    
    562
    -
    
    563
    -ifaceDeps :: Dependencies -> [Either (ImportLevel, ModNodeKeyWithUid) (ImportLevel, UnitId)]
    
    564
    -ifaceDeps deps =
    
    565
    -  [ Left (tcImportLevel lvl, ModNodeKeyWithUid dep uid)
    
    566
    -  | (lvl, uid, dep) <- Set.toList (dep_direct_mods deps)
    
    567
    -  ] ++
    
    568
    -  [ Right (tcImportLevel lvl, uid)
    
    569
    -  | (lvl, uid) <- Set.toList (dep_direct_pkgs deps)
    
    570
    -  ]
    
    571
    -
    
    572
    --- Like loopImports, but we already know exactly which module we are looking for.
    
    573
    -loopFixedImports :: [ModNodeKeyWithUid]
    
    574
    -                 -> M.Map NodeKey ModuleGraphNode
    
    575
    -                 -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    576
    -loopFixedImports [] done = pure done
    
    577
    -loopFixedImports (key:keys) done = do
    
    578
    -  let nk = NodeKey_Module key
    
    579
    -  hsc_env <- asks downsweep_hsc_env
    
    580
    -  case M.lookup nk done of
    
    581
    -    Just {} -> loopFixedImports keys done
    
    582
    -    Nothing -> do
    
    641
    +    expandModImport home_uid home_unit (imp,mb_pkg,gwib) = do
    
    642
    +      let GWIB { gwib_mod = L loc mod, gwib_isBoot = is_boot } = gwib
    
    643
    +          wanted_mod = L loc mod
    
    644
    +      mb_s <- downsweepSummarise home_unit is_boot wanted_mod mb_pkg Nothing
    
    645
    +      case mb_s of
    
    646
    +        NotThere -> return
    
    647
    +          ( Nothing, [] )
    
    648
    +        External uid -> return
    
    649
    +          ( Just $ mkModuleEdge imp (NodeKey_ExternalUnit uid)
    
    650
    +          -- Specify home unit, as each unit might have a different visible package database.
    
    651
    +          , [DSUnit{node_uid = uid, home_context_uid = home_uid}] )
    
    652
    +        FoundInstantiation iud -> return
    
    653
    +          ( Just (mkModuleEdge imp (NodeKey_Unit iud)), [] )
    
    654
    +        FoundHomeWithError (_uid, _e) -> return
    
    655
    +          ( Nothing, [] )
    
    656
    +          -- the error @e@ is already stored in the summarisation cache,
    
    657
    +          -- (the IORef in DownsweepM) and will get reported at the end.
    
    658
    +        FoundHome s -> return
    
    659
    +          -- MP: This assumes that we can only instantiate non home units, which is probably fair enough for now.
    
    660
    +          ( Just $ mkModuleEdge imp (NodeKey_Module (mnKey s))
    
    661
    +          , [DSMod s] )
    
    662
    +
    
    663
    +    calcDeps :: ModSummary -> [(ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))]
    
    664
    +    calcDeps ms =
    
    665
    +      -- Add a dependency on the HsBoot file if it exists
    
    666
    +      -- This gets passed to the loopImports function which just ignores it if it
    
    667
    +      -- can't be found.
    
    668
    +      [(NormalLevel, NoPkgQual, GWIB (noLoc $ ms_mod_name ms) IsBoot) | NotBoot <- [isBootSummary ms] ] ++
    
    669
    +      [(lvl, b, c) | (lvl, b, c) <- msDeps ms ]
    
    670
    +
    
    671
    +-- | Expand a 'ModuleNodeFixed' node
    
    672
    +-- NB: If you ever reach a Fixed node, everything under that also must be fixed.
    
    673
    +expandFixedModuleNode :: ModNodeKeyWithUid -> ModLocation -> DownsweepM (NodeRes (ModuleGraphNode, [DownsweepNode]))
    
    674
    +expandFixedModuleNode key loc = do
    
    675
    +    hsc_env <- asks downsweep_hsc_env
    
    676
    +    -- MP: TODO, we should just read the dependency info from the interface rather than either
    
    677
    +    -- a. Loading the whole thing into the EPS (this might never nececssary and causes lots of things to be permanently loaded into memory)
    
    678
    +    -- b. Loading the whole interface into a buffer before discarding it. (wasted allocation and deserialisation)
    
    679
    +    read_result <- liftIO $
    
    680
    +      -- 1. Check if the interface is already loaded into the EPS by some other
    
    681
    +      -- part of the compiler.
    
    682
    +      lookupIfaceByModuleHsc hsc_env (mnkToModule key) >>= \case
    
    683
    +        Just iface -> return (M.Succeeded iface)
    
    684
    +        Nothing -> readIface (hsc_hooks hsc_env) (hsc_logger hsc_env) (hsc_dflags hsc_env) (hsc_NC hsc_env) (mnkToModule key) (ml_hi_file loc)
    
    685
    +    case read_result of
    
    686
    +      M.Succeeded iface -> do
    
    687
    +        -- Computer information about this node
    
    688
    +        let node_deps = ifaceDeps (mi_deps iface)
    
    689
    +            edges = map mkFixedEdge node_deps
    
    690
    +            node = ModuleNode edges (ModuleNodeFixed key loc)
    
    691
    +        deps' <- catMaybes <$> mapM (mk_dep hsc_env) (bimap snd snd <$> node_deps)
    
    692
    +        pure $ NSuccess (node, deps')
    
    693
    +
    
    694
    +      -- Skip any failure, we might try to read a .hi-boot file for
    
    695
    +      -- example, even if there is not one.
    
    696
    +      M.Failed {} ->
    
    697
    +        pure NSkip
    
    698
    +  where
    
    699
    +    mk_dep hsc_env (Left key) = do
    
    700
    +      -- Like expandImports, but we already know exactly which module we are looking for.
    
    583 701
           read_result <- liftIO $ findExactModule hsc_env (mnkToInstalledModule key) (mnkIsBoot key)
    
    584 702
           case read_result of
    
    585 703
             InstalledFound loc -> do
    
    586
    -          done' <- loopFixedModule key loc done
    
    587
    -          loopFixedImports keys done'
    
    704
    +          pure $ Just $ DSMod (ModuleNodeFixed key loc)
    
    588 705
             _otherwise ->
    
    589 706
               -- If the finder fails, just keep going, there will be another
    
    590
    -          -- error later.
    
    591
    -          loopFixedImports keys done
    
    707
    +          -- error later when we try to expand this dependency.
    
    708
    +          pure Nothing
    
    709
    +    mk_dep _ (Right uid_dep) = do
    
    710
    +      -- Set active unit so that looking loopUnit finds the correct
    
    711
    +      -- -package flags in the unit state.
    
    712
    +      let home_uid = mnkUnitId key
    
    713
    +      pure (Just DSUnit{node_uid=uid_dep, home_context_uid=home_uid})
    
    714
    +
    
    715
    +    mkFixedEdge :: Either (ImportLevel, ModNodeKeyWithUid) (ImportLevel, UnitId) -> ModuleNodeEdge
    
    716
    +    mkFixedEdge (Left (lvl, key))  = mkModuleEdge lvl (NodeKey_Module key)
    
    717
    +    mkFixedEdge (Right (lvl, uid)) = mkModuleEdge lvl (NodeKey_ExternalUnit uid)
    
    718
    +
    
    719
    +    ifaceDeps :: Dependencies -> [Either (ImportLevel, ModNodeKeyWithUid) (ImportLevel, UnitId)]
    
    720
    +    ifaceDeps deps =
    
    721
    +      [ Left (tcImportLevel lvl, ModNodeKeyWithUid dep uid)
    
    722
    +      | (lvl, uid, dep) <- Set.toList (dep_direct_mods deps)
    
    723
    +      ] ++
    
    724
    +      [ Right (tcImportLevel lvl, uid)
    
    725
    +      | (lvl, uid) <- Set.toList (dep_direct_pkgs deps)
    
    726
    +      ]
    
    727
    +
    
    728
    +-- | Expand a unit id under the context of a certain home unit
    
    729
    +expandUnitNode :: UnitId {-^ @node_uid@ -} -> UnitId {-^ Home unit from where @node_uid@ was introduced -}
    
    730
    +               -> DownsweepM (NodeRes (ModuleGraphNode, [DownsweepNode]))
    
    731
    +expandUnitNode node_uid home_context_uid = do
    
    732
    +    -- Set active unit so that looking loopUnit finds the correct
    
    733
    +    -- -package flags in the unit state.
    
    734
    +    hsc_env <- asks downsweep_hsc_env
    
    735
    +    let lcl_hsc_env = hscSetActiveUnitId home_context_uid hsc_env
    
    736
    +    case unitDepends <$> lookupUnitId (hsc_units lcl_hsc_env) node_uid of
    
    737
    +      Just us -> pure $ NSuccess ((UnitNode us node_uid), map (\u -> DSUnit{node_uid=u, home_context_uid{-inherit-}}) us)
    
    738
    +      Nothing -> pprPanic "loopUnit" (text "Malformed package database, missing " <+> ppr node_uid)
    
    739
    +
    
    740
    +expandInstantiatedUnit :: InstantiatedUnit -> UnitId {-^ Home unit -} -> DownsweepM (NodeRes (ModuleGraphNode, [DownsweepNode]))
    
    741
    +expandInstantiatedUnit iud home_uid = pure $ NSuccess
    
    742
    +  ( InstantiationNode home_uid iud
    
    743
    +  , [DSUnit{node_uid=instUnitInstanceOf iud, home_context_uid=home_uid}] )
    
    744
    +
    
    745
    +expandInteractiveImports :: Module -> [InteractiveImport] -> DownsweepM (NodeRes (ModuleGraphNode, [DownsweepNode]))
    
    746
    +expandInteractiveImports imod imps = do
    
    747
    +  hsc_env    <- asks downsweep_hsc_env
    
    748
    +  imps_cache <- asks downsweep_imports_cache
    
    749
    +
    
    750
    +  let
    
    751
    +    -- A simple edge to a module from the same home unit
    
    752
    +    mkEdge (IIModule n) = return $
    
    753
    +      let
    
    754
    +        mod_node_key = ModNodeKeyWithUid
    
    755
    +          { mnkModuleName = GWIB (moduleName n) NotBoot
    
    756
    +          , mnkUnitId =
    
    757
    +              -- 'toUnitId' is safe here, as we can't import modules that
    
    758
    +              -- don't have a 'UnitId'.
    
    759
    +              toUnitId (moduleUnit n)
    
    760
    +          }
    
    761
    +       in (Just $ ModuleNodeEdge NormalLevel (NodeKey_Module mod_node_key), [])
    
    762
    +
    
    763
    +    -- A complete import statement
    
    764
    +    mkEdge (IIDecl i) =
    
    765
    +      let lvl = convImportLevel (ideclLevelSpec i)
    
    766
    +          wanted_mod = unLoc (ideclName i)
    
    767
    +          is_boot = ideclSource i
    
    768
    +          mb_pkg = renameRawPkgQual (hsc_unit_env hsc_env) (unLoc $ ideclName i) (ideclPkgQual i)
    
    769
    +          unitId = homeUnitId $ hsc_home_unit hsc_env
    
    770
    +      in do
    
    771
    +        let home_unit = ue_unitHomeUnit unitId (hsc_unit_env hsc_env)
    
    772
    +        let k _ loc mod =
    
    773
    +              let key = moduleToMnk mod is_boot
    
    774
    +              in return $ FoundHome (ModuleNodeFixed key loc)
    
    775
    +
    
    776
    +        found <- liftIO $ summariseModuleDispatch k hsc_env imps_cache
    
    777
    +                            home_unit is_boot (noLoc wanted_mod) mb_pkg []
    
    778
    +        case found of
    
    779
    +          -- Case 1: Home modules have to already be in the cache.
    
    780
    +          FoundHome (ModuleNodeFixed mod _) -> do
    
    781
    +            let edge = ModuleNodeEdge lvl (NodeKey_Module mod)
    
    782
    +            -- Note: Does not perform any further downsweep as the module must already be in the cache.
    
    783
    +            return (Just edge, [])
    
    784
    +          -- Case 2: External units may not be in the cache, if we haven't already initialised the
    
    785
    +          -- module graph. We can construct the module graph for those here by calling loopUnit.
    
    786
    +          External uid -> do
    
    787
    +            let edge = ModuleNodeEdge lvl (NodeKey_ExternalUnit uid)
    
    788
    +            return (Just edge, [DSUnit{node_uid=uid, home_context_uid=homeUnitId home_unit}])
    
    789
    +          -- And if it's not found.. just carry on and hope.
    
    790
    +          _ -> return (Nothing, [])
    
    791
    +
    
    792
    +  (module_edges, todo) <- unzip <$> mapM mkEdge imps
    
    793
    +  pure $ NSuccess
    
    794
    +    ( ModuleNode (catMaybes module_edges) node_type, concat todo )
    
    795
    +  where
    
    796
    +    -- No sensible value for ModLocation.. if you hit this panic then you probably
    
    797
    +    -- need to add proper support for modules without any source files to the driver.
    
    798
    +    ml = pprPanic "modLocation" (ppr imod <+> ppr imps)
    
    799
    +    key = moduleToMnk imod NotBoot
    
    800
    +    node_type = ModuleNodeFixed key ml
    
    801
    +
    
    802
    +--------------------------------------------------------------------------------
    
    803
    +-- * Constructing Module Summaries
    
    804
    +--------------------------------------------------------------------------------
    
    592 805
     
    
    593 806
     downsweepSummarise :: HomeUnit
    
    594 807
                        -> IsBootInterface
    
    ... ... @@ -597,90 +810,22 @@ downsweepSummarise :: HomeUnit
    597 810
                        -> Maybe (StringBuffer, UTCTime)
    
    598 811
                        -> DownsweepM SummariseResult
    
    599 812
     downsweepSummarise home_unit is_boot wanted_mod mb_pkg maybe_buf = do
    
    600
    -  DownsweepEnv hsc_env mode old_summaries excl_mods <- ask
    
    601
    -  case mode of
    
    602
    -    DownsweepUseCompile -> liftIO $ summariseModule hsc_env home_unit old_summaries is_boot wanted_mod mb_pkg maybe_buf excl_mods
    
    603
    -    DownsweepUseFixed -> liftIO $ summariseModuleInterface hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods
    
    604
    -
    
    605
    -
    
    606
    --- This loops over each import in each summary. It is mutually recursive with
    
    607
    --- loopSummaries if we discover a new module by doing this.
    
    608
    -loopImports
    
    609
    -  :: UnitId
    
    610
    -      -- ^ UnitId of home unit of summary whose imports are being processed
    
    611
    -  -> [(ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))]
    
    612
    -      -- ^ Work list: process these modules
    
    613
    -  -> M.Map NodeKey ModuleGraphNode
    
    614
    -  -> DownsweepCache
    
    615
    -      -- ^ Visited set; the range is a list because
    
    616
    -      -- the roots can have the same module names
    
    617
    -      -- if allow_dup_roots is True
    
    618
    -  -> DownsweepM ([ModuleNodeEdge],
    
    619
    -       M.Map NodeKey ModuleGraphNode, DownsweepCache)
    
    620
    -      -- ^ The result is the completed NodeMap
    
    621
    -loopImports _ [] done summarised = return ([], done, summarised)
    
    622
    -loopImports home_uid ((imp, mb_pkg, gwib) : ss) done summarised
    
    623
    -  | Just summs <- M.lookup cache_key summarised
    
    624
    -  = case summs of
    
    625
    -      [Right ms] -> do
    
    626
    -        let nk = mkModuleEdge imp (NodeKey_Module (mnKey ms))
    
    627
    -        (rest, summarised', done') <- loopImportsNext done summarised
    
    628
    -        return (nk: rest, summarised', done')
    
    629
    -      [Left _err] ->
    
    630
    -        loopImportsNext done summarised
    
    631
    -      _errs ->  do
    
    632
    -        loopImportsNext done summarised
    
    633
    -  | otherwise
    
    634
    -  = do
    
    635
    -       hsc_env <- asks downsweep_hsc_env
    
    636
    -       let home_unit = ue_unitHomeUnit home_uid (hsc_unit_env hsc_env)
    
    637
    -       mb_s <- downsweepSummarise home_unit
    
    638
    -                               is_boot wanted_mod mb_pkg
    
    639
    -                               Nothing
    
    640
    -       case mb_s of
    
    641
    -           NotThere -> loopImportsNext done summarised
    
    642
    -           External uid -> do
    
    643
    -            -- Pass an updated hsc_env to loopUnit, as each unit might
    
    644
    -            -- have a different visible package database.
    
    645
    -            let hsc_env' = hscSetActiveHomeUnit home_unit hsc_env
    
    646
    -            let done' = loopUnit hsc_env' done [uid]
    
    647
    -            (other_deps, done'', summarised') <- loopImportsNext done' summarised
    
    648
    -            return (mkModuleEdge imp (NodeKey_ExternalUnit uid) : other_deps, done'', summarised')
    
    649
    -           FoundInstantiation iud -> do
    
    650
    -            (other_deps, done', summarised') <- loopImportsNext done summarised
    
    651
    -            return (mkModuleEdge imp (NodeKey_Unit iud) : other_deps, done', summarised')
    
    652
    -           FoundHomeWithError (_uid, e) ->  loopImportsNext done (Map.insert cache_key [(Left e)] summarised)
    
    653
    -           FoundHome s -> do
    
    654
    -             (done', summarised') <-
    
    655
    -               loopModuleNodeInfo s (done, Map.insert cache_key [Right s] summarised)
    
    656
    -             (other_deps, final_done, final_summarised) <- loopImportsNext done' summarised'
    
    657
    -
    
    658
    -             -- MP: This assumes that we can only instantiate non home units, which is probably fair enough for now.
    
    659
    -             return (mkModuleEdge imp (NodeKey_Module (mnKey s)) : other_deps, final_done, final_summarised)
    
    660
    -  where
    
    661
    -    loopImportsNext = loopImports home_uid ss
    
    662
    -    cache_key = (home_uid, mb_pkg, unLoc <$> gwib)
    
    663
    -    GWIB { gwib_mod = L loc mod, gwib_isBoot = is_boot } = gwib
    
    664
    -    wanted_mod = L loc mod
    
    665
    -
    
    666
    -loopUnit :: HscEnv -> Map.Map NodeKey ModuleGraphNode -> [UnitId] -> Map.Map NodeKey ModuleGraphNode
    
    667
    -loopUnit _ cache [] = cache
    
    668
    -loopUnit lcl_hsc_env cache (u:uxs) = do
    
    669
    -   let nk = (NodeKey_ExternalUnit u)
    
    670
    -   case Map.lookup nk cache of
    
    671
    -     Just {} -> loopUnit lcl_hsc_env cache uxs
    
    672
    -     Nothing -> case unitDepends <$> lookupUnitId (hsc_units lcl_hsc_env) u of
    
    673
    -                 Just us -> loopUnit lcl_hsc_env (loopUnit lcl_hsc_env (Map.insert nk (UnitNode us u) cache) us) uxs
    
    674
    -                 Nothing -> pprPanic "loopUnit" (text "Malformed package database, missing " <+> ppr u)
    
    675
    -
    
    676
    -multiRootsErr :: SourceErrorContext -> [ModuleNodeInfo] -> IO ()
    
    677
    -multiRootsErr _ [] = panic "multiRootsErr"
    
    678
    -multiRootsErr sec summs@(summ1:_)
    
    813
    +  DownsweepEnv hsc_env mode summaries_cache_ref imports_cache_ref excl_mods <- ask
    
    814
    +  liftIO $ case mode of
    
    815
    +    DownsweepUseCompile ->
    
    816
    +      summariseModule hsc_env home_unit summaries_cache_ref imports_cache_ref
    
    817
    +                      is_boot wanted_mod mb_pkg maybe_buf excl_mods
    
    818
    +    DownsweepUseFixed ->
    
    819
    +      summariseModuleInterface hsc_env home_unit imports_cache_ref is_boot
    
    820
    +                      wanted_mod mb_pkg excl_mods
    
    821
    +
    
    822
    +multiRootsErr :: SourceErrorContext -> NE.NonEmpty ModuleNodeInfo -> IO ()
    
    823
    +multiRootsErr sec (summ1 NE.:| summs)
    
    679 824
       = throwOneError sec $ fmap GhcDriverMessage $
    
    680 825
         mkPlainErrorMsgEnvelope noSrcSpan $ DriverDuplicatedModuleDeclaration mod files
    
    681 826
       where
    
    682 827
         mod = moduleNodeInfoModule summ1
    
    683
    -    files = mapMaybe (ml_hs_file . moduleNodeInfoLocation) summs
    
    828
    +    files = mapMaybe (ml_hs_file . moduleNodeInfoLocation) (summ1:summs)
    
    684 829
     
    
    685 830
     moduleNotFoundErr :: UnitId -> ModuleName -> DriverMessages
    
    686 831
     moduleNotFoundErr uid mod = singleMessage $ mkPlainErrorMsgEnvelope noSrcSpan (DriverModuleNotFound uid mod)
    
    ... ... @@ -703,55 +848,27 @@ instantiationNodes uid unit_state = map (uid,) iuids_to_check
    703 848
             , recur <- (indef :) $ goUnitId $ moduleUnit $ snd inst
    
    704 849
             ]
    
    705 850
     
    
    706
    --- The linking plan for each module. If we need to do linking for a home unit
    
    707
    --- then this function returns a graph node which depends on all the modules in the home unit.
    
    708
    -
    
    709
    --- At the moment nothing can depend on these LinkNodes.
    
    710
    -linkNodes :: [ModuleGraphNode] -> UnitId -> HomeUnitEnv -> Maybe (Either (Messages DriverMessage) ModuleGraphNode)
    
    711
    -linkNodes summaries uid hue =
    
    712
    -  let dflags = homeUnitEnv_dflags hue
    
    713
    -      ofile = outputFile_ dflags
    
    714
    -
    
    715
    -      unit_nodes :: [NodeKey]
    
    716
    -      unit_nodes = map mkNodeKey (filter ((== uid) . mgNodeUnitId) summaries)
    
    717
    -  -- Issue a warning for the confusing case where the user
    
    718
    -  -- said '-o foo' but we're not going to do any linking.
    
    719
    -  -- We attempt linking if either (a) one of the modules is
    
    720
    -  -- called Main, or (b) the user said -no-hs-main, indicating
    
    721
    -  -- that main() is going to come from somewhere else.
    
    722
    -  --
    
    723
    -      no_hs_main = gopt Opt_NoHsMain dflags
    
    724
    -
    
    725
    -      main_sum = any (== NodeKey_Module (ModNodeKeyWithUid (GWIB (mainModuleNameIs dflags) NotBoot) uid)) unit_nodes
    
    726
    -
    
    727
    -      do_linking =  main_sum || no_hs_main || ghcLink dflags == LinkDynLib || ghcLink dflags == LinkStaticLib || ghcLink dflags == LinkBytecodeLib
    
    728
    -
    
    729
    -  in if | isExecutableLink (ghcLink dflags) && isJust ofile && not do_linking ->
    
    730
    -            Just (Left $ singleMessage $ mkPlainErrorMsgEnvelope noSrcSpan (DriverRedirectedNoMain $ mainModuleNameIs dflags))
    
    731
    -        -- This should be an error, not a warning (#10895).
    
    732
    -        | ghcLink dflags /= NoLink, do_linking -> Just (Right (LinkNode unit_nodes uid))
    
    733
    -        | otherwise  -> Nothing
    
    734
    -
    
    735 851
     getRootSummary ::
    
    736 852
       [ModuleName] ->
    
    737
    -  M.Map (UnitId, OsPath) ModSummary ->
    
    853
    +  ModSummaryCache ->
    
    854
    +  ImportsCache ->
    
    738 855
       HscEnv ->
    
    739 856
       Target ->
    
    740 857
       IO (Either DriverMessages ModSummary)
    
    741
    -getRootSummary excl_mods old_summary_map hsc_env target
    
    858
    +getRootSummary excl_mods summ_cache imports_cache hsc_env target
    
    742 859
       | TargetFile file mb_phase <- targetId
    
    743 860
       = do
    
    744 861
         let offset_file = augmentByWorkingDirectory dflags file
    
    745 862
         exists <- liftIO $ doesFileExist offset_file
    
    746 863
         if exists || isJust maybe_buf
    
    747
    -    then summariseFile hsc_env home_unit old_summary_map offset_file mb_phase
    
    864
    +    then summariseFile hsc_env home_unit summ_cache offset_file mb_phase
    
    748 865
              maybe_buf
    
    749 866
         else
    
    750 867
           return $ Left $ singleMessage $
    
    751 868
           mkPlainErrorMsgEnvelope noSrcSpan (DriverFileNotFound offset_file)
    
    752 869
       | TargetModule modl <- targetId
    
    753 870
       = do
    
    754
    -    maybe_summary <- summariseModule hsc_env home_unit old_summary_map NotBoot
    
    871
    +    maybe_summary <- summariseModule hsc_env home_unit summ_cache imports_cache NotBoot
    
    755 872
                          (L rootLoc modl) (ThisPkg (homeUnitId home_unit))
    
    756 873
                          maybe_buf excl_mods
    
    757 874
         pure case maybe_summary of
    
    ... ... @@ -815,6 +932,10 @@ rootSummariesParallel n_jobs hsc_env diag_wrapper msg get_summary = do
    815 932
                   throwIO e
    
    816 933
                 a -> pure a
    
    817 934
     
    
    935
    +--------------------------------------------------------------------------------
    
    936
    +-- * Check/validate properties and error out
    
    937
    +--------------------------------------------------------------------------------
    
    938
    +
    
    818 939
     -- | This function checks then important property that if both p and q are home units
    
    819 940
     -- then any dependency of p, which transitively depends on q is also a home unit.
    
    820 941
     --
    
    ... ... @@ -862,6 +983,10 @@ checkHomeUnitsClosed ue
    862 983
                           let todo'' = (depends Set.\\ done) `Set.union` todo'
    
    863 984
                           in DigraphNode uid uid (Set.toList depends) : go (Set.insert uid done) todo''
    
    864 985
     
    
    986
    +--------------------------------------------------------------------------------
    
    987
    +-- * Enable Code Gen for Template Haskell
    
    988
    +--------------------------------------------------------------------------------
    
    989
    +
    
    865 990
     -- | Update the every ModSummary that is depended on
    
    866 991
     -- by a module that needs template haskell. We enable codegen to
    
    867 992
     -- the specified target, disable optimization and change the .hi
    
    ... ... @@ -1179,15 +1304,9 @@ Potential TODOS:
    1179 1304
       generating temporary ones.
    
    1180 1305
     -}
    
    1181 1306
     
    
    1182
    --- | Populate the Downsweep cache with the root modules.
    
    1183
    -mkRootMap
    
    1184
    -  :: [ModuleNodeInfo]
    
    1185
    -  -> DownsweepCache
    
    1186
    -mkRootMap summaries = Map.fromListWith (flip (++))
    
    1187
    -  [ ((moduleNodeInfoUnitId s, NoPkgQual, moduleNodeInfoMnwib s), [Right s]) | s <- summaries ]
    
    1188
    -
    
    1189 1307
     -----------------------------------------------------------------------------
    
    1190
    --- Summarising modules
    
    1308
    +-- * Pre-processing and Summarising and modules
    
    1309
    +-----------------------------------------------------------------------------
    
    1191 1310
     
    
    1192 1311
     -- We have two types of summarisation:
    
    1193 1312
     --
    
    ... ... @@ -1202,33 +1321,39 @@ mkRootMap summaries = Map.fromListWith (flip (++))
    1202 1321
     summariseFile
    
    1203 1322
             :: HscEnv
    
    1204 1323
             -> HomeUnit
    
    1205
    -        -> M.Map (UnitId, OsPath) ModSummary    -- old summaries
    
    1324
    +        -> ModSummaryCache
    
    1206 1325
             -> FilePath                     -- source file name
    
    1207 1326
             -> Maybe Phase                  -- start phase
    
    1208 1327
             -> Maybe (StringBuffer,UTCTime)
    
    1209 1328
             -> IO (Either DriverMessages ModSummary)
    
    1210 1329
     
    
    1211
    -summariseFile hsc_env' home_unit old_summaries src_fn mb_phase maybe_buf
    
    1212
    -        -- we can use a cached summary if one is available and the
    
    1213
    -        -- source file hasn't changed,
    
    1214
    -   | Just old_summary <- M.lookup (homeUnitId home_unit, src_fn_os) old_summaries
    
    1215
    -   = do
    
    1216
    -        let location = ms_location $ old_summary
    
    1217
    -
    
    1218
    -        src_hash <- get_src_hash
    
    1219
    -                -- The file exists; we checked in getRootSummary above.
    
    1220
    -                -- If it gets removed subsequently, then this
    
    1221
    -                -- getFileHash may fail, but that's the right
    
    1222
    -                -- behaviour.
    
    1223
    -
    
    1224
    -                -- return the cached summary if the source didn't change
    
    1225
    -        checkSummaryHash
    
    1226
    -            hsc_env (new_summary src_fn)
    
    1227
    -            old_summary location src_hash
    
    1228
    -
    
    1229
    -   | otherwise
    
    1230
    -   = do src_hash <- get_src_hash
    
    1231
    -        new_summary src_fn src_hash
    
    1330
    +summariseFile hsc_env' home_unit summ_cache_ref src_fn mb_phase maybe_buf
    
    1331
    +   = do file_summ_cache <- readIORef summ_cache_ref
    
    1332
    +        case M.lookup (homeUnitId home_unit, src_fn_os) file_summ_cache of
    
    1333
    +          Just (Right (chd_summary, SummFresh)) ->
    
    1334
    +            -- Fresh: use it straight away
    
    1335
    +            pure (Right chd_summary)
    
    1336
    +          Just (Right (old_summary, SummOld)) -> do
    
    1337
    +            -- we can use a cached summary if one is available and the
    
    1338
    +            -- source file hasn't changed,
    
    1339
    +            let location = ms_location $ old_summary
    
    1340
    +
    
    1341
    +            src_hash <- get_src_hash
    
    1342
    +                    -- The file exists; we checked in getRootSummary above.
    
    1343
    +                    -- If it gets removed subsequently, then this
    
    1344
    +                    -- getFileHash may fail, but that's the right
    
    1345
    +                    -- behaviour.
    
    1346
    +
    
    1347
    +                    -- return the cached summary if the source didn't change
    
    1348
    +            res <- checkSummaryHash
    
    1349
    +                hsc_env (new_summary src_fn)
    
    1350
    +                old_summary location src_hash
    
    1351
    +            case res of
    
    1352
    +              Right ms -> modifySummCache summ_cache_ref (addModSummaryCache ms SummFresh)
    
    1353
    +              Left _   -> pure ()
    
    1354
    +            return res
    
    1355
    +          _ -> do src_hash <- get_src_hash
    
    1356
    +                  new_summary src_fn src_hash
    
    1232 1357
       where
    
    1233 1358
         -- change the main active unit so all operations happen relative to the given unit
    
    1234 1359
         hsc_env = hscSetActiveHomeUnit home_unit hsc_env'
    
    ... ... @@ -1239,7 +1364,8 @@ summariseFile hsc_env' home_unit old_summaries src_fn mb_phase maybe_buf
    1239 1364
                           Just (buf,_) -> return $ fingerprintStringBuffer buf
    
    1240 1365
                           Nothing -> liftIO $ getFileHash src_fn
    
    1241 1366
     
    
    1242
    -    new_summary src_fn src_hash = runExceptT $ do
    
    1367
    +    new_summary src_fn src_hash = do
    
    1368
    +      res <- runExceptT $ do
    
    1243 1369
             preimps@PreprocessedImports {..}
    
    1244 1370
                 <- getPreprocessedImports hsc_env src_fn mb_phase maybe_buf
    
    1245 1371
     
    
    ... ... @@ -1270,6 +1396,10 @@ summariseFile hsc_env' home_unit old_summaries src_fn mb_phase maybe_buf
    1270 1396
                 , nms_mod = mod
    
    1271 1397
                 , nms_preimps = preimps
    
    1272 1398
                 }
    
    1399
    +      modifySummCache summ_cache_ref $ case res of
    
    1400
    +        Left e   -> M.insert (homeUnitId home_unit, src_fn_os) (Left e)
    
    1401
    +        Right ms -> addModSummaryCache ms SummFresh
    
    1402
    +      return res
    
    1273 1403
     
    
    1274 1404
     checkSummaryHash
    
    1275 1405
         :: HscEnv
    
    ... ... @@ -1322,15 +1452,16 @@ data SummariseResult =
    1322 1452
     -- --make mode.
    
    1323 1453
     summariseModule :: HscEnv
    
    1324 1454
                     -> HomeUnit
    
    1325
    -                -> M.Map (UnitId, OsPath) ModSummary
    
    1455
    +                -> ModSummaryCache
    
    1456
    +                -> ImportsCache
    
    1326 1457
                     -> IsBootInterface
    
    1327 1458
                     -> Located ModuleName
    
    1328 1459
                     -> PkgQual
    
    1329 1460
                     -> Maybe (StringBuffer, UTCTime)
    
    1330 1461
                     -> [ModuleName]
    
    1331 1462
                     -> IO SummariseResult
    
    1332
    -summariseModule hsc_env home_unit old_summaries is_boot wanted_mod mb_pkg maybe_buf excl_mods =
    
    1333
    -  summariseModuleDispatch k hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1463
    +summariseModule hsc_env home_unit old_summaries imps_cache is_boot wanted_mod mb_pkg maybe_buf excl_mods =
    
    1464
    +  summariseModuleDispatch k hsc_env imps_cache home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1334 1465
       where
    
    1335 1466
         k = summariseModuleWithSource home_unit old_summaries is_boot maybe_buf
    
    1336 1467
     
    
    ... ... @@ -1339,13 +1470,14 @@ summariseModule hsc_env home_unit old_summaries is_boot wanted_mod mb_pkg maybe_
    1339 1470
     -- This version always returns a ModuleNodeFixed node.
    
    1340 1471
     summariseModuleInterface :: HscEnv
    
    1341 1472
                             -> HomeUnit
    
    1473
    +                        -> ImportsCache
    
    1342 1474
                             -> IsBootInterface
    
    1343 1475
                             -> Located ModuleName
    
    1344 1476
                             -> PkgQual
    
    1345 1477
                             -> [ModuleName]
    
    1346 1478
                             -> IO SummariseResult
    
    1347
    -summariseModuleInterface hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods =
    
    1348
    -  summariseModuleDispatch k hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1479
    +summariseModuleInterface hsc_env home_unit imps_cache is_boot wanted_mod mb_pkg excl_mods =
    
    1480
    +  summariseModuleDispatch k hsc_env imps_cache home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1349 1481
       where
    
    1350 1482
         k _hsc_env loc mod = do
    
    1351 1483
           -- The finder will return a path to the .hi-boot even if it doesn't actually
    
    ... ... @@ -1362,6 +1494,7 @@ summariseModuleInterface hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods =
    1362 1494
     summariseModuleDispatch
    
    1363 1495
               :: (HscEnv -> ModLocation -> Module -> IO SummariseResult) -- ^ Continuation about how to summarise a home module.
    
    1364 1496
               -> HscEnv
    
    1497
    +          -> ImportsCache
    
    1365 1498
               -> HomeUnit
    
    1366 1499
               -> IsBootInterface    -- True <=> a {-# SOURCE #-} import
    
    1367 1500
               -> Located ModuleName -- Imported module to be summarised
    
    ... ... @@ -1370,7 +1503,7 @@ summariseModuleDispatch
    1370 1503
               -> IO SummariseResult
    
    1371 1504
     
    
    1372 1505
     
    
    1373
    -summariseModuleDispatch k hsc_env' home_unit is_boot (L _ wanted_mod) mb_pkg excl_mods
    
    1506
    +summariseModuleDispatch k hsc_env' imps_cache_ref home_unit is_boot (L _ wanted_mod) mb_pkg excl_mods
    
    1374 1507
       | wanted_mod `elem` excl_mods
    
    1375 1508
       = return NotThere
    
    1376 1509
       | otherwise  = find_it
    
    ... ... @@ -1380,112 +1513,148 @@ summariseModuleDispatch k hsc_env' home_unit is_boot (L _ wanted_mod) mb_pkg exc
    1380 1513
         hsc_env   = hscSetActiveHomeUnit home_unit hsc_env'
    
    1381 1514
     
    
    1382 1515
         find_it :: IO SummariseResult
    
    1383
    -
    
    1384 1516
         find_it = do
    
    1385
    -        found <- findImportedModuleWithIsBoot hsc_env wanted_mod is_boot mb_pkg
    
    1386
    -        case found of
    
    1387
    -             Found location mod
    
    1388
    -                | moduleUnitId mod `Set.member` hsc_all_home_unit_ids hsc_env ->
    
    1389
    -                        -- Home package
    
    1390
    -                         k hsc_env location mod
    
    1391
    -                | VirtUnit iud <- moduleUnit mod
    
    1392
    -                , not (isHomeModule home_unit mod)
    
    1393
    -                  -> return $ FoundInstantiation iud
    
    1394
    -                | otherwise -> return $ External (moduleUnitId mod)
    
    1395
    -             _ -> return NotThere
    
    1396
    -                        -- Not found
    
    1397
    -                        -- (If it is TRULY not found at all, we'll
    
    1398
    -                        -- error when we actually try to compile)
    
    1399
    -
    
    1517
    +      imps_cache <- readIORef imps_cache_ref
    
    1518
    +      case M.lookup cache_key imps_cache of
    
    1519
    +        Just result -> return result
    
    1520
    +        Nothing -> do
    
    1521
    +          found <- findImportedModuleWithIsBoot hsc_env wanted_mod is_boot mb_pkg
    
    1522
    +          r <- case found of
    
    1523
    +               Found location mod
    
    1524
    +                  | moduleUnitId mod `Set.member` hsc_all_home_unit_ids hsc_env ->
    
    1525
    +                          -- Home package
    
    1526
    +                           k hsc_env location mod
    
    1527
    +                  | VirtUnit iud <- moduleUnit mod
    
    1528
    +                  , not (isHomeModule home_unit mod)
    
    1529
    +                    -> return $ FoundInstantiation iud
    
    1530
    +                  | otherwise -> return $ External (moduleUnitId mod)
    
    1531
    +               _ -> return NotThere
    
    1532
    +                          -- Not found
    
    1533
    +                          -- (If it is TRULY not found at all, we'll
    
    1534
    +                          -- error when we actually try to compile)
    
    1535
    +          modifyImpsCache imps_cache_ref (M.insert cache_key r)
    
    1536
    +          return r
    
    1537
    +
    
    1538
    +    cache_key = ( homeUnitId home_unit, mb_pkg
    
    1539
    +                , GWIB{ gwib_mod = wanted_mod, gwib_isBoot = is_boot })
    
    1400 1540
     
    
    1401 1541
     -- | The continuation to summarise a home module if we want to find the source file
    
    1402 1542
     -- for it and potentially compile it.
    
    1403 1543
     summariseModuleWithSource
    
    1404 1544
               :: HomeUnit
    
    1405
    -          -> M.Map (UnitId, OsPath) ModSummary
    
    1406
    -          -- ^ Map of old summaries
    
    1545
    +          -> ModSummaryCache
    
    1546
    +          -- ^ Cache of constructed summaries
    
    1407 1547
               -> IsBootInterface    -- True <=> a {-# SOURCE #-} import
    
    1408 1548
               -> Maybe (StringBuffer, UTCTime)
    
    1409 1549
               -> HscEnv
    
    1410 1550
               -> ModLocation
    
    1411 1551
               -> Module
    
    1412 1552
               -> IO SummariseResult
    
    1413
    -summariseModuleWithSource home_unit old_summary_map is_boot maybe_buf hsc_env location mod = do
    
    1414
    -        -- Adjust location to point to the hs-boot source file,
    
    1415
    -        -- hi file, object file, when is_boot says so
    
    1416
    -        let src_fn = expectJust (ml_hs_file location)
    
    1417
    -
    
    1418
    -                -- Check that it exists
    
    1419
    -                -- It might have been deleted since the Finder last found it
    
    1553
    +summariseModuleWithSource home_unit summ_cache_ref is_boot maybe_buf hsc_env location mod = do
    
    1554
    +    -- Adjust location to point to the hs-boot source file,
    
    1555
    +    -- hi file, object file, when is_boot says so
    
    1556
    +    let src_fn = expectJust (ml_hs_file location)
    
    1557
    +    summ_cache <- readIORef summ_cache_ref
    
    1558
    +
    
    1559
    +    -- Reject the cache result if the module name doesn't match the inferred
    
    1560
    +    -- module name based on the file name.
    
    1561
    +    -- See (W1) in Note [Downsweep Control Flow and Caching]
    
    1562
    +    let cached = do
    
    1563
    +          p   <- ml_hs_file_ospath location
    
    1564
    +          res <- M.lookup (moduleUnitId mod, p) summ_cache
    
    1565
    +          case res of
    
    1566
    +            Right (ms, _) | msKey ms /= moduleToMnk mod is_boot ->
    
    1567
    +              -- Module name doesn't match the file path name.
    
    1568
    +              -- We fall through to @new_summary@, where this will be
    
    1569
    +              -- discovered and the correct error message will be thrown.
    
    1570
    +              Nothing
    
    1571
    +            _ -> Just res
    
    1572
    +
    
    1573
    +    case cached of
    
    1574
    +      Just (Right (chd_summary, SummFresh)) ->
    
    1575
    +        -- Fresh! just return it
    
    1576
    +        pure $ FoundHome (ModuleNodeCompile chd_summary)
    
    1577
    +
    
    1578
    +      Just (Left err) ->
    
    1579
    +        -- Failure, don't try to summarise it again
    
    1580
    +        pure $ FoundHomeWithError (moduleUnitId mod, err)
    
    1581
    +
    
    1582
    +      mb_old -> do
    
    1583
    +        -- Either Nothing or a potentially old summary, must check.
    
    1584
    +
    
    1585
    +        -- Check that it exists
    
    1586
    +        -- It might have been deleted since the Finder last found it
    
    1420 1587
             maybe_h <- fileHashIfExists src_fn
    
    1421 1588
             case maybe_h of
    
    1422 1589
               -- This situation can also happen if we have found the .hs file but the
    
    1423 1590
               -- .hs-boot file doesn't exist.
    
    1424 1591
               Nothing -> return NotThere
    
    1425 1592
               Just h  -> do
    
    1426
    -            fresult <- new_summary_cache_check location mod src_fn h
    
    1593
    +            fresult <- case mb_old of
    
    1594
    +              Just (Right (old_summary, SummOld)) ->
    
    1595
    +                -- check the hash on the source file, and return the cached
    
    1596
    +                -- summary if it hasn't changed. If the file has changed then
    
    1597
    +                -- need to resummarise.
    
    1598
    +                case maybe_buf of
    
    1599
    +                  Just (buf,_) ->
    
    1600
    +                      checkSummaryHash hsc_env (new_summary location mod src_fn) old_summary location (fingerprintStringBuffer buf)
    
    1601
    +                  Nothing    ->
    
    1602
    +                      checkSummaryHash hsc_env (new_summary location mod src_fn) old_summary location h
    
    1603
    +              Nothing ->
    
    1604
    +                new_summary location mod src_fn h
    
    1427 1605
                 return $ case fresult of
    
    1428 1606
                   Left err -> FoundHomeWithError (moduleUnitId mod, err)
    
    1429 1607
                   Right ms -> FoundHome (ModuleNodeCompile ms)
    
    1430
    -
    
    1431 1608
       where
    
    1432 1609
         dflags    = hsc_dflags hsc_env
    
    1433
    -    new_summary_cache_check loc mod src_fn h
    
    1434
    -      | Just old_summary <- Map.lookup ((toUnitId (moduleUnit mod), src_fn_os)) old_summary_map =
    
    1435
    -
    
    1436
    -         -- check the hash on the source file, and
    
    1437
    -         -- return the cached summary if it hasn't changed.  If the
    
    1438
    -         -- file has changed then need to resummarise.
    
    1439
    -        case maybe_buf of
    
    1440
    -           Just (buf,_) ->
    
    1441
    -               checkSummaryHash hsc_env (new_summary loc mod src_fn) old_summary loc (fingerprintStringBuffer buf)
    
    1442
    -           Nothing    ->
    
    1443
    -               checkSummaryHash hsc_env (new_summary loc mod src_fn) old_summary loc h
    
    1444
    -      | otherwise = new_summary loc mod src_fn h
    
    1445
    -      where
    
    1446
    -        src_fn_os = unsafeEncodeUtf src_fn
    
    1447
    -
    
    1448 1610
         new_summary :: ModLocation
    
    1449 1611
                       -> Module
    
    1450 1612
                       -> FilePath
    
    1451 1613
                       -> Fingerprint
    
    1452 1614
                       -> IO (Either DriverMessages ModSummary)
    
    1453 1615
         new_summary location mod src_fn src_hash
    
    1454
    -      = runExceptT $ do
    
    1455
    -        preimps@PreprocessedImports {..}
    
    1456
    -            -- Remember to set the active unit here, otherwise the wrong include paths are passed to CPP
    
    1457
    -            -- See multiHomeUnits_cpp2 test
    
    1458
    -            <- getPreprocessedImports (hscSetActiveUnitId (moduleUnitId mod) hsc_env) src_fn Nothing maybe_buf
    
    1459
    -
    
    1460
    -        -- NB: Despite the fact that is_boot is a top-level parameter, we
    
    1461
    -        -- don't actually know coming into this function what the HscSource
    
    1462
    -        -- of the module in question is.  This is because we may be processing
    
    1463
    -        -- this module because another module in the graph imported it: in this
    
    1464
    -        -- case, we know if it's a boot or not because of the {-# SOURCE #-}
    
    1465
    -        -- annotation, but we don't know if it's a signature or a regular
    
    1466
    -        -- module until we actually look it up on the filesystem.
    
    1467
    -        let hsc_src
    
    1468
    -              | is_boot == IsBoot           = HsBootFile
    
    1469
    -              | isHaskellSigFilename src_fn = HsigFile
    
    1470
    -              | otherwise                   = HsSrcFile
    
    1471
    -
    
    1472
    -        when (pi_mod_name /= moduleName mod) $
    
    1473
    -                throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1474
    -                       $ DriverFileModuleNameMismatch pi_mod_name (moduleName mod)
    
    1475
    -
    
    1476
    -        let instantiations = homeUnitInstantiations home_unit
    
    1477
    -        when (hsc_src == HsigFile && isNothing (lookup pi_mod_name instantiations)) $
    
    1478
    -            throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1479
    -                   $ DriverUnexpectedSignature pi_mod_name (checkBuildingCabalPackage dflags) instantiations
    
    1480
    -
    
    1481
    -        liftIO $ makeNewModSummary hsc_env $ MakeNewModSummary
    
    1482
    -            { nms_src_fn = src_fn
    
    1483
    -            , nms_src_hash = src_hash
    
    1484
    -            , nms_hsc_src = hsc_src
    
    1485
    -            , nms_location = location
    
    1486
    -            , nms_mod = mod
    
    1487
    -            , nms_preimps = preimps
    
    1488
    -            }
    
    1616
    +      = do
    
    1617
    +        res <- runExceptT $ do
    
    1618
    +          preimps@PreprocessedImports {..}
    
    1619
    +              -- Remember to set the active unit here, otherwise the wrong include paths are passed to CPP
    
    1620
    +              -- See multiHomeUnits_cpp2 test
    
    1621
    +              <- getPreprocessedImports (hscSetActiveUnitId (moduleUnitId mod) hsc_env) src_fn Nothing maybe_buf
    
    1622
    +
    
    1623
    +          -- NB: Despite the fact that is_boot is a top-level parameter, we
    
    1624
    +          -- don't actually know coming into this function what the HscSource
    
    1625
    +          -- of the module in question is.  This is because we may be processing
    
    1626
    +          -- this module because another module in the graph imported it: in this
    
    1627
    +          -- case, we know if it's a boot or not because of the {-# SOURCE #-}
    
    1628
    +          -- annotation, but we don't know if it's a signature or a regular
    
    1629
    +          -- module until we actually look it up on the filesystem.
    
    1630
    +          let hsc_src
    
    1631
    +                | is_boot == IsBoot           = HsBootFile
    
    1632
    +                | isHaskellSigFilename src_fn = HsigFile
    
    1633
    +                | otherwise                   = HsSrcFile
    
    1634
    +
    
    1635
    +          when (pi_mod_name /= moduleName mod) $
    
    1636
    +                  throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1637
    +                         $ DriverFileModuleNameMismatch pi_mod_name (moduleName mod)
    
    1638
    +
    
    1639
    +          let instantiations = homeUnitInstantiations home_unit
    
    1640
    +          when (hsc_src == HsigFile && isNothing (lookup pi_mod_name instantiations)) $
    
    1641
    +              throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1642
    +                     $ DriverUnexpectedSignature pi_mod_name (checkBuildingCabalPackage dflags) instantiations
    
    1643
    +
    
    1644
    +          liftIO $ makeNewModSummary hsc_env $ MakeNewModSummary
    
    1645
    +              { nms_src_fn = src_fn
    
    1646
    +              , nms_src_hash = src_hash
    
    1647
    +              , nms_hsc_src = hsc_src
    
    1648
    +              , nms_location = location
    
    1649
    +              , nms_mod = mod
    
    1650
    +              , nms_preimps = preimps
    
    1651
    +              }
    
    1652
    +        modifySummCache summ_cache_ref $ case res of
    
    1653
    +          Left e -> case ml_hs_file_ospath location of
    
    1654
    +            Just p  -> M.insert (moduleUnitId mod, p) (Left e)
    
    1655
    +            Nothing -> id
    
    1656
    +          Right ms -> addModSummaryCache ms SummFresh
    
    1657
    +        return res
    
    1489 1658
     
    
    1490 1659
     -- | Convenience named arguments for 'makeNewModSummary' only used to make
    
    1491 1660
     -- code more readable, not exported.
    
    ... ... @@ -1508,7 +1677,6 @@ makeNewModSummary hsc_env MakeNewModSummary{..} = do
    1508 1677
       hie_timestamp <- modificationTimeIfExists (ml_hie_file_ospath nms_location)
    
    1509 1678
       bytecode_timestamp <- modificationTimeIfExists (ml_bytecode_file_ospath nms_location)
    
    1510 1679
       extra_sig_imports <- findExtraSigImports hsc_env nms_hsc_src pi_mod_name
    
    1511
    -  (implicit_sigs, _inst_deps) <- implicitRequirementsShallow (hscSetActiveUnitId (moduleUnitId nms_mod) hsc_env) pi_theimps
    
    1512 1680
     
    
    1513 1681
       return $
    
    1514 1682
             ModSummary
    
    ... ... @@ -1522,7 +1690,6 @@ makeNewModSummary hsc_env MakeNewModSummary{..} = do
    1522 1690
             , ms_srcimps = pi_srcimps
    
    1523 1691
             , ms_textual_imps =
    
    1524 1692
                 ((,,) NormalLevel NoPkgQual . noLoc <$> extra_sig_imports) ++
    
    1525
    -            ((,,) NormalLevel NoPkgQual . noLoc <$> implicit_sigs) ++
    
    1526 1693
                 pi_theimps
    
    1527 1694
             , ms_hs_hash = nms_src_hash
    
    1528 1695
             , ms_iface_date = hi_timestamp
    
    ... ... @@ -1568,3 +1735,160 @@ getPreprocessedImports hsc_env src_fn mb_phase maybe_buf = do
    1568 1735
       let pi_srcimps = pi_srcimps'
    
    1569 1736
       let pi_theimps = rn_imps pi_theimps'
    
    1570 1737
       return PreprocessedImports {..}
    
    1738
    +
    
    1739
    +--------------------------------------------------------------------------------
    
    1740
    +-- * Generic traversal of iteratively-built graph: dfsBuild
    
    1741
    +--------------------------------------------------------------------------------
    
    1742
    +
    
    1743
    +-- | The result of expanding a node in 'dfsBuild'.
    
    1744
    +data NodeRes v
    
    1745
    +  -- | Computed the node payload successfully
    
    1746
    +  = NSuccess v
    
    1747
    +  -- | Skip a node! This means this node doesn't produce a payload and we can
    
    1748
    +  -- just ignore it if we ever come across it.
    
    1749
    +  --
    
    1750
    +  -- In practice, this might happen because of an error or maybe from an
    
    1751
    +  -- attempt to expand e.g. an hs-boot node just to see if it sticks, but we
    
    1752
    +  -- don't distinguish these uses. Skip just means ignore this node and don't
    
    1753
    +  -- abort.
    
    1754
    +  | NSkip
    
    1755
    +
    
    1756
    +-- | In a depth-first order, and starting from the given roots, traverse a
    
    1757
    +-- graph by iteratively expanding a node into a payload and a list of children
    
    1758
    +-- nodes to visit next.
    
    1759
    +--
    
    1760
    +-- A node is NEVER visited/expanded more than once, as long as the node key
    
    1761
    +-- @k@, computed from the node @n@, uniquely identifies that node.
    
    1762
    +--
    
    1763
    +-- The first argument @base_map@ is the starting set of already visited nodes
    
    1764
    +-- (these nodes won't be expanded again!).
    
    1765
    +--
    
    1766
    +-- The result is a mapping from the key of every node transitively reachable
    
    1767
    +-- from the root nodes (inclusively) to the payload returned by expanding that
    
    1768
    +-- node. The result includes the previously visited nodes given in @base_map@,
    
    1769
    +-- s.t. @dfsBuild base_map [] _ _ == base_map@.
    
    1770
    +--
    
    1771
    +-- The @expand@ function returns an 'NResult'. See the 'NResult' documentation
    
    1772
    +-- for more information about each result type.
    
    1773
    +--
    
    1774
    +-- Error handling and exiting early can be achieved by selecting a @Monad m@
    
    1775
    +-- accordingly, such as @Control.Monad.Except.Except@
    
    1776
    +--
    
    1777
    +-- Example usage: @n@ is instanced to @DownsweepNode@, @k@ is @NodeKey@, and @v@ is @ModuleNodeEdge@.
    
    1778
    +--
    
    1779
    +-- See also Note [Downsweep Control Flow and Caching]
    
    1780
    +dfsBuild :: (Ord k, Monad m)
    
    1781
    +         => Maybe (Map.Map k (NodeRes v))
    
    1782
    +         -- ^ Base map, existing results. We won't re-expand any of the nodes
    
    1783
    +         -- already present in this map.
    
    1784
    +         -> [n]
    
    1785
    +         -- ^ The root nodes from where to start traversal
    
    1786
    +         -> (n -> k)
    
    1787
    +         -- ^ Compute the key which uniquely identifies this node
    
    1788
    +         -> (n -> m (NodeRes (v,[n])))
    
    1789
    +         -- ^ Expand this node into its payload result and into the list of
    
    1790
    +         -- children nodes to visit next.
    
    1791
    +         -> m (Map.Map k (NodeRes v))
    
    1792
    +         -- ^ The result accumulates the payload of expanding the root nodes
    
    1793
    +         -- and all nodes transitively reachable from those roots.
    
    1794
    +dfsBuild base_map roots key expand = go roots (fromMaybe Map.empty base_map)
    
    1795
    +  where
    
    1796
    +    go []     visited = pure visited
    
    1797
    +    go (s:ss) visited
    
    1798
    +      | k `Map.member` visited
    
    1799
    +      = go ss visited
    
    1800
    +      | otherwise
    
    1801
    +      = do r <- expand s
    
    1802
    +           case r of
    
    1803
    +             NSkip ->
    
    1804
    +               go ss
    
    1805
    +                  (Map.insert k NSkip        visited) -- Skip!
    
    1806
    +             NSuccess (v,ns) ->
    
    1807
    +               go (ns ++ ss)
    
    1808
    +                  (Map.insert k (NSuccess v) visited)
    
    1809
    +      where
    
    1810
    +        k = key s
    
    1811
    +
    
    1812
    +{-
    
    1813
    +Note [Downsweep Control Flow and Caching]
    
    1814
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    1815
    +The control flow of downsweep is extracted into a single function `dfsBuild`,
    
    1816
    +which takes care of iteratively expanding and traversing all nodes of the
    
    1817
    +in-construction module graph necessary to build a full `ModuleGraph` at the
    
    1818
    +end.
    
    1819
    +
    
    1820
    +There are three levels of caching going on, all of which are necessary to make
    
    1821
    +sure we don't do repeated work (notably, we NEVER summarise the same module
    
    1822
    +twice).
    
    1823
    +
    
    1824
    +1. `dfsBuild` accumulates the final module graph and never revisits the
    
    1825
    +   same node of the module graph. Cache is keyed by the final
    
    1826
    +   `ModuleGraph`s `NodeKey`s.
    
    1827
    +
    
    1828
    +    For example, suppose
    
    1829
    +
    
    1830
    +       A imports B and C
    
    1831
    +       B imports D
    
    1832
    +       C imports D
    
    1833
    +
    
    1834
    +    Then, starting from A we will expand A and push B and C to the worklist;
    
    1835
    +    then, going back to B, we expand B which pushes D to the worklist. After
    
    1836
    +    processing D, we go to C, which imports D, but we have already visited that
    
    1837
    +    module so we can just use the already-constructed `ModuleGraphNode` for D.
    
    1838
    +
    
    1839
    +2. For Module A in home-unit u1, each import in the list of imports
    
    1840
    +   needs to be *found* (call to `findImportedModuleWithIsBoot`): at this
    
    1841
    +   point, we only have the `ModuleName` of the import, not the `Module`.
    
    1842
    +   This *finding* is somewhat expensive, so we cache it as well
    
    1843
    +   (`ImportsCache`). The cache key is the home-unit to which the module
    
    1844
    +   belongs~[1], the import package qualifier, and the ModuleName.
    
    1845
    +
    
    1846
    +   Same example, suppose
    
    1847
    +
    
    1848
    +      A imports B and C
    
    1849
    +      B imports D
    
    1850
    +      C imports D
    
    1851
    +
    
    1852
    +   When expanding B, we will findImportedModule "import D".
    
    1853
    +   When expanding C, we would findImportedModule "import D", but we can just
    
    1854
    +   look it up in the cache
    
    1855
    +
    
    1856
    +   [1] Different home-units will have different package flags, which means
    
    1857
    +   potentially different `Module` resolution for the same `ModuleName`.
    
    1858
    +
    
    1859
    +3. The most expensive operation we want to avoid is summarising a
    
    1860
    +   `Module` into a `ModSummary`, which notably involves parsing the
    
    1861
    +   module header from scratch.
    
    1862
    +   The third cache, in essence, maps a `Module` to its `ModSummary`
    
    1863
    +   (named `ModSummaryCache`). This cache upholds the invariant: we NEVER
    
    1864
    +   summarise the same module twice. In practice, the cache key is the
    
    1865
    +   Module's UnitId and the Source path; the reason is we need to
    
    1866
    +   distinguish between `.hs` and `.hs-boot` files, as their summaries
    
    1867
    +   will differ.
    
    1868
    +
    
    1869
    +   Note that this covers more than just (1), because we summarise all imports
    
    1870
    +   of a single module when expanding it (see 'expandModuleSummary'), before
    
    1871
    +   returning from the expansion function.
    
    1872
    +
    
    1873
    +   Note that (2) can't guarantee this alone: Two ModuleName imports in
    
    1874
    +   separate units can (and likely do) map to the same `Module`.
    
    1875
    +
    
    1876
    +(W1)
    
    1877
    +   In `summariseModuleWithSource`, on a cache hit, we must check if the module
    
    1878
    +   name matches the file name, because the cache might have been populated by
    
    1879
    +   `summariseFile`:
    
    1880
    +
    
    1881
    +   - `summariseFile` is used for summarising file targets, where
    
    1882
    +     the file name needn't match the module name: e.g., the `Main` module is
    
    1883
    +     sometimes not defined in a file named `Main.hs`.
    
    1884
    +
    
    1885
    +   - `summariseModuleWithSource` is used for summarising module targets, like
    
    1886
    +     an `import Bar`, where `Bar.hs` must contain `module Bar where`
    
    1887
    +     specifically (since we will later look for .hi files based on the module
    
    1888
    +     name).
    
    1889
    +
    
    1890
    +   See tests T27461a and T27461b.
    
    1891
    +
    
    1892
    +See also Note [Downsweep: building and maintaining the module graph] and
    
    1893
    +Note [The ModuleGraph].
    
    1894
    +-}

  • compiler/GHC/Driver/Env.hs
    ... ... @@ -284,7 +284,7 @@ hugSomeThingsBelowUs :: (HomeModInfo -> [a]) -> Bool -> HscEnv -> UnitId -> Modu
    284 284
     -- These things are currently stored in the EPS for home packages. (See #25795 for
    
    285 285
     -- progress in removing these kind of checks; and making these functions of
    
    286 286
     -- `UnitEnv` rather than `HscEnv`)
    
    287
    --- See Note [Downsweep and the ModuleGraph]
    
    287
    +-- See Note [The ModuleGraph]
    
    288 288
     hugSomeThingsBelowUs _ _ hsc_env _ _ | isOneShot (ghcMode (hsc_dflags hsc_env)) = return []
    
    289 289
     hugSomeThingsBelowUs extract include_hi_boot hsc_env uid mn
    
    290 290
       = let hug = hsc_HUG hsc_env
    

  • compiler/GHC/Tc/Utils/Backpack.hs
    ... ... @@ -291,28 +291,28 @@ implicitRequirements hsc_env normal_imports
    291 291
       where
    
    292 292
         mhome_unit = hsc_home_unit_maybe hsc_env
    
    293 293
     
    
    294
    --- | Like @implicitRequirements'@, but returns either the module name, if it is
    
    295
    --- a free hole, or the instantiated unit the imported module is from, so that
    
    296
    --- that instantiated unit can be processed and via the batch mod graph (rather
    
    297
    --- than a transitive closure done here) all the free holes are still reachable.
    
    294
    +-- | Like @implicitRequirements'@, but returns the instantiated unit the
    
    295
    +-- imported module is from, so that that instantiated unit can be processed and
    
    296
    +-- via the batch mod graph (rather than a transitive closure done here) all the
    
    297
    +-- free holes are still reachable.
    
    298 298
     implicitRequirementsShallow
    
    299 299
       :: HscEnv
    
    300 300
       -> [(ImportLevel, PkgQual, Located ModuleName)]
    
    301
    -  -> IO ([ModuleName], [InstantiatedUnit])
    
    302
    -implicitRequirementsShallow hsc_env normal_imports = go ([], []) normal_imports
    
    301
    +  -> IO [InstantiatedUnit]
    
    302
    +implicitRequirementsShallow hsc_env normal_imports = go [] normal_imports
    
    303 303
      where
    
    304 304
       mhome_unit = hsc_home_unit_maybe hsc_env
    
    305 305
     
    
    306 306
       go acc [] = pure acc
    
    307
    -  go (accL, accR) ((_stage, mb_pkg, L _ imp):imports) = do
    
    307
    +  go accR ((_stage, mb_pkg, L _ imp):imports) = do
    
    308 308
         found <- findImportedModule hsc_env imp mb_pkg
    
    309 309
         let acc' = case found of
    
    310 310
               Found _ mod | notHomeModuleMaybe mhome_unit mod ->
    
    311 311
                   case moduleUnit mod of
    
    312
    -                  HoleUnit -> (moduleName mod : accL, accR)
    
    313
    -                  RealUnit _ -> (accL, accR)
    
    314
    -                  VirtUnit u -> (accL, u:accR)
    
    315
    -          _ -> (accL, accR)
    
    312
    +                  HoleUnit -> panic "implicitRequirementsShallow: HoleUnit is unreachable through findImportedModule!"
    
    313
    +                  RealUnit _ -> accR
    
    314
    +                  VirtUnit u -> u:accR
    
    315
    +          _ -> accR
    
    316 316
         go acc' imports
    
    317 317
     
    
    318 318
     -- | Given a 'Unit', make sure it is well typed.  This is because
    

  • compiler/GHC/Unit/Env.hs
    ... ... @@ -167,7 +167,7 @@ data UnitEnv = UnitEnv
    167 167
     
    
    168 168
         , ue_module_graph    :: ModuleGraph
    
    169 169
             -- ^ The module graph of the current session
    
    170
    -        -- See Note [Downsweep and the ModuleGraph] for when this is constructed.
    
    170
    +        -- See Note [The ModuleGraph] for when this is constructed.
    
    171 171
     
    
    172 172
         , ue_home_unit_graph :: !HomeUnitGraph
    
    173 173
             -- See Note [Multiple Home Units]
    

  • testsuite/tests/driver/T27461/Main1.hs
    1
    +module Main where
    
    2
    +
    
    3
    +import Bar () -- resolves to src/Bar.hs, which declares module Foo
    
    4
    +
    
    5
    +main :: IO ()
    
    6
    +main = return ()

  • testsuite/tests/driver/T27461/Main2.hs
    1
    +module Main where
    
    2
    +
    
    3
    +main :: IO ()
    
    4
    +main = return ()

  • testsuite/tests/driver/T27461/Makefile
    1
    +TOP=../../..
    
    2
    +include $(TOP)/mk/boilerplate.mk
    
    3
    +include $(TOP)/mk/test.mk
    
    4
    +
    
    5
    +# src/Bar.hs declares module Foo, which is fine for a file target, but Main's
    
    6
    +# `import Bar` resolves to that same file and must be rejected.
    
    7
    +T27461a :
    
    8
    +	cp Main1.hs src/Main.hs
    
    9
    +	! '$(TEST_HC)' $(TEST_HC_OPTS) --make -fno-code -v0 -isrc src/Main.hs src/Bar.hs

  • testsuite/tests/driver/T27461/T27461a.stderr
    1
    +src/Bar.hs:1:8: error: [GHC-28623]
    
    2
    +    File name does not match module name:
    
    3
    +    Saw     : ‘Foo’
    
    4
    +    Expected: ‘Bar’

  • testsuite/tests/driver/T27461/T27461b.script
    1
    +"-- Successfully load modules if file target is not imported"
    
    2
    +:! cp Main2.hs src/Main.hs
    
    3
    +:load src/Main.hs src/Bar.hs
    
    4
    +main
    
    5
    +:! cp Main1.hs src/Main.hs
    
    6
    +"-- Crash on reload as we import a file target that has the wrong module name"
    
    7
    +:reload

  • testsuite/tests/driver/T27461/T27461b.stderr
    1
    +src/Bar.hs:1:8: error: [GHC-28623]
    
    2
    +    File name does not match module name:
    
    3
    +    Saw     : ‘Foo’
    
    4
    +    Expected: ‘Bar’
    
    5
    +

  • testsuite/tests/driver/T27461/T27461b.stdout
    1
    +"-- Successfully load modules if file target is not imported"
    
    2
    +"-- Crash on reload as we import a file target that has the wrong module name"

  • testsuite/tests/driver/T27461/all.T
    1
    +test('T27461a', extra_files(['src/', 'Main1.hs']), makefile_test, [])
    
    2
    +test('T27461b', [extra_files(['src/', 'Main1.hs', 'Main2.hs']), extra_hc_opts('-isrc')],
    
    3
    +     ghci_script, ['T27461b.script'])

  • testsuite/tests/driver/T27461/src/Bar.hs
    1
    +module Foo where
    
    2
    +-- Named Bar.hs but declares module Foo: allowed for a file target.
    
    3
    +
    
    4
    +foo :: Int
    
    5
    +foo = 1

  • testsuite/tests/ghc-api/fixed-nodes/FixedNodes.hs
    ... ... @@ -24,6 +24,7 @@ import Control.Monad.Catch (handle, throwM)
    24 24
     import Control.Exception.Context
    
    25 25
     import GHC.Driver.MakeFile
    
    26 26
     import GHC.Utils.Outputable
    
    27
    +import Data.IORef (newIORef)
    
    27 28
     -- | Convert a ModuleNodeCompile to a ModuleNodeFixed
    
    28 29
     convertToFixed :: ModuleNodeInfo -> ModuleNodeInfo
    
    29 30
     convertToFixed (ModuleNodeCompile ms) =
    
    ... ... @@ -151,5 +152,6 @@ main = do
    151 152
             getModSummaryFromTarget :: FilePath -> Ghc ModSummary
    
    152 153
             getModSummaryFromTarget file = do
    
    153 154
               hsc_env <- getSession
    
    154
    -          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) mempty file Nothing Nothing
    
    155
    +          summ_cache <- liftIO $ newIORef mempty
    
    156
    +          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) summ_cache file Nothing Nothing
    
    155 157
               return ms

  • testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs
    ... ... @@ -16,6 +16,7 @@ import GHC.Types.SourceFile
    16 16
     import System.Environment
    
    17 17
     import Control.Monad (void, when)
    
    18 18
     import Data.Maybe (fromJust)
    
    19
    +import Data.IORef (newIORef)
    
    19 20
     import Control.Exception (ExceptionWithContext(..), SomeException)
    
    20 21
     import Control.Monad.Catch (handle, throwM)
    
    21 22
     import Control.Exception.Context
    
    ... ... @@ -67,7 +68,9 @@ main = do
    67 68
               keyC = msKey msC
    
    68 69
     
    
    69 70
           let mkGraph s = do
    
    70
    -            ([], nodes) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed s []
    
    71
    +            summ_cache <- newIORef mempty
    
    72
    +            imps_cache <- newIORef mempty
    
    73
    +            ([], nodes) <- downsweepFromRootNodes hsc_env summ_cache imps_cache Nothing [] True DownsweepUseFixed s []
    
    71 74
                 return $ mkModuleGraph nodes
    
    72 75
     
    
    73 76
           graph <- liftIO $ mkGraph [ModuleNodeCompile msC]
    
    ... ... @@ -98,5 +101,6 @@ main = do
    98 101
             getModSummaryFromTarget :: FilePath -> Ghc ModSummary
    
    99 102
             getModSummaryFromTarget file = do
    
    100 103
               hsc_env <- getSession
    
    101
    -          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) mempty file Nothing Nothing
    
    104
    +          summ_cache <- liftIO $ newIORef mempty
    
    105
    +          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) summ_cache file Nothing Nothing
    
    102 106
               return ms

  • testsuite/tests/ghc-api/fixed-nodes/ModuleGraphInvariants.hs
    ... ... @@ -23,6 +23,7 @@ import Control.Monad.Catch (handle, throwM)
    23 23
     import Control.Exception.Context
    
    24 24
     import GHC.Utils.Outputable
    
    25 25
     import Data.List
    
    26
    +import Data.IORef (newIORef)
    
    26 27
     
    
    27 28
     -- | Convert a ModuleNodeCompile to a ModuleNodeFixed
    
    28 29
     convertToFixed :: ModuleNodeInfo -> ModuleNodeInfo
    
    ... ... @@ -132,5 +133,6 @@ main = do
    132 133
             getModSummaryFromTarget :: FilePath -> Ghc ModSummary
    
    133 134
             getModSummaryFromTarget file = do
    
    134 135
               hsc_env <- getSession
    
    135
    -          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) mempty file Nothing Nothing
    
    136
    +          summ_cache <- liftIO $ newIORef mempty
    
    137
    +          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) summ_cache file Nothing Nothing
    
    136 138
               return ms

  • testsuite/tests/splice-imports/SI35.hs
    ... ... @@ -28,6 +28,7 @@ import GHC.Unit.Module.Stage
    28 28
     import GHC.Data.Graph.Directed.Reachability
    
    29 29
     import GHC.Utils.Trace
    
    30 30
     import GHC.Unit.Module.Graph
    
    31
    +import Data.IORef (newIORef)
    
    31 32
     
    
    32 33
     main :: IO ()
    
    33 34
     main = do
    
    ... ... @@ -75,5 +76,6 @@ main = do
    75 76
             getModSummaryFromTarget :: FilePath -> Ghc ModSummary
    
    76 77
             getModSummaryFromTarget file = do
    
    77 78
               hsc_env <- getSession
    
    78
    -          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) mempty file Nothing Nothing
    
    79
    +          summ_cache <- liftIO $ newIORef mempty
    
    80
    +          Right ms <- liftIO $ summariseFile hsc_env (DefiniteHomeUnit mainUnitId Nothing) summ_cache file Nothing Nothing
    
    79 81
               return ms
    \ No newline at end of file

  • utils/check-ppr/Main.hs
    ... ... @@ -18,6 +18,7 @@ import System.Environment( getArgs )
    18 18
     import System.Exit
    
    19 19
     import System.FilePath
    
    20 20
     import System.IO
    
    21
    +import Data.IORef
    
    21 22
     
    
    22 23
     usage :: String
    
    23 24
     usage = unlines
    
    ... ... @@ -85,7 +86,8 @@ parseOneFile libdir fileName = do
    85 86
              let dflags2 = dflags `gopt_set` Opt_KeepRawTokenStream
    
    86 87
              _ <- setSessionDynFlags dflags2
    
    87 88
              hsc_env <- getSession
    
    88
    -         mms <- liftIO $ summariseFile hsc_env (hsc_home_unit hsc_env) mempty fileName Nothing Nothing
    
    89
    +         cache <- liftIO $ newIORef mempty
    
    90
    +         mms <- liftIO $ summariseFile hsc_env (hsc_home_unit hsc_env) cache fileName Nothing Nothing
    
    89 91
              case mms of
    
    90 92
                Left _err -> error "parseOneFile"
    
    91 93
                Right ms -> parseModule ms