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

Commits:

2 changed files:

Changes:

  • compiler/GHC/Driver/Downsweep.hs
    ... ... @@ -5,6 +5,8 @@
    5 5
     {-# LANGUAGE RecordWildCards #-}
    
    6 6
     {-# LANGUAGE BlockArguments #-}
    
    7 7
     {-# LANGUAGE ViewPatterns #-}
    
    8
    +{-# LANGUAGE TypeFamilies #-}
    
    9
    +{-# LANGUAGE FunctionalDependencies #-}
    
    8 10
     module GHC.Driver.Downsweep
    
    9 11
       ( downsweep
    
    10 12
       , downsweepThunk
    
    ... ... @@ -91,7 +93,7 @@ import GHC.Unit.Module.Deps
    91 93
     import qualified GHC.Unit.Home.Graph as HUG
    
    92 94
     import GHC.Unit.Module.Stage
    
    93 95
     
    
    94
    -import Data.Either ( rights, partitionEithers, lefts )
    
    96
    +import Data.Either ( partitionEithers, lefts )
    
    95 97
     import qualified Data.Map as Map
    
    96 98
     import qualified Data.Set as Set
    
    97 99
     
    
    ... ... @@ -111,6 +113,8 @@ import Control.Monad.Trans.Reader
    111 113
     import qualified Data.Map.Strict as M
    
    112 114
     import Control.Monad.Trans.Class
    
    113 115
     import System.IO.Unsafe (unsafeInterleaveIO)
    
    116
    +import Data.IORef
    
    117
    +import qualified Data.List.NonEmpty as NE
    
    114 118
     
    
    115 119
     {-
    
    116 120
     Note [Downsweep and the ModuleGraph]
    
    ... ... @@ -142,14 +146,6 @@ The result is having a uniform graph available for the whole compilation pipelin
    142 146
     
    
    143 147
     -}
    
    144 148
     
    
    145
    --- This caches the answer to the question, if we are in this unit, what does
    
    146
    --- an import of this module mean.
    
    147
    -type DownsweepCache = M.Map (UnitId, PkgQual, ModuleNameWithIsBoot) [Either DriverMessages ModuleNodeInfo]
    
    148
    -
    
    149
    -moduleGraphNodeMap :: ModuleGraph -> M.Map NodeKey ModuleGraphNode
    
    150
    -moduleGraphNodeMap graph
    
    151
    -    = M.fromList [(mkNodeKey node, node) | node <- mgModSummaries' graph]
    
    152
    -
    
    153 149
     -----------------------------------------------------------------------------
    
    154 150
     --
    
    155 151
     -- | Downsweep (dependency analysis) for --make mode
    
    ... ... @@ -195,8 +191,11 @@ downsweep :: HscEnv
    195 191
                     -- (Modules, IsBoot) identifiers, unless the Bool is true in
    
    196 192
                     -- which case there can be repeats
    
    197 193
     downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allow_dup_roots = do
    
    198
    -  n_jobs <- mkWorkerLimit (hsc_dflags hsc_env)
    
    199
    -  (root_errs, root_summaries) <- rootSummariesParallel n_jobs hsc_env diag_wrapper msg summary
    
    194
    +  n_jobs     <- mkWorkerLimit (hsc_dflags hsc_env)
    
    195
    +  summ_cache <- newIORef (mkModSummaryCache (zip old_summaries (repeat SummOld)))
    
    196
    +  imps_cache <- newIORef Map.empty
    
    197
    +  (root_errs, root_summaries) <- rootSummariesParallel n_jobs hsc_env diag_wrapper msg
    
    198
    +                                   (getRootSummary excl_mods summ_cache imps_cache)
    
    200 199
       let closure_errs = checkHomeUnitsClosed unit_env
    
    201 200
           unit_env = hsc_unit_env hsc_env
    
    202 201
     
    
    ... ... @@ -204,9 +203,13 @@ downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allo
    204 203
     
    
    205 204
       case all_errs of
    
    206 205
         [] -> do
    
    207
    -       (downsweep_errs, downsweep_nodes) <- downsweepFromRootNodes hsc_env old_summary_map maybe_base_graph excl_mods allow_dup_roots DownsweepUseCompile (map ModuleNodeCompile root_summaries) []
    
    206
    +       (downsweep_errs, downsweep_nodes) <-
    
    207
    +          downsweepFromRootNodes hsc_env summ_cache imps_cache maybe_base_graph
    
    208
    +            excl_mods allow_dup_roots DownsweepUseCompile (map ModuleNodeCompile root_summaries) []
    
    208 209
     
    
    209
    -       let (other_errs, unit_nodes) = partitionEithers $ HUG.unitEnv_foldWithKey (\nodes uid hue -> nodes ++ unitModuleNodes downsweep_nodes uid hue) [] (hsc_HUG hsc_env)
    
    210
    +       let (other_errs, unit_nodes) = partitionEithers $
    
    211
    +              HUG.unitEnv_foldWithKey (\nodes uid hue -> nodes ++ unitModuleNodes downsweep_nodes uid hue) []
    
    212
    +                                      (hsc_HUG hsc_env)
    
    210 213
     
    
    211 214
            let all_nodes = downsweep_nodes ++ unit_nodes
    
    212 215
            let all_errs = downsweep_errs ++ other_errs
    
    ... ... @@ -222,17 +225,6 @@ downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allo
    222 225
            return (all_errs, th_configured_nodes)
    
    223 226
         _  -> return (all_errs, emptyMG)
    
    224 227
       where
    
    225
    -    summary = getRootSummary excl_mods old_summary_map
    
    226
    -
    
    227
    -    -- A cache from file paths to the already summarised modules. The same file
    
    228
    -    -- can be used in multiple units so the map is also keyed by which unit the
    
    229
    -    -- file was used in.
    
    230
    -    -- Reuse these if we can because the most expensive part of downsweep is
    
    231
    -    -- reading the headers.
    
    232
    -    old_summary_map :: M.Map (UnitId, OsPath) ModSummary
    
    233
    -    old_summary_map =
    
    234
    -      M.fromList [((ms_unitid ms, msHsFileOsPath ms), ms) | ms <- old_summaries]
    
    235
    -
    
    236 228
         -- Dependencies arising on a unit (backpack and module linking deps)
    
    237 229
         unitModuleNodes :: [ModuleGraphNode] -> UnitId -> HomeUnitEnv -> [Either (Messages DriverMessage) ModuleGraphNode]
    
    238 230
         unitModuleNodes summaries uid hue =
    
    ... ... @@ -245,7 +237,9 @@ downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allo
    245 237
     downsweepThunk :: HscEnv -> ModSummary -> IO ModuleGraph
    
    246 238
     downsweepThunk hsc_env mod_summary = unsafeInterleaveIO $ do
    
    247 239
       debugTraceMsg (hsc_logger hsc_env) 3 $ text "Computing Module Graph thunk..."
    
    248
    -  ~(errs, mg) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed [ModuleNodeCompile mod_summary] []
    
    240
    +  summs <- newIORef (mkModSummaryCache [(mod_summary,SummOld)])
    
    241
    +  imps  <- newIORef mempty
    
    242
    +  ~(errs, mg) <- downsweepFromRootNodes hsc_env summs imps Nothing [] True DownsweepUseFixed [ModuleNodeCompile mod_summary] []
    
    249 243
       let dflags = hsc_dflags hsc_env
    
    250 244
       liftIO $ printOrThrowDiagnostics (hsc_logger hsc_env)
    
    251 245
                                        (initPrintConfig dflags)
    
    ... ... @@ -269,83 +263,22 @@ downsweepInteractiveImports hsc_env ic = unsafeInterleaveIO $ do
    269 263
       debugTraceMsg (hsc_logger hsc_env) 3 $ (text "Computing Interactive Module Graph thunk...")
    
    270 264
       let imps = ic_imports (hsc_IC hsc_env)
    
    271 265
     
    
    272
    -  let interactive_mn = icInteractiveModule ic
    
    273
    -  -- No sensible value for ModLocation.. if you hit this panic then you probably
    
    274
    -  -- need to add proper support for modules without any source files to the driver.
    
    275
    -  let ml = pprPanic "modLocation" (ppr interactive_mn <+> ppr imps)
    
    276
    -  let key = moduleToMnk interactive_mn NotBoot
    
    277
    -  let node_type = ModuleNodeFixed key ml
    
    266
    +      interactive_mn = icInteractiveModule ic
    
    267
    +      key = dsNodeInfoKey (DSInteractive interactive_mn imps)
    
    278 268
     
    
    279 269
       -- The existing nodes in the module graph. This will be populated when GHCi runs
    
    280 270
       -- :load. Any home package modules need to already be in here.
    
    281 271
       let cached_nodes = Map.fromList [ (mkNodeKey n, n) | n <- mg_mss (hsc_mod_graph hsc_env) ]
    
    282 272
     
    
    283
    -  (module_edges, graph) <- loopFromInteractive hsc_env (map mkEdge imps) cached_nodes
    
    284
    -  let interactive_node = ModuleNode module_edges node_type
    
    285
    -
    
    286
    -  let all_nodes  = M.elems graph
    
    273
    +  summ_cache <- newIORef mempty
    
    274
    +  imps_cache <- newIORef mempty
    
    275
    +  let env = DownsweepEnv hsc_env DownsweepUseFixed{-or UseCompiled?-} summ_cache imps_cache []
    
    276
    +  graph <- runDownsweepM env do
    
    277
    +    loopFromInteractive cached_nodes interactive_mn imps
    
    278
    +  let interactive_node  = expectJust $ M.lookup key graph
    
    279
    +      all_nodes  = M.elems graph
    
    287 280
       return $ mkModuleGraph (interactive_node : all_nodes)
    
    288 281
     
    
    289
    -  where
    
    290
    - --
    
    291
    -    mkEdge :: InteractiveImport -> Either ModuleNodeEdge (UnitId, ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))
    
    292
    -    -- A simple edge to a module from the same home unit
    
    293
    -    mkEdge (IIModule n) =
    
    294
    -      let
    
    295
    -        mod_node_key = ModNodeKeyWithUid
    
    296
    -          { mnkModuleName = GWIB (moduleName n) NotBoot
    
    297
    -          , mnkUnitId =
    
    298
    -              -- 'toUnitId' is safe here, as we can't import modules that
    
    299
    -              -- don't have a 'UnitId'.
    
    300
    -              toUnitId (moduleUnit n)
    
    301
    -          }
    
    302
    -        mod_node_edge =
    
    303
    -          ModuleNodeEdge NormalLevel (NodeKey_Module mod_node_key)
    
    304
    -      in Left mod_node_edge
    
    305
    -    -- A complete import statement
    
    306
    -    mkEdge (IIDecl i) =
    
    307
    -      let lvl = convImportLevel (ideclLevelSpec i)
    
    308
    -          wanted_mod = unLoc (ideclName i)
    
    309
    -          is_boot = ideclSource i
    
    310
    -          mb_pkg = renameRawPkgQual (hsc_unit_env hsc_env) (unLoc $ ideclName i) (ideclPkgQual i)
    
    311
    -          unitId = homeUnitId $ hsc_home_unit hsc_env
    
    312
    -      in Right (unitId, lvl, mb_pkg, GWIB (noLoc wanted_mod) is_boot)
    
    313
    -
    
    314
    -loopFromInteractive :: HscEnv
    
    315
    -                    -> [Either ModuleNodeEdge (UnitId, ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))]
    
    316
    -                    -> M.Map NodeKey ModuleGraphNode
    
    317
    -                    -> IO ([ModuleNodeEdge],M.Map NodeKey ModuleGraphNode)
    
    318
    -loopFromInteractive _ [] cached_nodes = return ([], cached_nodes)
    
    319
    -loopFromInteractive hsc_env (edge:edges) cached_nodes =
    
    320
    -  case edge of
    
    321
    -    Left edge -> do
    
    322
    -        (edges, cached_nodes') <- loopFromInteractive hsc_env edges cached_nodes
    
    323
    -        return (edge : edges, cached_nodes')
    
    324
    -    Right (unitId, lvl, mb_pkg, GWIB wanted_mod is_boot) -> do
    
    325
    -      let home_unit = ue_unitHomeUnit unitId (hsc_unit_env hsc_env)
    
    326
    -      let k _ loc mod =
    
    327
    -            let key = moduleToMnk mod is_boot
    
    328
    -            in return $ FoundHome (ModuleNodeFixed key loc)
    
    329
    -      found <- liftIO $ summariseModuleDispatch k hsc_env home_unit is_boot wanted_mod mb_pkg []
    
    330
    -      case found of
    
    331
    -        -- Case 1: Home modules have to already be in the cache.
    
    332
    -        FoundHome (ModuleNodeFixed mod _) -> do
    
    333
    -          let edge = ModuleNodeEdge lvl (NodeKey_Module mod)
    
    334
    -          -- Note: Does not perform any further downsweep as the module must already be in the cache.
    
    335
    -          (edges, cached_nodes') <- loopFromInteractive hsc_env edges cached_nodes
    
    336
    -          return (edge : edges, cached_nodes')
    
    337
    -        -- Case 2: External units may not be in the cache, if we haven't already initialised the
    
    338
    -        -- module graph. We can construct the module graph for those here by calling loopUnit.
    
    339
    -        External uid -> do
    
    340
    -          let hsc_env' = hscSetActiveHomeUnit home_unit hsc_env
    
    341
    -              cached_nodes' = loopUnit hsc_env' cached_nodes [uid]
    
    342
    -              edge = ModuleNodeEdge lvl (NodeKey_ExternalUnit uid)
    
    343
    -          (edges, cached_nodes') <- loopFromInteractive hsc_env edges cached_nodes'
    
    344
    -          return (edge : edges, cached_nodes')
    
    345
    -        -- And if it's not found.. just carry on and hope.
    
    346
    -        _ -> loopFromInteractive hsc_env edges cached_nodes
    
    347
    -
    
    348
    -
    
    349 282
     -- | Create a module graph from a list of installed modules.
    
    350 283
     -- This is used by the loader when we need to load modules but there
    
    351 284
     -- isn't already an existing module graph. For example, when loading plugins
    
    ... ... @@ -373,7 +306,9 @@ downsweepInstalledModules hsc_env mods = do
    373 306
                 _ -> throwGhcException $ ProgramError $ showSDoc (hsc_dflags hsc_env) $ text "downsweepInstalledModules: Could not find installed module" <+> ppr i
    
    374 307
     
    
    375 308
         nodes <- mapM process installed_mods
    
    376
    -    (errs, mg) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed nodes external_uids
    
    309
    +    summs <- newIORef mempty
    
    310
    +    imps  <- newIORef mempty
    
    311
    +    (errs, mg) <- downsweepFromRootNodes hsc_env summs imps Nothing [] True DownsweepUseFixed nodes external_uids
    
    377 312
     
    
    378 313
         -- Similarly here, we should really not get any errors, but print them out if we do.
    
    379 314
         let dflags = hsc_dflags hsc_env
    
    ... ... @@ -397,7 +332,8 @@ data DownsweepMode = DownsweepUseCompile | DownsweepUseFixed
    397 332
     -- This function will start at the given roots, and traverse downwards to find
    
    398 333
     -- all the dependencies, all the way to the leaf units.
    
    399 334
     downsweepFromRootNodes :: HscEnv
    
    400
    -                  -> M.Map (UnitId, OsPath) ModSummary
    
    335
    +                  -> ModSummaryCache
    
    336
    +                  -> ImportsCache
    
    401 337
                       -> Maybe ModuleGraph
    
    402 338
                       -> [ModuleName]
    
    403 339
                       -> Bool
    
    ... ... @@ -405,44 +341,47 @@ downsweepFromRootNodes :: HscEnv
    405 341
                       -> [ModuleNodeInfo] -- ^ The starting ModuleNodeInfo
    
    406 342
                       -> [UnitId] -- ^ The starting units
    
    407 343
                       -> IO ([DriverMessages], [ModuleGraphNode])
    
    408
    -downsweepFromRootNodes hsc_env old_summaries maybe_base_graph excl_mods allow_dup_roots mode root_nodes root_uids
    
    409
    -   = do
    
    410
    -       let root_map = mkRootMap root_nodes
    
    411
    -       checkDuplicates root_map
    
    412
    -       let env = DownsweepEnv hsc_env mode old_summaries excl_mods
    
    413
    -       (deps', map0) <- runDownsweepM env  $ do
    
    414
    -                    let base_nodes = maybe M.empty moduleGraphNodeMap maybe_base_graph
    
    415
    -                    (module_deps, map0) <- loopModuleNodeInfos root_nodes (base_nodes, root_map)
    
    416
    -                    let all_deps = loopUnit hsc_env module_deps root_uids
    
    417
    -                    let all_instantiations =  getHomeUnitInstantiations hsc_env
    
    418
    -                    deps' <- loopInstantiations all_instantiations all_deps
    
    419
    -                    return (deps', map0)
    
    420
    -
    
    421
    -
    
    422
    -       let downsweep_errs = lefts $ concat $ M.elems map0
    
    423
    -           downsweep_nodes = M.elems deps'
    
    424
    -
    
    425
    -       return (downsweep_errs, downsweep_nodes)
    
    426
    -     where
    
    427
    -        getHomeUnitInstantiations :: HscEnv -> [(UnitId, InstantiatedUnit)]
    
    428
    -        getHomeUnitInstantiations hsc_env = HUG.unitEnv_foldWithKey (\nodes uid hue -> nodes ++  instantiationNodes uid (homeUnitEnv_units hue)) [] (hsc_HUG hsc_env)
    
    429
    -
    
    430
    -        -- In a root module, the filename is allowed to diverge from the module
    
    431
    -        -- name, so we have to check that there aren't multiple root files
    
    432
    -        -- defining the same module (otherwise the duplicates will be silently
    
    433
    -        -- ignored, leading to confusing behaviour).
    
    434
    -        checkDuplicates
    
    435
    -          :: DownsweepCache
    
    436
    -          -> IO ()
    
    437
    -        checkDuplicates root_map
    
    438
    -           | not allow_dup_roots
    
    439
    -           , dup_root:_ <- dup_roots = liftIO $ multiRootsErr sec dup_root
    
    440
    -           | otherwise = pure ()
    
    441
    -           where
    
    442
    -             sec = initSourceErrorContext (hsc_dflags hsc_env)
    
    443
    -             dup_roots :: [[ModuleNodeInfo]]        -- Each at least of length 2
    
    444
    -             dup_roots = filterOut isSingleton $ map rights (M.elems root_map)
    
    445
    -
    
    344
    +downsweepFromRootNodes hsc_env summ_cache imps_cache maybe_base_graph excl_mods allow_dup_roots mode root_nodes root_uids = do
    
    345
    +     when (not allow_dup_roots) $
    
    346
    +       case root_duplicates of
    
    347
    +         []           -> return ()
    
    348
    +         (dup_root:_) -> multiRootsErr sec dup_root
    
    349
    +     let env = DownsweepEnv hsc_env mode summ_cache imps_cache excl_mods
    
    350
    +     deps' <- runDownsweepM env  $ do
    
    351
    +        let base_nodes = maybe M.empty moduleGraphNodeMap maybe_base_graph
    
    352
    +        module_deps <- loopModuleNodeInfos base_nodes root_nodes
    
    353
    +        all_deps    <- loopUnits module_deps (hscActiveUnitId hsc_env) root_uids
    
    354
    +        deps'       <- loopInstantiations all_deps (getHomeUnitInstantiations hsc_env)
    
    355
    +        return deps'
    
    356
    +     f_cache <- readIORef summ_cache
    
    357
    +     let downsweep_errs = lefts (M.elems f_cache)
    
    358
    +         downsweep_nodes = M.elems deps'
    
    359
    +
    
    360
    +     return (downsweep_errs, downsweep_nodes)
    
    361
    +  where
    
    362
    +    getHomeUnitInstantiations :: HscEnv -> [(UnitId, InstantiatedUnit)]
    
    363
    +    getHomeUnitInstantiations hsc_env = HUG.unitEnv_foldWithKey
    
    364
    +      (\nodes uid hue -> nodes ++  instantiationNodes uid (homeUnitEnv_units hue)) [] (hsc_HUG hsc_env)
    
    365
    +
    
    366
    +    -- In a root module, the filename is allowed to diverge from the module
    
    367
    +    -- name, so we have to check that there aren't multiple root files
    
    368
    +    -- defining the same module (otherwise the duplicates will be silently
    
    369
    +    -- ignored, leading to confusing behaviour).
    
    370
    +    root_duplicates :: [NE.NonEmpty ModuleNodeInfo]
    
    371
    +    root_duplicates = mapMaybe takes2 (M.elems root_map)
    
    372
    +       where
    
    373
    +         takes2 (a:as@(_:_)) = Just (a NE.:| as) -- Each at least of length 2
    
    374
    +         takes2 _            = Nothing
    
    375
    +
    
    376
    +         root_map = Map.fromListWith (flip (++))
    
    377
    +           [ ((moduleNodeInfoUnitId s, moduleNodeInfoMnwib s), [s])
    
    378
    +           | s <- root_nodes ]
    
    379
    +
    
    380
    +    moduleGraphNodeMap :: ModuleGraph -> M.Map NodeKey ModuleGraphNode
    
    381
    +    moduleGraphNodeMap graph
    
    382
    +        = M.fromList [(mkNodeKey node, node) | node <- mgModSummaries' graph]
    
    383
    +
    
    384
    +    sec = initSourceErrorContext (hsc_dflags hsc_env)
    
    446 385
     
    
    447 386
     calcDeps :: ModSummary -> [(ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))]
    
    448 387
     calcDeps ms =
    
    ... ... @@ -457,104 +396,287 @@ type DownsweepM a = ReaderT DownsweepEnv IO a
    457 396
     data DownsweepEnv = DownsweepEnv {
    
    458 397
           downsweep_hsc_env :: HscEnv
    
    459 398
         , _downsweep_mode :: DownsweepMode
    
    460
    -    , _downsweep_old_summaries :: M.Map (UnitId, OsPath) ModSummary
    
    399
    +    , _downsweep_summaries_cache :: ModSummaryCache
    
    400
    +    , downsweep_imports_cache :: ImportsCache
    
    461 401
         , _downsweep_excl_mods :: [ModuleName]
    
    462 402
     }
    
    463 403
     
    
    404
    +type ModSummaryCache = IORef ModSummaryCacheMap
    
    405
    +type ImportsCache    = IORef ImportsCacheMap
    
    406
    +
    
    407
    +-- | A cache from file paths to the already summarised modules. The same file
    
    408
    +-- can be used in multiple units so the map is actually also keyed by which
    
    409
    +-- unit the file was used in.
    
    410
    +--
    
    411
    +-- We want to reuse ModSummaries as far as possible because the most expensive
    
    412
    +-- part of downsweep is reading and parsing the headers.
    
    413
    +--
    
    414
    +-- See Note [Downsweep Control Flow and Caching]
    
    415
    +type ModSummaryCacheMap
    
    416
    +      -- The cache can't be keyed by 'Module' because that isn't sufficient to
    
    417
    +      -- distinguish .hs from .hs-boot files. Use path+unit instead.
    
    418
    +      = ( M.Map (UnitId, OsPath) (Either DriverMessages (ModSummary, SummProvenance)) )
    
    419
    +
    
    420
    +data SummProvenance
    
    421
    +  -- | Constructed during this downsweep: trivially up to date
    
    422
    +  = SummFresh
    
    423
    +  -- | Carried over from a previous run: may be stale, must be hash-checked
    
    424
    +  -- (and considered by -fforce-recomp)
    
    425
    +  | SummOld
    
    426
    +
    
    427
    +mkModSummaryCache :: [(ModSummary, SummProvenance)] -> ModSummaryCacheMap
    
    428
    +mkModSummaryCache summs = foldl' (flip (uncurry addModSummaryCache)) M.empty summs
    
    429
    +
    
    430
    +addModSummaryCache :: ModSummary -> SummProvenance -> ModSummaryCacheMap -> ModSummaryCacheMap
    
    431
    +addModSummaryCache ms pr fe = upd_fe fe
    
    432
    +  where
    
    433
    +    upd_fe fe
    
    434
    +      | Just src_fn_os <- ml_hs_file_ospath (ms_location ms)
    
    435
    +      = M.insert (ms_unitid ms, src_fn_os) (Right (ms, pr)) fe
    
    436
    +      | otherwise = fe
    
    437
    +
    
    438
    +modifySummCache :: ModSummaryCache -> (ModSummaryCacheMap -> ModSummaryCacheMap) -> IO ()
    
    439
    +modifyImpsCache :: ImportsCache    -> (ImportsCacheMap    -> ImportsCacheMap)    -> IO ()
    
    440
    +modifySummCache r f = atomicModifyIORef' r (\c -> (f c, ()))
    
    441
    +modifyImpsCache r f = atomicModifyIORef' r (\c -> (f c, ()))
    
    442
    +
    
    443
    +-- | A cache from a module import (in given home unit context, with a package
    
    444
    +-- qualifier, and the imported module name (with or without SOURCE)) to the
    
    445
    +-- result of summarising that import (see 'summariseModuleDispatch').
    
    446
    +--
    
    447
    +-- See Note [Downsweep Control Flow and Caching]
    
    448
    +type ImportsCacheMap
    
    449
    +      = M.Map (UnitId, PkgQual, ModuleNameWithIsBoot) SummariseResult
    
    450
    +
    
    464 451
     runDownsweepM :: DownsweepEnv -> DownsweepM a -> IO a
    
    465 452
     runDownsweepM env act = runReaderT act env
    
    466 453
     
    
    454
    +loopDownsweepNodes  :: M.Map NodeKey ModuleGraphNode -> [DownsweepNode]              -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    455
    +loopModuleNodeInfos :: M.Map NodeKey ModuleGraphNode -> [ModuleNodeInfo]             -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    456
    +loopUnits           :: M.Map NodeKey ModuleGraphNode -> UnitId -> [UnitId] -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    457
    +loopInstantiations  :: M.Map NodeKey ModuleGraphNode -> [(UnitId, InstantiatedUnit)] -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    458
    +loopFromInteractive :: M.Map NodeKey ModuleGraphNode -> Module -> [InteractiveImport] -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    459
    +loopDownsweepNodes  base_map nodes = dfsBuild (Just base_map) nodes dsNodeInfoKey dsNodeExpand
    
    460
    +loopModuleNodeInfos base_map       = loopDownsweepNodes base_map . map DSMod
    
    461
    +loopUnits           base_map homud = loopDownsweepNodes base_map . map (DSUnit homud)
    
    462
    +loopInstantiations  base_map       = loopDownsweepNodes base_map . map (uncurry DSInst)
    
    463
    +loopFromInteractive base_map m     = loopDownsweepNodes base_map . (:[]) . DSInteractive m
    
    464
    +
    
    465
    +--------------------------------------------------------------------------------
    
    466
    +
    
    467
    +-- | A 'DownsweepNode' is the basic block of the downsweep algorithm which
    
    468
    +-- encompasses the types of nodes we can iteratively expand to construct the
    
    469
    +-- full module graph. See 'loopDownsweepNodes'.
    
    470
    +--
    
    471
    +-- See Note [Downsweep Control Flow and Caching]
    
    472
    +data DownsweepNode
    
    473
    +  -- | A module node to expand
    
    474
    +  = DSMod ModuleNodeInfo
    
    475
    +  -- | A unit node to expand
    
    476
    +  | DSUnit
    
    477
    +  { home_context_uid :: UnitId
    
    478
    +  -- ^ The home unit which introduced the dependency on this 'node_uid'. This
    
    479
    +  -- 'node_uid' can only be expanded in the context ('HscEnv') where
    
    480
    +  -- 'home_context_uid' is the active home unit, to make sure the package flags
    
    481
    +  -- are the ones attributed to the home package that introduced this node.
    
    482
    +  , node_uid         :: UnitId
    
    483
    +  -- ^ The unit node to expand
    
    484
    +  }
    
    485
    +  -- | FIXME: document the meaning of 'DSInst'
    
    486
    +  | DSInst
    
    487
    +  { home_context_uid :: UnitId
    
    488
    +  , instantiated_ud  :: InstantiatedUnit
    
    489
    +  }
    
    490
    +  -- | A group of interactive imports from this interactive Module
    
    491
    +  | DSInteractive Module [InteractiveImport]
    
    492
    +
    
    493
    +instance Outputable DownsweepNode where
    
    494
    +  ppr = \case
    
    495
    +    DSMod (ModuleNodeCompile ms) -> text "DSModC" <+> ppr (ms_mod_name ms)
    
    496
    +    DSMod (ModuleNodeFixed key _) -> text "DSModF" <+> ppr key
    
    497
    +    DSUnit{node_uid} -> text "DSUnit" <+> ppr node_uid
    
    498
    +    DSInst{instantiated_ud} -> text "DSInst" <+> ppr instantiated_ud
    
    499
    +    DSInteractive mod ii    -> text "DSInteractive" <+> ppr mod <+> ppr ii
    
    500
    +
    
    501
    +-- | They key by which to cache previously visited 'DownsweepNode's
    
    502
    +dsNodeInfoKey :: DownsweepNode -> NodeKey
    
    503
    +dsNodeInfoKey = \case
    
    504
    +  DSMod (ModuleNodeCompile ms)  -> NodeKey_Module (msKey ms)
    
    505
    +  DSMod (ModuleNodeFixed mod _) -> NodeKey_Module mod
    
    506
    +  DSUnit{node_uid}              -> NodeKey_ExternalUnit node_uid
    
    507
    +  DSInst{instantiated_ud}       -> NodeKey_Unit instantiated_ud
    
    508
    +  DSInteractive mod _imps       -> NodeKey_Module $ moduleToMnk mod NotBoot
    
    509
    +
    
    510
    +dsNodeExpand :: DownsweepNode -> DownsweepM (Maybe (ModuleGraphNode, [DownsweepNode]))
    
    511
    +dsNodeExpand = \case
    
    512
    +  DSMod (ModuleNodeCompile ms)         -> expandModuleSummary ms
    
    513
    +  DSMod (ModuleNodeFixed key loc)      -> expandFixedModuleNode key loc
    
    514
    +  DSUnit{ node_uid, home_context_uid } -> expandUnitNode node_uid home_context_uid
    
    515
    +  DSInst{ instantiated_ud
    
    516
    +        , home_context_uid }           -> expandInstantiatedUnit instantiated_ud home_context_uid
    
    517
    +  DSInteractive imod iis               -> expandInteractiveImports imod iis
    
    518
    +
    
    519
    +expandModuleSummary :: ModSummary -> DownsweepM (Maybe (ModuleGraphNode, [DownsweepNode]))
    
    520
    +expandModuleSummary ms = do -- Didn't work out what the imports mean yet, now do that.
    
    521
    +    hsc_env <- asks downsweep_hsc_env
    
    522
    +    let home_uid  = ms_unitid ms
    
    523
    +        home_unit = ue_unitHomeUnit home_uid (hsc_unit_env hsc_env)
    
    524
    +    (final_deps, todo) <- fmap unzip $ forM (calcDeps ms) $ \(imp,mb_pkg,gwib) -> do
    
    525
    +      let GWIB { gwib_mod = L loc mod, gwib_isBoot = is_boot } = gwib
    
    526
    +          wanted_mod = L loc mod
    
    527
    +      mb_s <- downsweepSummarise home_unit is_boot wanted_mod mb_pkg Nothing
    
    528
    +      case mb_s of
    
    529
    +        NotThere -> return
    
    530
    +          ( Nothing, [] )
    
    531
    +        External uid -> return
    
    532
    +          ( Just $ mkModuleEdge imp (NodeKey_ExternalUnit uid)
    
    533
    +          -- Specify home unit, as each unit might have a different visible package database.
    
    534
    +          , [DSUnit{node_uid = uid, home_context_uid = home_uid}] )
    
    535
    +        FoundInstantiation iud -> return
    
    536
    +          ( Just (mkModuleEdge imp (NodeKey_Unit iud)), [] )
    
    537
    +        FoundHomeWithError (_uid, _e) -> return
    
    538
    +          ( Nothing, [] )
    
    539
    +          -- the error @e@ is already stored in the summarisation cache,
    
    540
    +          -- (the IORef in DownsweepM) and will get reported at the end.
    
    541
    +        FoundHome s -> return
    
    542
    +          -- MP: This assumes that we can only instantiate non home units, which is probably fair enough for now.
    
    543
    +          ( Just $ mkModuleEdge imp (NodeKey_Module (mnKey s))
    
    544
    +          , [DSMod s] )
    
    545
    +
    
    546
    +    -- This has the effect of finding a .hs file if we are looking at the .hs-boot file.
    
    547
    +    boot_todo <-
    
    548
    +      if | HsBootFile <- ms_hsc_src ms
    
    549
    +         -> do
    
    550
    +            r <- downsweepSummarise home_unit NotBoot (noLoc $ ms_mod_name ms) NoPkgQual Nothing
    
    551
    +            case r of
    
    552
    +              FoundHome s -> pure [DSMod s]
    
    553
    +              _           -> pure []
    
    554
    +         | otherwise      -> pure []
    
    555
    +
    
    556
    +    return $ Just
    
    557
    +      ( ModuleNode (catMaybes final_deps) (ModuleNodeCompile ms)
    
    558
    +      , boot_todo ++ concat todo
    
    559
    +      )
    
    560
    +
    
    561
    +-- | Expand a 'ModuleNodeFixed' node
    
    562
    +-- NB: If you ever reach a Fixed node, everything under that also must be fixed.
    
    563
    +expandFixedModuleNode :: ModNodeKeyWithUid -> ModLocation -> DownsweepM (Maybe (ModuleGraphNode, [DownsweepNode]))
    
    564
    +expandFixedModuleNode key loc = do
    
    565
    +    hsc_env <- asks downsweep_hsc_env
    
    566
    +    -- MP: TODO, we should just read the dependency info from the interface rather than either
    
    567
    +    -- a. Loading the whole thing into the EPS (this might never nececssary and causes lots of things to be permanently loaded into memory)
    
    568
    +    -- b. Loading the whole interface into a buffer before discarding it. (wasted allocation and deserialisation)
    
    569
    +    read_result <- liftIO $
    
    570
    +      -- 1. Check if the interface is already loaded into the EPS by some other
    
    571
    +      -- part of the compiler.
    
    572
    +      lookupIfaceByModuleHsc hsc_env (mnkToModule key) >>= \case
    
    573
    +        Just iface -> return (M.Succeeded iface)
    
    574
    +        Nothing -> readIface (hsc_hooks hsc_env) (hsc_logger hsc_env) (hsc_dflags hsc_env) (hsc_NC hsc_env) (mnkToModule key) (ml_hi_file loc)
    
    575
    +    case read_result of
    
    576
    +      M.Succeeded iface -> do
    
    577
    +        -- Computer information about this node
    
    578
    +        let node_deps = ifaceDeps (mi_deps iface)
    
    579
    +            edges = map mkFixedEdge node_deps
    
    580
    +            node = ModuleNode edges (ModuleNodeFixed key loc)
    
    581
    +        deps' <- catMaybes <$> mapM (mk_dep hsc_env) (bimap snd snd <$> node_deps)
    
    582
    +        pure $ Just (node, deps')
    
    583
    +
    
    584
    +      -- Ignore any failure, we might try to read a .hi-boot file for
    
    585
    +      -- example, even if there is not one.
    
    586
    +      M.Failed {} ->
    
    587
    +        pure Nothing
    
    588
    +  where
    
    589
    +    mk_dep hsc_env (Left key) = do
    
    590
    +      -- Like expandImports, but we already know exactly which module we are looking for.
    
    591
    +      read_result <- liftIO $ findExactModule hsc_env (mnkToInstalledModule key) (mnkIsBoot key)
    
    592
    +      case read_result of
    
    593
    +        InstalledFound loc -> do
    
    594
    +          pure $ Just $ DSMod (ModuleNodeFixed key loc)
    
    595
    +        _otherwise ->
    
    596
    +          -- If the finder fails, just keep going, there will be another
    
    597
    +          -- error later.
    
    598
    +          pure Nothing
    
    599
    +    mk_dep _ (Right uid_dep) = do
    
    600
    +      -- Set active unit so that looking loopUnit finds the correct
    
    601
    +      -- -package flags in the unit state.
    
    602
    +      let home_uid = mnkUnitId key
    
    603
    +      pure (Just DSUnit{node_uid=uid_dep, home_context_uid=home_uid})
    
    604
    +
    
    605
    +-- | Expand a unit id under the context of a certain home unit
    
    606
    +expandUnitNode :: UnitId {-^ @node_uid@ -} -> UnitId {-^ Home unit from where @node_uid@ was introduced -}
    
    607
    +               -> DownsweepM (Maybe (ModuleGraphNode, [DownsweepNode]))
    
    608
    +expandUnitNode node_uid home_context_uid = do
    
    609
    +    -- Set active unit so that looking loopUnit finds the correct
    
    610
    +    -- -package flags in the unit state.
    
    611
    +    hsc_env <- asks downsweep_hsc_env
    
    612
    +    let lcl_hsc_env = hscSetActiveUnitId home_context_uid hsc_env
    
    613
    +    case unitDepends <$> lookupUnitId (hsc_units lcl_hsc_env) node_uid of
    
    614
    +      Just us -> pure $ Just ((UnitNode us node_uid), map (\u -> DSUnit{node_uid=u, home_context_uid{-inherit-}}) us)
    
    615
    +      Nothing -> pprPanic "loopUnit" (text "Malformed package database, missing " <+> ppr node_uid)
    
    616
    +
    
    617
    +expandInstantiatedUnit :: InstantiatedUnit -> UnitId {-^ Home unit -} -> DownsweepM (Maybe (ModuleGraphNode, [DownsweepNode]))
    
    618
    +expandInstantiatedUnit iud home_uid = pure $ Just
    
    619
    +  ( InstantiationNode home_uid iud
    
    620
    +  , [DSUnit{node_uid=instUnitInstanceOf iud, home_context_uid=home_uid}] )
    
    621
    +
    
    622
    +expandInteractiveImports :: Module -> [InteractiveImport] -> DownsweepM (Maybe (ModuleGraphNode, [DownsweepNode]))
    
    623
    +expandInteractiveImports imod imps = do
    
    624
    +  hsc_env    <- asks downsweep_hsc_env
    
    625
    +  imps_cache <- asks downsweep_imports_cache
    
    626
    +
    
    627
    +  let
    
    628
    +    -- A simple edge to a module from the same home unit
    
    629
    +    mkEdge (IIModule n) = return $
    
    630
    +      let
    
    631
    +        mod_node_key = ModNodeKeyWithUid
    
    632
    +          { mnkModuleName = GWIB (moduleName n) NotBoot
    
    633
    +          , mnkUnitId =
    
    634
    +              -- 'toUnitId' is safe here, as we can't import modules that
    
    635
    +              -- don't have a 'UnitId'.
    
    636
    +              toUnitId (moduleUnit n)
    
    637
    +          }
    
    638
    +       in (Just $ ModuleNodeEdge NormalLevel (NodeKey_Module mod_node_key), [])
    
    467 639
     
    
    468
    -loopInstantiations :: [(UnitId, InstantiatedUnit)]
    
    469
    -                   -> M.Map NodeKey ModuleGraphNode
    
    470
    -                   -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    471
    -loopInstantiations [] done = pure done
    
    472
    -loopInstantiations ((home_uid, iud) :xs) done = do
    
    473
    -  hsc_env <- asks downsweep_hsc_env
    
    474
    -  let home_unit = ue_unitHomeUnit home_uid (hsc_unit_env hsc_env)
    
    475
    -  let hsc_env' = hscSetActiveHomeUnit home_unit hsc_env
    
    476
    -      done' = loopUnit hsc_env' done [instUnitInstanceOf iud]
    
    477
    -      payload = InstantiationNode home_uid iud
    
    478
    -  loopInstantiations xs (M.insert (mkNodeKey payload) payload done')
    
    479
    -
    
    480
    -
    
    481
    --- This loops over all the mod summaries in the dependency graph, accumulates the actual dependencies for each module/unit
    
    482
    -loopSummaries :: [ModSummary]
    
    483
    -      -> (M.Map NodeKey ModuleGraphNode,
    
    484
    -            DownsweepCache)
    
    485
    -      -> DownsweepM ((M.Map NodeKey ModuleGraphNode), DownsweepCache)
    
    486
    -loopSummaries [] done = pure done
    
    487
    -loopSummaries (ms:next) (done, summarised)
    
    488
    -  | Just {} <- M.lookup k done
    
    489
    -  = loopSummaries next (done, summarised)
    
    490
    -  -- Didn't work out what the imports mean yet, now do that.
    
    491
    -  | otherwise = do
    
    492
    -     (final_deps, done', summarised') <- loopImports (ms_unitid ms) (calcDeps ms) done summarised
    
    493
    -     -- This has the effect of finding a .hs file if we are looking at the .hs-boot file.
    
    494
    -     (_, done'', summarised'') <- loopImports (ms_unitid ms) (maybeToList hs_file_for_boot) done' summarised'
    
    495
    -     loopSummaries next (M.insert k (ModuleNode final_deps (ModuleNodeCompile ms)) done'', summarised'')
    
    640
    +    -- A complete import statement
    
    641
    +    mkEdge (IIDecl i) =
    
    642
    +      let lvl = convImportLevel (ideclLevelSpec i)
    
    643
    +          wanted_mod = unLoc (ideclName i)
    
    644
    +          is_boot = ideclSource i
    
    645
    +          mb_pkg = renameRawPkgQual (hsc_unit_env hsc_env) (unLoc $ ideclName i) (ideclPkgQual i)
    
    646
    +          unitId = homeUnitId $ hsc_home_unit hsc_env
    
    647
    +      in do
    
    648
    +        let home_unit = ue_unitHomeUnit unitId (hsc_unit_env hsc_env)
    
    649
    +        let k _ loc mod =
    
    650
    +              let key = moduleToMnk mod is_boot
    
    651
    +              in return $ FoundHome (ModuleNodeFixed key loc)
    
    652
    +
    
    653
    +        found <- liftIO $ summariseModuleDispatch k hsc_env imps_cache
    
    654
    +                            home_unit is_boot (noLoc wanted_mod) mb_pkg []
    
    655
    +        case found of
    
    656
    +          -- Case 1: Home modules have to already be in the cache.
    
    657
    +          FoundHome (ModuleNodeFixed mod _) -> do
    
    658
    +            let edge = ModuleNodeEdge lvl (NodeKey_Module mod)
    
    659
    +            -- Note: Does not perform any further downsweep as the module must already be in the cache.
    
    660
    +            return (Just edge, [])
    
    661
    +          -- Case 2: External units may not be in the cache, if we haven't already initialised the
    
    662
    +          -- module graph. We can construct the module graph for those here by calling loopUnit.
    
    663
    +          External uid -> do
    
    664
    +            let edge = ModuleNodeEdge lvl (NodeKey_ExternalUnit uid)
    
    665
    +            return (Just edge, [DSUnit{node_uid=uid, home_context_uid=homeUnitId home_unit}])
    
    666
    +          -- And if it's not found.. just carry on and hope.
    
    667
    +          _ -> return (Nothing, [])
    
    668
    +
    
    669
    +  (module_edges, todo) <- unzip <$> mapM mkEdge imps
    
    670
    +  pure $ Just
    
    671
    +    ( ModuleNode (catMaybes module_edges) node_type, concat todo )
    
    496 672
       where
    
    497
    -    k = NodeKey_Module (msKey ms)
    
    673
    +    -- No sensible value for ModLocation.. if you hit this panic then you probably
    
    674
    +    -- need to add proper support for modules without any source files to the driver.
    
    675
    +    ml = pprPanic "modLocation" (ppr imod <+> ppr imps)
    
    676
    +    key = moduleToMnk imod NotBoot
    
    677
    +    node_type = ModuleNodeFixed key ml
    
    498 678
     
    
    499
    -    hs_file_for_boot
    
    500
    -      | HsBootFile <- ms_hsc_src ms
    
    501
    -      = Just (NormalLevel, NoPkgQual, (GWIB (noLoc $ ms_mod_name ms) NotBoot))
    
    502
    -      | otherwise
    
    503
    -      = Nothing
    
    504
    -
    
    505
    -loopModuleNodeInfos :: [ModuleNodeInfo] -> (M.Map NodeKey ModuleGraphNode, DownsweepCache) -> DownsweepM (M.Map NodeKey ModuleGraphNode, DownsweepCache)
    
    506
    -loopModuleNodeInfos is cache = foldM (flip loopModuleNodeInfo) cache is
    
    507
    -
    
    508
    -loopModuleNodeInfo :: ModuleNodeInfo -> (M.Map NodeKey ModuleGraphNode, DownsweepCache) -> DownsweepM (M.Map NodeKey ModuleGraphNode, DownsweepCache)
    
    509
    -loopModuleNodeInfo mod_node_info (done, summarised) = do
    
    510
    -  case mod_node_info of
    
    511
    -    ModuleNodeCompile ms -> do
    
    512
    -      loopSummaries [ms] (done, summarised)
    
    513
    -    ModuleNodeFixed mod ml -> do
    
    514
    -      done' <- loopFixedModule mod ml done
    
    515
    -      return (done', summarised)
    
    516
    -
    
    517
    --- NB: loopFixedModule does not take a downsweep cache, because if you
    
    518
    --- ever reach a Fixed node, everything under that also must be fixed.
    
    519
    -loopFixedModule :: ModNodeKeyWithUid -> ModLocation
    
    520
    -                -> M.Map NodeKey ModuleGraphNode
    
    521
    -                -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    522
    -loopFixedModule key loc done = do
    
    523
    -  let nk = NodeKey_Module key
    
    524
    -  hsc_env <- asks downsweep_hsc_env
    
    525
    -  case M.lookup nk done of
    
    526
    -    Just {} -> return done
    
    527
    -    Nothing -> do
    
    528
    -      -- MP: TODO, we should just read the dependency info from the interface rather than either
    
    529
    -      -- a. Loading the whole thing into the EPS (this might never nececssary and causes lots of things to be permanently loaded into memory)
    
    530
    -      -- b. Loading the whole interface into a buffer before discarding it. (wasted allocation and deserialisation)
    
    531
    -      read_result <- liftIO $
    
    532
    -        -- 1. Check if the interface is already loaded into the EPS by some other
    
    533
    -        -- part of the compiler.
    
    534
    -        lookupIfaceByModuleHsc hsc_env (mnkToModule key) >>= \case
    
    535
    -          Just iface -> return (M.Succeeded iface)
    
    536
    -          Nothing -> readIface (hsc_hooks hsc_env) (hsc_logger hsc_env) (hsc_dflags hsc_env) (hsc_NC hsc_env) (mnkToModule key) (ml_hi_file loc)
    
    537
    -      case read_result of
    
    538
    -        M.Succeeded iface -> do
    
    539
    -          -- Computer information about this node
    
    540
    -          let node_deps = ifaceDeps (mi_deps iface)
    
    541
    -              edges = map mkFixedEdge node_deps
    
    542
    -              node = ModuleNode edges (ModuleNodeFixed key loc)
    
    543
    -          foldM (loopFixedNodeKey (mnkUnitId key)) (M.insert nk node done) (bimap snd snd <$> node_deps)
    
    544
    -        -- Ignore any failure, we might try to read a .hi-boot file for
    
    545
    -        -- example, even if there is not one.
    
    546
    -        M.Failed {} ->
    
    547
    -          return done
    
    548
    -
    
    549
    -loopFixedNodeKey :: UnitId -> M.Map NodeKey ModuleGraphNode -> Either ModNodeKeyWithUid UnitId -> DownsweepM  (M.Map NodeKey ModuleGraphNode)
    
    550
    -loopFixedNodeKey _ done (Left key) = do
    
    551
    -  loopFixedImports [key] done
    
    552
    -loopFixedNodeKey home_uid done (Right uid) = do
    
    553
    -  -- Set active unit so that looking loopUnit finds the correct
    
    554
    -  -- -package flags in the unit state.
    
    555
    -  hsc_env <- asks downsweep_hsc_env
    
    556
    -  let hsc_env' = hscSetActiveUnitId home_uid hsc_env
    
    557
    -  return $ loopUnit hsc_env' done [uid]
    
    679
    +--------------------------------------------------------------------------------
    
    558 680
     
    
    559 681
     mkFixedEdge :: Either (ImportLevel, ModNodeKeyWithUid) (ImportLevel, UnitId) -> ModuleNodeEdge
    
    560 682
     mkFixedEdge (Left (lvl, key)) = mkModuleEdge lvl (NodeKey_Module key)
    
    ... ... @@ -569,27 +691,6 @@ ifaceDeps deps =
    569 691
       | (lvl, uid) <- Set.toList (dep_direct_pkgs deps)
    
    570 692
       ]
    
    571 693
     
    
    572
    --- Like loopImports, but we already know exactly which module we are looking for.
    
    573
    -loopFixedImports :: [ModNodeKeyWithUid]
    
    574
    -                 -> M.Map NodeKey ModuleGraphNode
    
    575
    -                 -> DownsweepM (M.Map NodeKey ModuleGraphNode)
    
    576
    -loopFixedImports [] done = pure done
    
    577
    -loopFixedImports (key:keys) done = do
    
    578
    -  let nk = NodeKey_Module key
    
    579
    -  hsc_env <- asks downsweep_hsc_env
    
    580
    -  case M.lookup nk done of
    
    581
    -    Just {} -> loopFixedImports keys done
    
    582
    -    Nothing -> do
    
    583
    -      read_result <- liftIO $ findExactModule hsc_env (mnkToInstalledModule key) (mnkIsBoot key)
    
    584
    -      case read_result of
    
    585
    -        InstalledFound loc -> do
    
    586
    -          done' <- loopFixedModule key loc done
    
    587
    -          loopFixedImports keys done'
    
    588
    -        _otherwise ->
    
    589
    -          -- If the finder fails, just keep going, there will be another
    
    590
    -          -- error later.
    
    591
    -          loopFixedImports keys done
    
    592
    -
    
    593 694
     downsweepSummarise :: HomeUnit
    
    594 695
                        -> IsBootInterface
    
    595 696
                        -> Located ModuleName
    
    ... ... @@ -597,90 +698,22 @@ downsweepSummarise :: HomeUnit
    597 698
                        -> Maybe (StringBuffer, UTCTime)
    
    598 699
                        -> DownsweepM SummariseResult
    
    599 700
     downsweepSummarise home_unit is_boot wanted_mod mb_pkg maybe_buf = do
    
    600
    -  DownsweepEnv hsc_env mode old_summaries excl_mods <- ask
    
    601
    -  case mode of
    
    602
    -    DownsweepUseCompile -> liftIO $ summariseModule hsc_env home_unit old_summaries is_boot wanted_mod mb_pkg maybe_buf excl_mods
    
    603
    -    DownsweepUseFixed -> liftIO $ summariseModuleInterface hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods
    
    604
    -
    
    605
    -
    
    606
    --- This loops over each import in each summary. It is mutually recursive with
    
    607
    --- loopSummaries if we discover a new module by doing this.
    
    608
    -loopImports
    
    609
    -  :: UnitId
    
    610
    -      -- ^ UnitId of home unit of summary whose imports are being processed
    
    611
    -  -> [(ImportLevel, PkgQual, GenWithIsBoot (Located ModuleName))]
    
    612
    -      -- ^ Work list: process these modules
    
    613
    -  -> M.Map NodeKey ModuleGraphNode
    
    614
    -  -> DownsweepCache
    
    615
    -      -- ^ Visited set; the range is a list because
    
    616
    -      -- the roots can have the same module names
    
    617
    -      -- if allow_dup_roots is True
    
    618
    -  -> DownsweepM ([ModuleNodeEdge],
    
    619
    -       M.Map NodeKey ModuleGraphNode, DownsweepCache)
    
    620
    -      -- ^ The result is the completed NodeMap
    
    621
    -loopImports _ [] done summarised = return ([], done, summarised)
    
    622
    -loopImports home_uid ((imp, mb_pkg, gwib) : ss) done summarised
    
    623
    -  | Just summs <- M.lookup cache_key summarised
    
    624
    -  = case summs of
    
    625
    -      [Right ms] -> do
    
    626
    -        let nk = mkModuleEdge imp (NodeKey_Module (mnKey ms))
    
    627
    -        (rest, summarised', done') <- loopImportsNext done summarised
    
    628
    -        return (nk: rest, summarised', done')
    
    629
    -      [Left _err] ->
    
    630
    -        loopImportsNext done summarised
    
    631
    -      _errs ->  do
    
    632
    -        loopImportsNext done summarised
    
    633
    -  | otherwise
    
    634
    -  = do
    
    635
    -       hsc_env <- asks downsweep_hsc_env
    
    636
    -       let home_unit = ue_unitHomeUnit home_uid (hsc_unit_env hsc_env)
    
    637
    -       mb_s <- downsweepSummarise home_unit
    
    638
    -                               is_boot wanted_mod mb_pkg
    
    639
    -                               Nothing
    
    640
    -       case mb_s of
    
    641
    -           NotThere -> loopImportsNext done summarised
    
    642
    -           External uid -> do
    
    643
    -            -- Pass an updated hsc_env to loopUnit, as each unit might
    
    644
    -            -- have a different visible package database.
    
    645
    -            let hsc_env' = hscSetActiveHomeUnit home_unit hsc_env
    
    646
    -            let done' = loopUnit hsc_env' done [uid]
    
    647
    -            (other_deps, done'', summarised') <- loopImportsNext done' summarised
    
    648
    -            return (mkModuleEdge imp (NodeKey_ExternalUnit uid) : other_deps, done'', summarised')
    
    649
    -           FoundInstantiation iud -> do
    
    650
    -            (other_deps, done', summarised') <- loopImportsNext done summarised
    
    651
    -            return (mkModuleEdge imp (NodeKey_Unit iud) : other_deps, done', summarised')
    
    652
    -           FoundHomeWithError (_uid, e) ->  loopImportsNext done (Map.insert cache_key [(Left e)] summarised)
    
    653
    -           FoundHome s -> do
    
    654
    -             (done', summarised') <-
    
    655
    -               loopModuleNodeInfo s (done, Map.insert cache_key [Right s] summarised)
    
    656
    -             (other_deps, final_done, final_summarised) <- loopImportsNext done' summarised'
    
    657
    -
    
    658
    -             -- MP: This assumes that we can only instantiate non home units, which is probably fair enough for now.
    
    659
    -             return (mkModuleEdge imp (NodeKey_Module (mnKey s)) : other_deps, final_done, final_summarised)
    
    660
    -  where
    
    661
    -    loopImportsNext = loopImports home_uid ss
    
    662
    -    cache_key = (home_uid, mb_pkg, unLoc <$> gwib)
    
    663
    -    GWIB { gwib_mod = L loc mod, gwib_isBoot = is_boot } = gwib
    
    664
    -    wanted_mod = L loc mod
    
    665
    -
    
    666
    -loopUnit :: HscEnv -> Map.Map NodeKey ModuleGraphNode -> [UnitId] -> Map.Map NodeKey ModuleGraphNode
    
    667
    -loopUnit _ cache [] = cache
    
    668
    -loopUnit lcl_hsc_env cache (u:uxs) = do
    
    669
    -   let nk = (NodeKey_ExternalUnit u)
    
    670
    -   case Map.lookup nk cache of
    
    671
    -     Just {} -> loopUnit lcl_hsc_env cache uxs
    
    672
    -     Nothing -> case unitDepends <$> lookupUnitId (hsc_units lcl_hsc_env) u of
    
    673
    -                 Just us -> loopUnit lcl_hsc_env (loopUnit lcl_hsc_env (Map.insert nk (UnitNode us u) cache) us) uxs
    
    674
    -                 Nothing -> pprPanic "loopUnit" (text "Malformed package database, missing " <+> ppr u)
    
    675
    -
    
    676
    -multiRootsErr :: SourceErrorContext -> [ModuleNodeInfo] -> IO ()
    
    677
    -multiRootsErr _ [] = panic "multiRootsErr"
    
    678
    -multiRootsErr sec summs@(summ1:_)
    
    701
    +  DownsweepEnv hsc_env mode summaries_cache_ref imports_cache_ref excl_mods <- ask
    
    702
    +  liftIO $ case mode of
    
    703
    +    DownsweepUseCompile ->
    
    704
    +      summariseModule hsc_env home_unit summaries_cache_ref imports_cache_ref
    
    705
    +                      is_boot wanted_mod mb_pkg maybe_buf excl_mods
    
    706
    +    DownsweepUseFixed ->
    
    707
    +      summariseModuleInterface hsc_env home_unit imports_cache_ref is_boot
    
    708
    +                      wanted_mod mb_pkg excl_mods
    
    709
    +
    
    710
    +multiRootsErr :: SourceErrorContext -> NE.NonEmpty ModuleNodeInfo -> IO ()
    
    711
    +multiRootsErr sec (summ1 NE.:| summs)
    
    679 712
       = throwOneError sec $ fmap GhcDriverMessage $
    
    680 713
         mkPlainErrorMsgEnvelope noSrcSpan $ DriverDuplicatedModuleDeclaration mod files
    
    681 714
       where
    
    682 715
         mod = moduleNodeInfoModule summ1
    
    683
    -    files = mapMaybe (ml_hs_file . moduleNodeInfoLocation) summs
    
    716
    +    files = mapMaybe (ml_hs_file . moduleNodeInfoLocation) (summ1:summs)
    
    684 717
     
    
    685 718
     moduleNotFoundErr :: UnitId -> ModuleName -> DriverMessages
    
    686 719
     moduleNotFoundErr uid mod = singleMessage $ mkPlainErrorMsgEnvelope noSrcSpan (DriverModuleNotFound uid mod)
    
    ... ... @@ -734,24 +767,25 @@ linkNodes summaries uid hue =
    734 767
     
    
    735 768
     getRootSummary ::
    
    736 769
       [ModuleName] ->
    
    737
    -  M.Map (UnitId, OsPath) ModSummary ->
    
    770
    +  ModSummaryCache ->
    
    771
    +  ImportsCache ->
    
    738 772
       HscEnv ->
    
    739 773
       Target ->
    
    740 774
       IO (Either DriverMessages ModSummary)
    
    741
    -getRootSummary excl_mods old_summary_map hsc_env target
    
    775
    +getRootSummary excl_mods summ_cache imports_cache hsc_env target
    
    742 776
       | TargetFile file mb_phase <- targetId
    
    743 777
       = do
    
    744 778
         let offset_file = augmentByWorkingDirectory dflags file
    
    745 779
         exists <- liftIO $ doesFileExist offset_file
    
    746 780
         if exists || isJust maybe_buf
    
    747
    -    then summariseFile hsc_env home_unit old_summary_map offset_file mb_phase
    
    781
    +    then summariseFile hsc_env home_unit summ_cache offset_file mb_phase
    
    748 782
              maybe_buf
    
    749 783
         else
    
    750 784
           return $ Left $ singleMessage $
    
    751 785
           mkPlainErrorMsgEnvelope noSrcSpan (DriverFileNotFound offset_file)
    
    752 786
       | TargetModule modl <- targetId
    
    753 787
       = do
    
    754
    -    maybe_summary <- summariseModule hsc_env home_unit old_summary_map NotBoot
    
    788
    +    maybe_summary <- summariseModule hsc_env home_unit summ_cache imports_cache NotBoot
    
    755 789
                          (L rootLoc modl) (ThisPkg (homeUnitId home_unit))
    
    756 790
                          maybe_buf excl_mods
    
    757 791
         pure case maybe_summary of
    
    ... ... @@ -1179,13 +1213,6 @@ Potential TODOS:
    1179 1213
       generating temporary ones.
    
    1180 1214
     -}
    
    1181 1215
     
    
    1182
    --- | Populate the Downsweep cache with the root modules.
    
    1183
    -mkRootMap
    
    1184
    -  :: [ModuleNodeInfo]
    
    1185
    -  -> DownsweepCache
    
    1186
    -mkRootMap summaries = Map.fromListWith (flip (++))
    
    1187
    -  [ ((moduleNodeInfoUnitId s, NoPkgQual, moduleNodeInfoMnwib s), [Right s]) | s <- summaries ]
    
    1188
    -
    
    1189 1216
     -----------------------------------------------------------------------------
    
    1190 1217
     -- Summarising modules
    
    1191 1218
     
    
    ... ... @@ -1202,33 +1229,35 @@ mkRootMap summaries = Map.fromListWith (flip (++))
    1202 1229
     summariseFile
    
    1203 1230
             :: HscEnv
    
    1204 1231
             -> HomeUnit
    
    1205
    -        -> M.Map (UnitId, OsPath) ModSummary    -- old summaries
    
    1232
    +        -> ModSummaryCache
    
    1206 1233
             -> FilePath                     -- source file name
    
    1207 1234
             -> Maybe Phase                  -- start phase
    
    1208 1235
             -> Maybe (StringBuffer,UTCTime)
    
    1209 1236
             -> IO (Either DriverMessages ModSummary)
    
    1210 1237
     
    
    1211
    -summariseFile hsc_env' home_unit old_summaries src_fn mb_phase maybe_buf
    
    1212
    -        -- we can use a cached summary if one is available and the
    
    1213
    -        -- source file hasn't changed,
    
    1214
    -   | Just old_summary <- M.lookup (homeUnitId home_unit, src_fn_os) old_summaries
    
    1215
    -   = do
    
    1216
    -        let location = ms_location $ old_summary
    
    1217
    -
    
    1218
    -        src_hash <- get_src_hash
    
    1219
    -                -- The file exists; we checked in getRootSummary above.
    
    1220
    -                -- If it gets removed subsequently, then this
    
    1221
    -                -- getFileHash may fail, but that's the right
    
    1222
    -                -- behaviour.
    
    1223
    -
    
    1224
    -                -- return the cached summary if the source didn't change
    
    1225
    -        checkSummaryHash
    
    1226
    -            hsc_env (new_summary src_fn)
    
    1227
    -            old_summary location src_hash
    
    1228
    -
    
    1229
    -   | otherwise
    
    1230
    -   = do src_hash <- get_src_hash
    
    1231
    -        new_summary src_fn src_hash
    
    1238
    +summariseFile hsc_env' home_unit summ_cache_ref src_fn mb_phase maybe_buf
    
    1239
    +   = do file_summ_cache <- readIORef summ_cache_ref
    
    1240
    +        case M.lookup (homeUnitId home_unit, src_fn_os) file_summ_cache of
    
    1241
    +          Just (Right (chd_summary, SummFresh)) ->
    
    1242
    +            -- Fresh: use it straight away
    
    1243
    +            pure (Right chd_summary)
    
    1244
    +          Just (Right (old_summary, SummOld)) -> do
    
    1245
    +            -- we can use a cached summary if one is available and the
    
    1246
    +            -- source file hasn't changed,
    
    1247
    +            let location = ms_location $ old_summary
    
    1248
    +
    
    1249
    +            src_hash <- get_src_hash
    
    1250
    +                    -- The file exists; we checked in getRootSummary above.
    
    1251
    +                    -- If it gets removed subsequently, then this
    
    1252
    +                    -- getFileHash may fail, but that's the right
    
    1253
    +                    -- behaviour.
    
    1254
    +
    
    1255
    +                    -- return the cached summary if the source didn't change
    
    1256
    +            checkSummaryHash
    
    1257
    +                hsc_env (new_summary src_fn)
    
    1258
    +                old_summary location src_hash
    
    1259
    +          _ -> do src_hash <- get_src_hash
    
    1260
    +                  new_summary src_fn src_hash
    
    1232 1261
       where
    
    1233 1262
         -- change the main active unit so all operations happen relative to the given unit
    
    1234 1263
         hsc_env = hscSetActiveHomeUnit home_unit hsc_env'
    
    ... ... @@ -1239,7 +1268,8 @@ summariseFile hsc_env' home_unit old_summaries src_fn mb_phase maybe_buf
    1239 1268
                           Just (buf,_) -> return $ fingerprintStringBuffer buf
    
    1240 1269
                           Nothing -> liftIO $ getFileHash src_fn
    
    1241 1270
     
    
    1242
    -    new_summary src_fn src_hash = runExceptT $ do
    
    1271
    +    new_summary src_fn src_hash = do
    
    1272
    +      res <- runExceptT $ do
    
    1243 1273
             preimps@PreprocessedImports {..}
    
    1244 1274
                 <- getPreprocessedImports hsc_env src_fn mb_phase maybe_buf
    
    1245 1275
     
    
    ... ... @@ -1270,6 +1300,10 @@ summariseFile hsc_env' home_unit old_summaries src_fn mb_phase maybe_buf
    1270 1300
                 , nms_mod = mod
    
    1271 1301
                 , nms_preimps = preimps
    
    1272 1302
                 }
    
    1303
    +      modifySummCache summ_cache_ref $ case res of
    
    1304
    +        Left e   -> M.insert (homeUnitId home_unit, src_fn_os) (Left e)
    
    1305
    +        Right ms -> addModSummaryCache ms SummFresh
    
    1306
    +      return res
    
    1273 1307
     
    
    1274 1308
     checkSummaryHash
    
    1275 1309
         :: HscEnv
    
    ... ... @@ -1322,15 +1356,16 @@ data SummariseResult =
    1322 1356
     -- --make mode.
    
    1323 1357
     summariseModule :: HscEnv
    
    1324 1358
                     -> HomeUnit
    
    1325
    -                -> M.Map (UnitId, OsPath) ModSummary
    
    1359
    +                -> ModSummaryCache
    
    1360
    +                -> ImportsCache
    
    1326 1361
                     -> IsBootInterface
    
    1327 1362
                     -> Located ModuleName
    
    1328 1363
                     -> PkgQual
    
    1329 1364
                     -> Maybe (StringBuffer, UTCTime)
    
    1330 1365
                     -> [ModuleName]
    
    1331 1366
                     -> IO SummariseResult
    
    1332
    -summariseModule hsc_env home_unit old_summaries is_boot wanted_mod mb_pkg maybe_buf excl_mods =
    
    1333
    -  summariseModuleDispatch k hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1367
    +summariseModule hsc_env home_unit old_summaries imps_cache is_boot wanted_mod mb_pkg maybe_buf excl_mods =
    
    1368
    +  summariseModuleDispatch k hsc_env imps_cache home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1334 1369
       where
    
    1335 1370
         k = summariseModuleWithSource home_unit old_summaries is_boot maybe_buf
    
    1336 1371
     
    
    ... ... @@ -1339,13 +1374,14 @@ summariseModule hsc_env home_unit old_summaries is_boot wanted_mod mb_pkg maybe_
    1339 1374
     -- This version always returns a ModuleNodeFixed node.
    
    1340 1375
     summariseModuleInterface :: HscEnv
    
    1341 1376
                             -> HomeUnit
    
    1377
    +                        -> ImportsCache
    
    1342 1378
                             -> IsBootInterface
    
    1343 1379
                             -> Located ModuleName
    
    1344 1380
                             -> PkgQual
    
    1345 1381
                             -> [ModuleName]
    
    1346 1382
                             -> IO SummariseResult
    
    1347
    -summariseModuleInterface hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods =
    
    1348
    -  summariseModuleDispatch k hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1383
    +summariseModuleInterface hsc_env home_unit imps_cache is_boot wanted_mod mb_pkg excl_mods =
    
    1384
    +  summariseModuleDispatch k hsc_env imps_cache home_unit is_boot wanted_mod mb_pkg excl_mods
    
    1349 1385
       where
    
    1350 1386
         k _hsc_env loc mod = do
    
    1351 1387
           -- The finder will return a path to the .hi-boot even if it doesn't actually
    
    ... ... @@ -1362,6 +1398,7 @@ summariseModuleInterface hsc_env home_unit is_boot wanted_mod mb_pkg excl_mods =
    1362 1398
     summariseModuleDispatch
    
    1363 1399
               :: (HscEnv -> ModLocation -> Module -> IO SummariseResult) -- ^ Continuation about how to summarise a home module.
    
    1364 1400
               -> HscEnv
    
    1401
    +          -> ImportsCache
    
    1365 1402
               -> HomeUnit
    
    1366 1403
               -> IsBootInterface    -- True <=> a {-# SOURCE #-} import
    
    1367 1404
               -> Located ModuleName -- Imported module to be summarised
    
    ... ... @@ -1370,7 +1407,7 @@ summariseModuleDispatch
    1370 1407
               -> IO SummariseResult
    
    1371 1408
     
    
    1372 1409
     
    
    1373
    -summariseModuleDispatch k hsc_env' home_unit is_boot (L _ wanted_mod) mb_pkg excl_mods
    
    1410
    +summariseModuleDispatch k hsc_env' imps_cache_ref home_unit is_boot (L _ wanted_mod) mb_pkg excl_mods
    
    1374 1411
       | wanted_mod `elem` excl_mods
    
    1375 1412
       = return NotThere
    
    1376 1413
       | otherwise  = find_it
    
    ... ... @@ -1380,37 +1417,44 @@ summariseModuleDispatch k hsc_env' home_unit is_boot (L _ wanted_mod) mb_pkg exc
    1380 1417
         hsc_env   = hscSetActiveHomeUnit home_unit hsc_env'
    
    1381 1418
     
    
    1382 1419
         find_it :: IO SummariseResult
    
    1383
    -
    
    1384 1420
         find_it = do
    
    1385
    -        found <- findImportedModuleWithIsBoot hsc_env wanted_mod is_boot mb_pkg
    
    1386
    -        case found of
    
    1387
    -             Found location mod
    
    1388
    -                | moduleUnitId mod `Set.member` hsc_all_home_unit_ids hsc_env ->
    
    1389
    -                        -- Home package
    
    1390
    -                         k hsc_env location mod
    
    1391
    -                | VirtUnit iud <- moduleUnit mod
    
    1392
    -                , not (isHomeModule home_unit mod)
    
    1393
    -                  -> return $ FoundInstantiation iud
    
    1394
    -                | otherwise -> return $ External (moduleUnitId mod)
    
    1395
    -             _ -> return NotThere
    
    1396
    -                        -- Not found
    
    1397
    -                        -- (If it is TRULY not found at all, we'll
    
    1398
    -                        -- error when we actually try to compile)
    
    1399
    -
    
    1421
    +      imps_cache <- readIORef imps_cache_ref
    
    1422
    +      case M.lookup cache_key imps_cache of
    
    1423
    +        Just result -> return result
    
    1424
    +        Nothing -> do
    
    1425
    +          found <- findImportedModuleWithIsBoot hsc_env wanted_mod is_boot mb_pkg
    
    1426
    +          r <- case found of
    
    1427
    +               Found location mod
    
    1428
    +                  | moduleUnitId mod `Set.member` hsc_all_home_unit_ids hsc_env ->
    
    1429
    +                          -- Home package
    
    1430
    +                           k hsc_env location mod
    
    1431
    +                  | VirtUnit iud <- moduleUnit mod
    
    1432
    +                  , not (isHomeModule home_unit mod)
    
    1433
    +                    -> return $ FoundInstantiation iud
    
    1434
    +                  | otherwise -> return $ External (moduleUnitId mod)
    
    1435
    +               _ -> return NotThere
    
    1436
    +                          -- Not found
    
    1437
    +                          -- (If it is TRULY not found at all, we'll
    
    1438
    +                          -- error when we actually try to compile)
    
    1439
    +          modifyImpsCache imps_cache_ref (M.insert cache_key r)
    
    1440
    +          return r
    
    1441
    +
    
    1442
    +    cache_key = ( homeUnitId home_unit, mb_pkg
    
    1443
    +                , GWIB{ gwib_mod = wanted_mod, gwib_isBoot = is_boot })
    
    1400 1444
     
    
    1401 1445
     -- | The continuation to summarise a home module if we want to find the source file
    
    1402 1446
     -- for it and potentially compile it.
    
    1403 1447
     summariseModuleWithSource
    
    1404 1448
               :: HomeUnit
    
    1405
    -          -> M.Map (UnitId, OsPath) ModSummary
    
    1406
    -          -- ^ Map of old summaries
    
    1449
    +          -> ModSummaryCache
    
    1450
    +          -- ^ Cache of constructed summaries
    
    1407 1451
               -> IsBootInterface    -- True <=> a {-# SOURCE #-} import
    
    1408 1452
               -> Maybe (StringBuffer, UTCTime)
    
    1409 1453
               -> HscEnv
    
    1410 1454
               -> ModLocation
    
    1411 1455
               -> Module
    
    1412 1456
               -> IO SummariseResult
    
    1413
    -summariseModuleWithSource home_unit old_summary_map is_boot maybe_buf hsc_env location mod = do
    
    1457
    +summariseModuleWithSource home_unit summ_cache_ref is_boot maybe_buf hsc_env location mod = do
    
    1414 1458
             -- Adjust location to point to the hs-boot source file,
    
    1415 1459
             -- hi file, object file, when is_boot says so
    
    1416 1460
             let src_fn = expectJust (ml_hs_file location)
    
    ... ... @@ -1430,20 +1474,22 @@ summariseModuleWithSource home_unit old_summary_map is_boot maybe_buf hsc_env lo
    1430 1474
     
    
    1431 1475
       where
    
    1432 1476
         dflags    = hsc_dflags hsc_env
    
    1433
    -    new_summary_cache_check loc mod src_fn h
    
    1434
    -      | Just old_summary <- Map.lookup ((toUnitId (moduleUnit mod), src_fn_os)) old_summary_map =
    
    1435
    -
    
    1436
    -         -- check the hash on the source file, and
    
    1437
    -         -- return the cached summary if it hasn't changed.  If the
    
    1438
    -         -- file has changed then need to resummarise.
    
    1439
    -        case maybe_buf of
    
    1440
    -           Just (buf,_) ->
    
    1441
    -               checkSummaryHash hsc_env (new_summary loc mod src_fn) old_summary loc (fingerprintStringBuffer buf)
    
    1442
    -           Nothing    ->
    
    1443
    -               checkSummaryHash hsc_env (new_summary loc mod src_fn) old_summary loc h
    
    1444
    -      | otherwise = new_summary loc mod src_fn h
    
    1445
    -      where
    
    1446
    -        src_fn_os = unsafeEncodeUtf src_fn
    
    1477
    +    new_summary_cache_check loc mod src_fn h = do
    
    1478
    +      summ_cache <- readIORef summ_cache_ref
    
    1479
    +      case ml_hs_file_ospath loc >>= \p -> M.lookup (moduleUnitId mod, p) summ_cache of
    
    1480
    +        Just (Right (chd_summary, SummFresh)) ->
    
    1481
    +          -- Fresh! just return it
    
    1482
    +          pure (Right chd_summary)
    
    1483
    +        Just (Right (old_summary, SummOld)) -> do
    
    1484
    +          -- check the hash on the source file, and
    
    1485
    +          -- return the cached summary if it hasn't changed.  If the
    
    1486
    +          -- file has changed then need to resummarise.
    
    1487
    +          case maybe_buf of
    
    1488
    +            Just (buf,_) ->
    
    1489
    +                checkSummaryHash hsc_env (new_summary loc mod src_fn) old_summary loc (fingerprintStringBuffer buf)
    
    1490
    +            Nothing    ->
    
    1491
    +                checkSummaryHash hsc_env (new_summary loc mod src_fn) old_summary loc h
    
    1492
    +        _ -> new_summary loc mod src_fn h
    
    1447 1493
     
    
    1448 1494
         new_summary :: ModLocation
    
    1449 1495
                       -> Module
    
    ... ... @@ -1451,41 +1497,48 @@ summariseModuleWithSource home_unit old_summary_map is_boot maybe_buf hsc_env lo
    1451 1497
                       -> Fingerprint
    
    1452 1498
                       -> IO (Either DriverMessages ModSummary)
    
    1453 1499
         new_summary location mod src_fn src_hash
    
    1454
    -      = runExceptT $ do
    
    1455
    -        preimps@PreprocessedImports {..}
    
    1456
    -            -- Remember to set the active unit here, otherwise the wrong include paths are passed to CPP
    
    1457
    -            -- See multiHomeUnits_cpp2 test
    
    1458
    -            <- getPreprocessedImports (hscSetActiveUnitId (moduleUnitId mod) hsc_env) src_fn Nothing maybe_buf
    
    1459
    -
    
    1460
    -        -- NB: Despite the fact that is_boot is a top-level parameter, we
    
    1461
    -        -- don't actually know coming into this function what the HscSource
    
    1462
    -        -- of the module in question is.  This is because we may be processing
    
    1463
    -        -- this module because another module in the graph imported it: in this
    
    1464
    -        -- case, we know if it's a boot or not because of the {-# SOURCE #-}
    
    1465
    -        -- annotation, but we don't know if it's a signature or a regular
    
    1466
    -        -- module until we actually look it up on the filesystem.
    
    1467
    -        let hsc_src
    
    1468
    -              | is_boot == IsBoot           = HsBootFile
    
    1469
    -              | isHaskellSigFilename src_fn = HsigFile
    
    1470
    -              | otherwise                   = HsSrcFile
    
    1471
    -
    
    1472
    -        when (pi_mod_name /= moduleName mod) $
    
    1473
    -                throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1474
    -                       $ DriverFileModuleNameMismatch pi_mod_name (moduleName mod)
    
    1475
    -
    
    1476
    -        let instantiations = homeUnitInstantiations home_unit
    
    1477
    -        when (hsc_src == HsigFile && isNothing (lookup pi_mod_name instantiations)) $
    
    1478
    -            throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1479
    -                   $ DriverUnexpectedSignature pi_mod_name (checkBuildingCabalPackage dflags) instantiations
    
    1480
    -
    
    1481
    -        liftIO $ makeNewModSummary hsc_env $ MakeNewModSummary
    
    1482
    -            { nms_src_fn = src_fn
    
    1483
    -            , nms_src_hash = src_hash
    
    1484
    -            , nms_hsc_src = hsc_src
    
    1485
    -            , nms_location = location
    
    1486
    -            , nms_mod = mod
    
    1487
    -            , nms_preimps = preimps
    
    1488
    -            }
    
    1500
    +      = do
    
    1501
    +        res <- runExceptT $ do
    
    1502
    +          preimps@PreprocessedImports {..}
    
    1503
    +              -- Remember to set the active unit here, otherwise the wrong include paths are passed to CPP
    
    1504
    +              -- See multiHomeUnits_cpp2 test
    
    1505
    +              <- getPreprocessedImports (hscSetActiveUnitId (moduleUnitId mod) hsc_env) src_fn Nothing maybe_buf
    
    1506
    +
    
    1507
    +          -- NB: Despite the fact that is_boot is a top-level parameter, we
    
    1508
    +          -- don't actually know coming into this function what the HscSource
    
    1509
    +          -- of the module in question is.  This is because we may be processing
    
    1510
    +          -- this module because another module in the graph imported it: in this
    
    1511
    +          -- case, we know if it's a boot or not because of the {-# SOURCE #-}
    
    1512
    +          -- annotation, but we don't know if it's a signature or a regular
    
    1513
    +          -- module until we actually look it up on the filesystem.
    
    1514
    +          let hsc_src
    
    1515
    +                | is_boot == IsBoot           = HsBootFile
    
    1516
    +                | isHaskellSigFilename src_fn = HsigFile
    
    1517
    +                | otherwise                   = HsSrcFile
    
    1518
    +
    
    1519
    +          when (pi_mod_name /= moduleName mod) $
    
    1520
    +                  throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1521
    +                         $ DriverFileModuleNameMismatch pi_mod_name (moduleName mod)
    
    1522
    +
    
    1523
    +          let instantiations = homeUnitInstantiations home_unit
    
    1524
    +          when (hsc_src == HsigFile && isNothing (lookup pi_mod_name instantiations)) $
    
    1525
    +              throwE $ singleMessage $ mkPlainErrorMsgEnvelope pi_mod_name_loc
    
    1526
    +                     $ DriverUnexpectedSignature pi_mod_name (checkBuildingCabalPackage dflags) instantiations
    
    1527
    +
    
    1528
    +          liftIO $ makeNewModSummary hsc_env $ MakeNewModSummary
    
    1529
    +              { nms_src_fn = src_fn
    
    1530
    +              , nms_src_hash = src_hash
    
    1531
    +              , nms_hsc_src = hsc_src
    
    1532
    +              , nms_location = location
    
    1533
    +              , nms_mod = mod
    
    1534
    +              , nms_preimps = preimps
    
    1535
    +              }
    
    1536
    +        modifySummCache summ_cache_ref $ case res of
    
    1537
    +          Left e -> case ml_hs_file_ospath location of
    
    1538
    +            Just p  -> M.insert (moduleUnitId mod, p) (Left e)
    
    1539
    +            Nothing -> id
    
    1540
    +          Right ms -> addModSummaryCache ms SummFresh
    
    1541
    +        return res
    
    1489 1542
     
    
    1490 1543
     -- | Convenience named arguments for 'makeNewModSummary' only used to make
    
    1491 1544
     -- code more readable, not exported.
    
    ... ... @@ -1568,3 +1621,78 @@ getPreprocessedImports hsc_env src_fn mb_phase maybe_buf = do
    1568 1621
       let pi_srcimps = pi_srcimps'
    
    1569 1622
       let pi_theimps = rn_imps pi_theimps'
    
    1570 1623
       return PreprocessedImports {..}
    
    1624
    +
    
    1625
    +--------------------------------------------------------------------------------
    
    1626
    +
    
    1627
    +-- | In a depth-first order, and starting from the given roots, traverse a
    
    1628
    +-- graph by iteratively expanding the visited nodes and accumulating a payload
    
    1629
    +-- for each explored node.
    
    1630
    +--
    
    1631
    +-- The same node is NEVER visited more than once, as long as the the node key
    
    1632
    +-- @k@, computed from the node @n@, uniquely identifies that node.
    
    1633
    +--
    
    1634
    +-- Example: @n@ is instanced to @DownsweepNode@, @k@ is @NodeKey@, and @v@ is @ModuleNodeEdge@.
    
    1635
    +--
    
    1636
    +-- Returning 'Nothing' in the @expand@ function means that node couldn't be
    
    1637
    +-- expanded yet, and we should continue without failure. We do not cache a
    
    1638
    +-- "negative" result for the 'Nothing', because we may yet discover new
    
    1639
    +-- information (in the monadic context) and try to expand that node in the
    
    1640
    +-- future again, then successfully.
    
    1641
    +--
    
    1642
    +-- See also Note [Downsweep Control Flow and Caching]
    
    1643
    +dfsBuild :: (Ord k, Monad m, Outputable n) => Maybe (Map.Map k v) -> [n] -> (n -> k) -> (n -> m (Maybe (v,[n]))) -> m (Map.Map k v)
    
    1644
    +dfsBuild base_map roots key expand = go roots (fromMaybe Map.empty base_map)
    
    1645
    +  where
    
    1646
    +    go []     visited = pure visited
    
    1647
    +    go (s:ss) visited
    
    1648
    +      | k `Map.member` visited
    
    1649
    +      = go ss visited
    
    1650
    +      | otherwise
    
    1651
    +      = do r <- expand s
    
    1652
    +           case r of
    
    1653
    +             Nothing -> go ss visited -- Skip!
    
    1654
    +             Just (v,ns) ->
    
    1655
    +               go (ns ++ ss {- todo: not use ++ here? -})
    
    1656
    +                  (Map.insert k v visited)
    
    1657
    +      where
    
    1658
    +        k = key s
    
    1659
    +
    
    1660
    +{-
    
    1661
    +Note [Downsweep Control Flow and Caching]
    
    1662
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    1663
    +The control flow of downsweep is extracted into a single function `dfsBuild`,
    
    1664
    +which takes care of iteratively expanding and traversing all nodes of the
    
    1665
    +in-construction module graph necessary to build a full `ModuleGraph` at the
    
    1666
    +end.
    
    1667
    +
    
    1668
    +There are three levels of caching going on, all of which are necessary
    
    1669
    +to make sure we don't do repeated work (specifically: NEVER summarise
    
    1670
    +the same module twice).
    
    1671
    +
    
    1672
    +1. `dfsBuild` accumulates the final module graph and never revisits the
    
    1673
    +   same node of the module graph. Cache is keyed by the final
    
    1674
    +   `ModuleGraph`s `NodeKey`s.
    
    1675
    +
    
    1676
    +2. For Module A in home-unit u1, each import in the list of imports
    
    1677
    +   needs to be *found* (call to `findImportedModuleWithIsBoot`): at this
    
    1678
    +   point, we only have the `ModuleName` of the import, not the `Module`.
    
    1679
    +   This *finding* is somewhat expensive, so we cache it as well
    
    1680
    +   (`ImportsCache`). The cache key is the home-unit to which the module
    
    1681
    +   belongs~[1], the import package qualifier, and the ModuleName.
    
    1682
    +
    
    1683
    +   [1] Different home-units will have different package flags, which means
    
    1684
    +   potentially different `Module` resolution for the same `ModuleName`.
    
    1685
    +
    
    1686
    +3. The most expensive operation we want to avoid is summarising a
    
    1687
    +   `Module` into a `ModSummary`, which notably involves parsing the
    
    1688
    +   module header from scratch.
    
    1689
    +   The third cache, in essence, maps a `Module` to its `ModSummary`
    
    1690
    +   (named `ModSummaryCache`). This cache upholds the invariant: we NEVER
    
    1691
    +   summarise the same module twice. In practice, the cache key is the
    
    1692
    +   Module's UnitId and the Source path; the reason is we need to
    
    1693
    +   distinguish between `.hs` and `.hs-boot` files, as their summaries
    
    1694
    +   will differ.
    
    1695
    +
    
    1696
    +   Note that (2) can't guarantee this alone: Two ModuleName imports in
    
    1697
    +   separate units can (and likely do) map to the same `Module`.
    
    1698
    +-}

  • 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