| ... |
... |
@@ -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
|
+-} |