Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC

Commits:

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

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

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

  • hadrian/hie-bios.bat

  • 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