summaryrefslogtreecommitdiff
path: root/compiler/GHC
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC')
-rw-r--r--compiler/GHC/Core/Opt/Pipeline.hs2
-rw-r--r--compiler/GHC/Core/Opt/Specialise.hs2
-rw-r--r--compiler/GHC/Driver/Env.hs55
-rw-r--r--compiler/GHC/Driver/Main.hs3
-rw-r--r--compiler/GHC/Driver/Pipeline.hs2
-rw-r--r--compiler/GHC/HsToCore/Usage.hs33
-rw-r--r--compiler/GHC/Iface/Load.hs19
-rw-r--r--compiler/GHC/Iface/Recomp.hs119
-rw-r--r--compiler/GHC/Iface/Tidy.hs2
-rw-r--r--compiler/GHC/Linker/Loader.hs10
-rw-r--r--compiler/GHC/Rename/Module.hs4
-rw-r--r--compiler/GHC/Rename/Names.hs83
-rw-r--r--compiler/GHC/Tc/Module.hs20
-rw-r--r--compiler/GHC/Tc/Types.hs90
-rw-r--r--compiler/GHC/Types/Unique/FM.hs16
-rw-r--r--compiler/GHC/Unit/Module/Deps.hs137
-rw-r--r--compiler/GHC/Unit/Module/ModIface.hs2
17 files changed, 366 insertions, 233 deletions
diff --git a/compiler/GHC/Core/Opt/Pipeline.hs b/compiler/GHC/Core/Opt/Pipeline.hs
index ba75cab359..90b5968a2f 100644
--- a/compiler/GHC/Core/Opt/Pipeline.hs
+++ b/compiler/GHC/Core/Opt/Pipeline.hs
@@ -109,7 +109,7 @@ core2core hsc_env guts@(ModGuts { mg_module = mod
where
logger = hsc_logger hsc_env
dflags = hsc_dflags hsc_env
- home_pkg_rules = hptRules hsc_env (dep_mods deps)
+ home_pkg_rules = hptRules hsc_env (dep_direct_mods deps)
hpt_rule_base = mkRuleBase home_pkg_rules
print_unqual = mkPrintUnqualified (hsc_unit_env hsc_env) rdr_env
-- mod: get the module out of the current HscEnv so we can retrieve it from the monad.
diff --git a/compiler/GHC/Core/Opt/Specialise.hs b/compiler/GHC/Core/Opt/Specialise.hs
index 459e3fe43c..68b16ea753 100644
--- a/compiler/GHC/Core/Opt/Specialise.hs
+++ b/compiler/GHC/Core/Opt/Specialise.hs
@@ -2592,7 +2592,7 @@ data CallInfoSet = CIS Id (Bag CallInfo)
data CallInfo
= CI { ci_key :: [SpecArg] -- All arguments
, ci_fvs :: IdSet -- Free Ids of the ci_key call
- -- *not* including the main id itself, of course
+ -- _not_ including the main id itself, of course
-- NB: excluding tyvars:
-- See Note [Specialising polymorphic dictionaries]
}
diff --git a/compiler/GHC/Driver/Env.hs b/compiler/GHC/Driver/Env.hs
index 27e250b68c..756d8eaff0 100644
--- a/compiler/GHC/Driver/Env.hs
+++ b/compiler/GHC/Driver/Env.hs
@@ -13,7 +13,8 @@ module GHC.Driver.Env
, hscEPS
, hscInterp
, hptCompleteSigs
- , hptInstances
+ , hptAllInstances
+ , hptInstancesBelow
, hptAnns
, hptAllThings
, hptSomeThingsBelowUs
@@ -64,9 +65,10 @@ import GHC.Utils.Outputable
import GHC.Utils.Monad
import GHC.Utils.Panic
import GHC.Utils.Misc
+import GHC.Types.Unique.FM
-import Control.Monad ( guard )
import Data.IORef
+import qualified Data.Set as Set
runHsc :: HscEnv -> Hsc a -> IO a
runHsc hsc_env (Hsc hsc) = do
@@ -180,14 +182,28 @@ hptCompleteSigs = hptAllThings (md_complete_matches . hm_details)
-- the Home Package Table filtered by the provided predicate function.
-- Used in @tcRnImports@, to select the instances that are in the
-- transitive closure of imports from the currently compiled module.
-hptInstances :: HscEnv -> (ModuleName -> Bool) -> ([ClsInst], [FamInst])
-hptInstances hsc_env want_this_module
+hptAllInstances :: HscEnv -> ([ClsInst], [FamInst])
+hptAllInstances hsc_env
= let (insts, famInsts) = unzip $ flip hptAllThings hsc_env $ \mod_info -> do
- guard (want_this_module (moduleName (mi_module (hm_iface mod_info))))
let details = hm_details mod_info
return (md_insts details, md_fam_insts details)
in (concat insts, concat famInsts)
+-- | Find instances visible from the given set of imports
+hptInstancesBelow :: HscEnv -> ModuleName -> [ModuleNameWithIsBoot] -> ([ClsInst], [FamInst])
+hptInstancesBelow hsc_env mn mns =
+ let (insts, famInsts) =
+ unzip $ hptSomeThingsBelowUs (\mod_info ->
+ let details = hm_details mod_info
+ -- Don't include instances for the current module
+ in if moduleName (mi_module (hm_iface mod_info)) == mn
+ then []
+ else [(md_insts details, md_fam_insts details)])
+ True -- Include -hi-boot
+ hsc_env
+ mns
+ in (concat insts, concat famInsts)
+
-- | Get rules from modules "below" this one (in the dependency sense)
hptRules :: HscEnv -> [ModuleNameWithIsBoot] -> [CoreRule]
hptRules = hptSomeThingsBelowUs (md_rules . hm_details) False
@@ -201,10 +217,33 @@ hptAnns hsc_env Nothing = hptAllThings (md_anns . hm_details) hsc_env
hptAllThings :: (HomeModInfo -> [a]) -> HscEnv -> [a]
hptAllThings extract hsc_env = concatMap extract (eltsHpt (hsc_HPT hsc_env))
+hptModulesBelow :: HscEnv -> [ModuleNameWithIsBoot] -> Set.Set ModuleNameWithIsBoot
+hptModulesBelow hsc_env mn = Set.fromList (eltsUFM $ go mn emptyUFM)
+ where
+ hpt = hsc_HPT hsc_env
+
+ go [] seen = seen
+ go (mn:mns) seen
+ | Just mn' <- lookupUFM seen (gwib_mod mn)
+ -- Already seen the module before
+ , gwib_isBoot mn' == gwib_isBoot mn = go mns seen
+ | otherwise =
+ case lookupHpt hpt (gwib_mod mn) of
+ -- Not a home module
+ Nothing -> go mns seen
+ Just hmi ->
+ let
+ comb m@(GWIB { gwib_isBoot = NotBoot }) _ = m
+ comb (GWIB { gwib_isBoot = IsBoot }) x = x
+ in
+ go (dep_direct_mods (mi_deps (hm_iface hmi)) ++ mns)
+ (addToUFM_C comb seen (gwib_mod mn) mn)
+
+
-- | Get things from modules "below" this one (in the dependency sense)
-- C.f Inst.hptInstances
hptSomeThingsBelowUs :: (HomeModInfo -> [a]) -> Bool -> HscEnv -> [ModuleNameWithIsBoot] -> [a]
-hptSomeThingsBelowUs extract include_hi_boot hsc_env deps
+hptSomeThingsBelowUs extract include_hi_boot hsc_env mod
| isOneShot (ghcMode (hsc_dflags hsc_env)) = []
| otherwise
@@ -212,7 +251,7 @@ hptSomeThingsBelowUs extract include_hi_boot hsc_env deps
in
[ thing
| -- Find each non-hi-boot module below me
- GWIB { gwib_mod = mod, gwib_isBoot = is_boot } <- deps
+ GWIB { gwib_mod = mod, gwib_isBoot = is_boot } <- Set.toList (hptModulesBelow hsc_env mod)
, include_hi_boot || (is_boot == NotBoot)
-- unsavoury: when compiling the base package with --make, we
@@ -243,7 +282,7 @@ prepareAnnotations hsc_env mb_guts = do
-- Extract dependencies of the module if we are supplied one,
-- otherwise load annotations from all home package table
-- entries regardless of dependency ordering.
- home_pkg_anns = (mkAnnEnv . hptAnns hsc_env) $ fmap (dep_mods . mg_deps) mb_guts
+ home_pkg_anns = (mkAnnEnv . hptAnns hsc_env) $ fmap (dep_direct_mods . mg_deps) mb_guts
other_pkg_anns = eps_ann_env eps
ann_env = foldl1' plusAnnEnv $ catMaybes [mb_this_module_anns,
Just home_pkg_anns,
diff --git a/compiler/GHC/Driver/Main.hs b/compiler/GHC/Driver/Main.hs
index 210c8644da..2d3e1e3925 100644
--- a/compiler/GHC/Driver/Main.hs
+++ b/compiler/GHC/Driver/Main.hs
@@ -1362,7 +1362,7 @@ hscCheckSafe' m l = do
-- check package is trusted
safeP = packageTrusted dflags (hsc_units hsc_env) home_unit trust trust_own_pkg m
-- pkg trust reqs
- pkgRs = S.fromList . map fst $ filter snd $ dep_pkgs $ mi_deps iface'
+ pkgRs = S.fromList (dep_trusted_pkgs $ mi_deps iface')
-- warn if Safe module imports Safe-Inferred module.
warns = if wopt Opt_WarnInferredSafeImports dflags
&& safeLanguageOn dflags
@@ -1518,7 +1518,6 @@ markUnsafeInfer tcg_env whyUnsafe = do
text "overlap mode isn't allowed in Safe Haskell"]
| otherwise = []
-
-- | Figure out the final correct safe haskell mode
hscGetSafeMode :: TcGblEnv -> Hsc SafeHaskellMode
hscGetSafeMode tcg_env = do
diff --git a/compiler/GHC/Driver/Pipeline.hs b/compiler/GHC/Driver/Pipeline.hs
index 02ebfbb5ce..e766fda3c7 100644
--- a/compiler/GHC/Driver/Pipeline.hs
+++ b/compiler/GHC/Driver/Pipeline.hs
@@ -554,7 +554,7 @@ link' logger tmpfs dflags unit_env batch_attempt_linking hpt
home_mod_infos = eltsHpt hpt
-- the packages we depend on
- pkg_deps = concatMap (map fst . dep_pkgs . mi_deps . hm_iface) home_mod_infos
+ pkg_deps = concatMap (dep_direct_pkgs . mi_deps . hm_iface) home_mod_infos
-- the linkables to link
linkables = map (expectJust "link".hm_linkable) home_mod_infos
diff --git a/compiler/GHC/HsToCore/Usage.hs b/compiler/GHC/HsToCore/Usage.hs
index 139ec05167..0da8f59070 100644
--- a/compiler/GHC/HsToCore/Usage.hs
+++ b/compiler/GHC/HsToCore/Usage.hs
@@ -38,11 +38,12 @@ import GHC.Unit.Module.Deps
import GHC.Data.Maybe
import Control.Monad (filterM)
-import Data.List (sort, sortBy, nub)
+import Data.List (sortBy, sort, nub)
import Data.IORef
import Data.Map (Map)
import qualified Data.Map as Map
import qualified Data.Set as Set
+
import System.Directory
import System.FilePath
@@ -80,8 +81,7 @@ mkDependencies iuid pluginModules
let (dep_plgins, ms) = unzip [ (moduleName mn, mn) | mn <- pluginModules ]
plugin_dep_pkgs = filter (/= iuid) (map (toUnitId . moduleUnit) ms)
th_used <- readIORef th_var
- let dep_mods = modDepsElts (delFromUFM (imp_dep_mods imports)
- (moduleName mod))
+ let direct_mods = modDepsElts (delFromUFM (imp_direct_dep_mods imports) (moduleName mod))
-- M.hi-boot can be in the imp_dep_mods, but we must remove
-- it before recording the modules on which this one depends!
-- (We want to retain M.hi-boot in imp_dep_mods so that
@@ -93,19 +93,28 @@ mkDependencies iuid pluginModules
-- We must also remove self-references from imp_orphs. See
-- Note [Module self-dependency]
- raw_pkgs = foldr Set.insert (imp_dep_pkgs imports) plugin_dep_pkgs
+ direct_pkgs_0 = foldr Set.insert (imp_dep_direct_pkgs imports) plugin_dep_pkgs
- pkgs | th_used = Set.insert thUnitId raw_pkgs
- | otherwise = raw_pkgs
+ direct_pkgs
+ | th_used = Set.insert thUnitId direct_pkgs_0
+ | otherwise = direct_pkgs_0
-- Set the packages required to be Safe according to Safe Haskell.
-- See Note [Tracking Trust Transitively] in GHC.Rename.Names
- sorted_pkgs = sort (Set.toList pkgs)
+ sorted_direct_pkgs = sort (Set.toList direct_pkgs)
trust_pkgs = imp_trust_pkgs imports
- dep_pkgs' = map (\x -> (x, x `Set.member` trust_pkgs)) sorted_pkgs
-
- return Deps { dep_mods = dep_mods,
- dep_pkgs = dep_pkgs',
+ -- If there's a non-boot import, then it shadows the boot import
+ -- coming from the dependencies
+ source_mods =
+ modDepsElts $ (imp_boot_mods imports)
+
+ sig_mods = filter (/= (moduleName mod)) $ imp_sig_mods imports
+
+ return Deps { dep_direct_mods = direct_mods,
+ dep_direct_pkgs = sorted_direct_pkgs,
+ dep_sig_mods = sort sig_mods,
+ dep_trusted_pkgs = sort (Set.toList trust_pkgs),
+ dep_boot_mods = sort source_mods,
dep_orphs = dep_orphs,
dep_plgins = dep_plgins,
dep_finsts = sortBy stableModuleCmp (imp_finsts imports) }
@@ -235,7 +244,7 @@ mkPluginUsage hsc_env pluginModule
pNm = moduleName $ mi_module pluginModule
pPkg = moduleUnit $ mi_module pluginModule
deps = map gwib_mod $
- dep_mods $ mi_deps pluginModule
+ dep_direct_mods $ mi_deps pluginModule
-- Lookup object file for a plugin dependency,
-- from the same package as the plugin.
diff --git a/compiler/GHC/Iface/Load.hs b/compiler/GHC/Iface/Load.hs
index 7b2a659161..89480c6112 100644
--- a/compiler/GHC/Iface/Load.hs
+++ b/compiler/GHC/Iface/Load.hs
@@ -1179,18 +1179,25 @@ pprUsageImport usage usg_mod'
-- | Pretty-print unit dependencies
pprDeps :: UnitState -> Dependencies -> SDoc
-pprDeps unit_state (Deps { dep_mods = mods, dep_pkgs = pkgs, dep_orphs = orphs,
- dep_finsts = finsts })
+pprDeps unit_state (Deps { dep_direct_mods = dmods
+ , dep_boot_mods = bmods
+ , dep_orphs = orphs
+ , dep_direct_pkgs = pkgs
+ , dep_trusted_pkgs = tps
+ , dep_finsts = finsts
+ , dep_plgins = plugins })
= pprWithUnitState unit_state $
- vcat [text "module dependencies:" <+> fsep (map ppr_mod mods),
- text "package dependencies:" <+> fsep (map ppr_pkg pkgs),
+ vcat [text "direct module dependencies:" <+> fsep (map ppr_mod dmods),
+ text "boot module dependencies:" <+> fsep (map ppr bmods),
+ text "direct package dependencies:" <+> fsep (map ppr_pkg pkgs),
+ if null tps then empty else text "trusted package dependencies:" <+> fsep (map ppr_pkg pkgs),
text "orphans:" <+> fsep (map ppr orphs),
+ text "plugins:" <+> fsep (map ppr plugins),
text "family instance modules:" <+> fsep (map ppr finsts)
]
where
ppr_mod (GWIB { gwib_mod = mod_name, gwib_isBoot = boot }) = ppr mod_name <+> ppr_boot boot
- ppr_pkg (pkg,trust_req) = ppr pkg <>
- (if trust_req then text "*" else Outputable.empty)
+ ppr_pkg pkg = ppr pkg
ppr_boot IsBoot = text "[boot]"
ppr_boot NotBoot = Outputable.empty
diff --git a/compiler/GHC/Iface/Recomp.hs b/compiler/GHC/Iface/Recomp.hs
index e033a6628a..9bccffab3d 100644
--- a/compiler/GHC/Iface/Recomp.hs
+++ b/compiler/GHC/Iface/Recomp.hs
@@ -63,9 +63,8 @@ import GHC.Unit.Module.Deps
import Control.Monad
import Data.Function
-import Data.List (find, sortBy, sort)
+import Data.List (sortBy, sort)
import qualified Data.Map as Map
-import qualified Data.Set as Set
import Data.Word (Word64)
--Qualified import so we can define a Semigroup instance
@@ -265,11 +264,10 @@ checkVersions hsc_env mod_summary iface
-- It's just temporary because either the usage check will succeed
-- (in which case we are done with this module) or it'll fail (in which
-- case we'll compile the module from scratch anyhow).
- --
- -- We do this regardless of compilation mode, although in --make mode
- -- all the dependent modules should be in the HPT already, so it's
- -- quite redundant
- ; updateEps_ $ \eps -> eps { eps_is_boot = mod_deps }
+
+ when (isOneShot (ghcMode (hsc_dflags hsc_env))) $ do {
+ ; updateEps_ $ \eps -> eps { eps_is_boot = mkModDeps $ (dep_boot_mods (mi_deps iface)) }
+ }
; recomp <- checkList [checkModUsage (homeUnitAsUnit home_unit) u
| u <- mi_usages iface]
; return (recomp, Just iface)
@@ -278,9 +276,9 @@ checkVersions hsc_env mod_summary iface
logger = hsc_logger hsc_env
dflags = hsc_dflags hsc_env
home_unit = hsc_home_unit hsc_env
- -- This is a bit of a hack really
- mod_deps :: ModuleNameEnv ModuleNameWithIsBoot
- mod_deps = mkModDeps (dep_mods (mi_deps iface))
+
+
+
-- | Check if any plugins are requesting recompilation
checkPlugins :: HscEnv -> ModIface -> IfG RecompileRequired
@@ -450,38 +448,19 @@ checkMergedSignatures hsc_env mod_summary iface = do
-- - a new home module has been added that shadows a package module
-- See bug #1372.
--
--- In addition, we also check if the union of dependencies of the imported
--- modules has any difference to the previous set of dependencies. We would need
--- to recompile in that case also since the `mi_deps` field of ModIface needs
--- to be updated to match that information. This is one of the invariants
--- of interface files (see https://gitlab.haskell.org/ghc/ghc/wikis/commentary/compiler/recompilation-avoidance#interface-file-invariants).
--- See bug #16511.
---
-- Returns (RecompBecause <textual reason>) if recompilation is required.
checkDependencies :: HscEnv -> ModSummary -> ModIface -> IfG RecompileRequired
checkDependencies hsc_env summary iface
- =
- checkList $
- [ liftIO $ checkList (map dep_missing (ms_imps summary ++ ms_srcimps summary))
- , do
- (recomp, mnames_seen) <- runUntilRecompRequired $ map
- checkForNewHomeDependency
- (ms_home_imps summary)
- liftIO $ case recomp of
- UpToDate -> do
- let
- seen_home_deps = Set.unions $ map Set.fromList mnames_seen
- checkIfAllOldHomeDependenciesAreSeen seen_home_deps
- _ -> return recomp]
+ = liftIO $ checkList (map dep_missing (ms_imps summary ++ ms_srcimps summary))
where
dflags = hsc_dflags hsc_env
logger = hsc_logger hsc_env
fc = hsc_FC hsc_env
home_unit = hsc_home_unit hsc_env
units = hsc_units hsc_env
- prev_dep_mods = dep_mods (mi_deps iface)
+ prev_dep_mods = dep_direct_mods (mi_deps iface)
prev_dep_plgn = dep_plgins (mi_deps iface)
- prev_dep_pkgs = dep_pkgs (mi_deps iface)
+ prev_dep_pkgs = dep_direct_pkgs (mi_deps iface)
dep_missing (mb_pkg, L _ mod) = do
find_res <- findImportedModule fc units home_unit dflags mod (mb_pkg)
@@ -497,7 +476,7 @@ checkDependencies hsc_env summary iface
else
return UpToDate
| otherwise
- -> if toUnitId pkg `notElem` (map fst prev_dep_pkgs)
+ -> if toUnitId pkg `notElem` prev_dep_pkgs
then do trace_hi_diffs logger dflags $
text "imported module " <> quotes (ppr mod) <>
text " is from package " <> quotes (ppr pkg) <>
@@ -508,58 +487,6 @@ checkDependencies hsc_env summary iface
where pkg = moduleUnit mod
_otherwise -> return (RecompBecause reason)
- projectNonBootNames = map gwib_mod . filter ((== NotBoot) . gwib_isBoot)
- old_deps = Set.fromList
- $ projectNonBootNames prev_dep_mods
- isOldHomeDeps = flip Set.member old_deps
- checkForNewHomeDependency (L _ mname) = do
- let
- mod = mkHomeModule home_unit mname
- str_mname = moduleNameString mname
- reason = str_mname ++ " changed"
- -- We only want to look at home modules to check if any new home dependency
- -- pops in and thus here, skip modules that are not home. Checking
- -- membership in old home dependencies suffice because the `dep_missing`
- -- check already verified that all imported home modules are present there.
- if not (isOldHomeDeps mname)
- then return (UpToDate, [])
- else do
- mb_result <- getFromModIface "need mi_deps for" mod $ \imported_iface -> do
- let mnames = mname:(map gwib_mod $ filter ((== NotBoot) . gwib_isBoot) $
- dep_mods $ mi_deps imported_iface)
- case find (not . isOldHomeDeps) mnames of
- Nothing -> return (UpToDate, mnames)
- Just new_dep_mname -> do
- trace_hi_diffs logger dflags $
- text "imported home module " <> quotes (ppr mod) <>
- text " has a new dependency " <> quotes (ppr new_dep_mname)
- return (RecompBecause reason, [])
- return $ fromMaybe (MustCompile, []) mb_result
-
- -- Performs all recompilation checks in the list until a check that yields
- -- recompile required is encountered. Returns the list of the results of
- -- all UpToDate checks.
- runUntilRecompRequired [] = return (UpToDate, [])
- runUntilRecompRequired (check:checks) = do
- (recompile, value) <- check
- if recompileRequired recompile
- then return (recompile, [])
- else do
- (recomp, values) <- runUntilRecompRequired checks
- return (recomp, value:values)
-
- checkIfAllOldHomeDependenciesAreSeen seen_deps = do
- let unseen_old_deps = Set.difference
- old_deps
- seen_deps
- if not (null unseen_old_deps)
- then do
- let missing_dep = Set.elemAt 0 unseen_old_deps
- trace_hi_diffs logger dflags $
- text "missing old home dependency " <> quotes (ppr missing_dep)
- return $ RecompBecause "missing old dependency"
- else return UpToDate
-
needInterface :: Module -> (ModIface -> IO RecompileRequired)
-> IfG RecompileRequired
needInterface mod continue
@@ -1043,17 +970,22 @@ addFingerprints hsc_env iface0
orphan_hash <- computeFingerprint (mk_put_name local_env)
(map ifDFun orph_insts, orph_rules, orph_fis)
+ -- Hash of the transitive things in dependencies
+ dep_hash <- computeFingerprint putNameLiterally
+ (dep_sig_mods (mi_deps iface0),
+ dep_boot_mods (mi_deps iface0),
+ -- Trusted packages are like orphans
+ dep_trusted_pkgs (mi_deps iface0),
+ -- See Note [Export hash depends on non-orphan family instances]
+ dep_finsts (mi_deps iface0) )
+
-- the export list hash doesn't depend on the fingerprints of
-- the Names it mentions, only the Names themselves, hence putNameLiterally.
export_hash <- computeFingerprint putNameLiterally
(mi_exports iface0,
orphan_hash,
+ dep_hash,
dep_orphan_hashes,
- dep_pkgs (mi_deps iface0),
- -- See Note [Export hash depends on non-orphan family instances]
- dep_finsts (mi_deps iface0),
- -- dep_pkgs: see "Package Version Changes" on
- -- wiki/commentary/compiler/recompilation-avoidance
mi_trust iface0)
-- Make sure change of Safe Haskell mode causes recomp.
@@ -1209,8 +1141,11 @@ getOrphanHashes hsc_env mods = do
sortDependencies :: Dependencies -> Dependencies
sortDependencies d
- = Deps { dep_mods = sortBy (lexicalCompareFS `on` (moduleNameFS . gwib_mod)) (dep_mods d),
- dep_pkgs = sortBy (compare `on` fst) (dep_pkgs d),
+ = Deps { dep_direct_mods = sortBy (lexicalCompareFS `on` (moduleNameFS . gwib_mod)) (dep_direct_mods d),
+ dep_direct_pkgs = sort (dep_direct_pkgs d),
+ dep_sig_mods = sort (dep_sig_mods d),
+ dep_trusted_pkgs = sort (dep_trusted_pkgs d),
+ dep_boot_mods = sort (dep_boot_mods d),
dep_orphs = sortBy stableModuleCmp (dep_orphs d),
dep_finsts = sortBy stableModuleCmp (dep_finsts d),
dep_plgins = sortBy (lexicalCompareFS `on` moduleNameFS) (dep_plgins d) }
diff --git a/compiler/GHC/Iface/Tidy.hs b/compiler/GHC/Iface/Tidy.hs
index 71e93671b9..96da0ce2c0 100644
--- a/compiler/GHC/Iface/Tidy.hs
+++ b/compiler/GHC/Iface/Tidy.hs
@@ -459,7 +459,7 @@ tidyProgram hsc_env (ModGuts { mg_module = mod
cg_binds = all_tidy_binds,
cg_foreign = add_spt_init_code foreign_stubs,
cg_foreign_files = foreign_files,
- cg_dep_pkgs = map fst $ dep_pkgs deps,
+ cg_dep_pkgs = dep_direct_pkgs deps,
cg_hpc_info = hpc_info,
cg_modBreaks = modBreaks,
cg_spt_entries = spt_entries },
diff --git a/compiler/GHC/Linker/Loader.hs b/compiler/GHC/Linker/Loader.hs
index 1258034fb5..ccd3879910 100644
--- a/compiler/GHC/Linker/Loader.hs
+++ b/compiler/GHC/Linker/Loader.hs
@@ -692,20 +692,20 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods
deps = mi_deps iface
home_unit = hsc_home_unit hsc_env
- pkg_deps = dep_pkgs deps
- (boot_deps, mod_deps) = flip partitionWith (dep_mods deps) $
+ pkg_deps = dep_direct_pkgs deps
+ (boot_deps, mod_deps) = flip partitionWith (dep_direct_mods deps) $
\ (GWIB { gwib_mod = m, gwib_isBoot = is_boot }) ->
m & case is_boot of
IsBoot -> Left
NotBoot -> Right
- boot_deps' = filter (not . (`elementOfUniqDSet` acc_mods)) boot_deps
+ mod_deps' = filter (not . (`elementOfUniqDSet` acc_mods)) (boot_deps ++ mod_deps)
acc_mods' = addListToUniqDSet acc_mods (moduleName mod : mod_deps)
- acc_pkgs' = addListToUniqDSet acc_pkgs $ map fst pkg_deps
+ acc_pkgs' = addListToUniqDSet acc_pkgs pkg_deps
--
if not (isHomeUnit home_unit pkg)
then follow_deps mods acc_mods (addOneToUniqDSet acc_pkgs' (toUnitId pkg))
- else follow_deps (map (mkHomeModule home_unit) boot_deps' ++ mods)
+ else follow_deps (map (mkHomeModule home_unit) mod_deps' ++ mods)
acc_mods' acc_pkgs'
where
msg = text "need to link module" <+> ppr mod <+>
diff --git a/compiler/GHC/Rename/Module.hs b/compiler/GHC/Rename/Module.hs
index 8bb8557186..2eb048f3f6 100644
--- a/compiler/GHC/Rename/Module.hs
+++ b/compiler/GHC/Rename/Module.hs
@@ -763,10 +763,10 @@ rnFamEqn doc atfi extra_kvars
-- See Note [Renaming associated types].
-- Per that Note, the LHS type variables consist of:
--
- -- * The variables mentioned in the instance's type patterns
+ -- - The variables mentioned in the instance's type patterns
-- (pat_fvs), and
--
- -- * The variables mentioned in an outermost kind signature on the
+ -- - The variables mentioned in an outermost kind signature on the
-- RHS. This is a subset of `rhs_fvs`. To compute it, we look up
-- each RdrName in `extra_kvars` to find its corresponding Name in
-- the LocalRdrEnv.
diff --git a/compiler/GHC/Rename/Names.hs b/compiler/GHC/Rename/Names.hs
index b747f73987..68dab19a9b 100644
--- a/compiler/GHC/Rename/Names.hs
+++ b/compiler/GHC/Rename/Names.hs
@@ -71,6 +71,7 @@ import GHC.Types.Basic ( TopLevelFlag(..) )
import GHC.Types.SourceText
import GHC.Types.Id
import GHC.Types.HpcInfo
+import GHC.Types.Unique.FM
import GHC.Unit
import GHC.Unit.Module.Warnings
@@ -198,9 +199,20 @@ rnImports imports = do
stuff2 <- mapAndReportM (rnImportDecl this_mod) source
-- Safe Haskell: See Note [Tracking Trust Transitively]
let (decls, rdr_env, imp_avails, hpc_usage) = combine (stuff1 ++ stuff2)
- return (decls, rdr_env, imp_avails, hpc_usage)
+ -- Update imp_boot_mods if imp_direct_mods mentions any of them
+ let final_import_avail = clobberSourceImports imp_avails
+ return (decls, rdr_env, final_import_avail, hpc_usage)
where
+ clobberSourceImports imp_avails =
+ imp_avails { imp_boot_mods = imp_boot_mods' }
+ where
+ imp_boot_mods' = mergeUFM combJ id (const mempty)
+ (imp_boot_mods imp_avails)
+ (imp_direct_dep_mods imp_avails)
+
+ combJ (GWIB _ IsBoot) x = Just x
+ combJ r _ = Just r
-- See Note [Combining ImportAvails]
combine :: [(LImportDecl GhcRn, GlobalRdrEnv, ImportAvails, AnyHpcUsage)]
-> ([LImportDecl GhcRn], GlobalRdrEnv, ImportAvails, AnyHpcUsage)
@@ -422,6 +434,7 @@ calculateAvails home_unit iface mod_safe' want_boot imported_by =
deps = mi_deps iface
trust = getSafeMode $ mi_trust iface
trust_pkg = mi_trust_pkg iface
+ is_sig = mi_hsc_src iface == HsigFile
-- If the module exports anything defined in this module, just
-- ignore it. Reason: otherwise it looks as if there are two
@@ -457,53 +470,61 @@ calculateAvails home_unit iface mod_safe' want_boot imported_by =
imp_sem_mod : dep_finsts deps
| otherwise = dep_finsts deps
+ -- Trusted packages are a lot like orphans.
+ trusted_pkgs | mod_safe' = S.fromList (dep_trusted_pkgs deps)
+ | otherwise = S.empty
+
+
pkg = moduleUnit (mi_module iface)
ipkg = toUnitId pkg
-- Does this import mean we now require our own pkg
-- to be trusted? See Note [Trust Own Package]
ptrust = trust == Sf_Trustworthy || trust_pkg
+ pkg_trust_req
+ | isHomeUnit home_unit pkg = ptrust
+ | otherwise = False
+
+ dependent_pkgs = if isHomeUnit home_unit pkg
+ then S.empty
+ else S.fromList [ipkg]
+
+ direct_mods = mkModDeps $ if isHomeUnit home_unit pkg
+ then [GWIB (moduleName imp_mod) want_boot]
+ else []
+
+ dep_boot_mods_map = mkModDeps (dep_boot_mods deps)
+
+ boot_mods
+ -- If we are looking for a boot module, it must be HPT
+ | IsBoot <- want_boot = addToUFM dep_boot_mods_map (moduleName imp_mod) (GWIB (moduleName imp_mod) IsBoot)
+ -- Now we are importing A properly, so don't go looking for
+ -- A.hs-boot
+ | isHomeUnit home_unit pkg = dep_boot_mods_map
+ -- There's no boot files to find in external imports
+ | otherwise = emptyUFM
+
+ sig_mods =
+ if is_sig
+ then moduleName imp_mod : dep_sig_mods deps
+ else dep_sig_mods deps
- (dependent_mods, dependent_pkgs, pkg_trust_req)
- | isHomeUnit home_unit pkg =
- -- Imported module is from the home package
- -- Take its dependent modules and add imp_mod itself
- -- Take its dependent packages unchanged
- --
- -- NB: (dep_mods deps) might include a hi-boot file
- -- for the module being compiled, CM. Do *not* filter
- -- this out (as we used to), because when we've
- -- finished dealing with the direct imports we want to
- -- know if any of them depended on CM.hi-boot, in
- -- which case we should do the hi-boot consistency
- -- check. See GHC.Iface.Load.loadHiBootInterface
- ( GWIB { gwib_mod = moduleName imp_mod, gwib_isBoot = want_boot } : dep_mods deps
- , dep_pkgs deps
- , ptrust
- )
-
- | otherwise =
- -- Imported module is from another package
- -- Dump the dependent modules
- -- Add the package imp_mod comes from to the dependent packages
- assertPpr (not (ipkg `elem` (map fst $ dep_pkgs deps)))
- (ppr ipkg <+> ppr (dep_pkgs deps))
- ([], (ipkg, False) : dep_pkgs deps, False)
in ImportAvails {
imp_mods = unitModuleEnv (mi_module iface) [imported_by],
imp_orphs = orphans,
imp_finsts = finsts,
- imp_dep_mods = mkModDeps dependent_mods,
- imp_dep_pkgs = S.fromList . map fst $ dependent_pkgs,
+ imp_sig_mods = sig_mods,
+ imp_direct_dep_mods = direct_mods,
+ imp_dep_direct_pkgs = dependent_pkgs,
+ imp_boot_mods = boot_mods,
+
-- Add in the imported modules trusted package
-- requirements. ONLY do this though if we import the
-- module as a safe import.
-- See Note [Tracking Trust Transitively]
-- and Note [Trust Transitive Property]
- imp_trust_pkgs = if mod_safe'
- then S.fromList . map fst $ filter snd dependent_pkgs
- else S.empty,
+ imp_trust_pkgs = trusted_pkgs,
-- Do we require our own pkg to be trusted?
-- See Note [Trust Own Package]
imp_trust_own_pkg = pkg_trust_req
diff --git a/compiler/GHC/Tc/Module.hs b/compiler/GHC/Tc/Module.hs
index 5e3f0b3501..b04ab96e43 100644
--- a/compiler/GHC/Tc/Module.hs
+++ b/compiler/GHC/Tc/Module.hs
@@ -366,7 +366,7 @@ tcRnImports hsc_env import_decls
; this_mod <- getModule
; let { dep_mods :: ModuleNameEnv ModuleNameWithIsBoot
- ; dep_mods = imp_dep_mods imports
+ ; dep_mods = imp_direct_dep_mods imports
-- We want instance declarations from all home-package
-- modules below this one, including boot modules, except
@@ -375,17 +375,15 @@ tcRnImports hsc_env import_decls
-- filtering also ensures that we don't see instances from
-- modules batch (@--make@) compiled before this one, but
-- which are not below this one.
- ; want_instances :: ModuleName -> Bool
- ; want_instances mod = mod `elemUFM` dep_mods
- && mod /= moduleName this_mod
- ; (home_insts, home_fam_insts) = hptInstances hsc_env
- want_instances
+ ; (home_insts, home_fam_insts) = hptInstancesBelow hsc_env (moduleName this_mod) (eltsUFM dep_mods)
} ;
-- Record boot-file info in the EPS, so that it's
-- visible to loadHiBootInterface in tcRnSrcDecls,
-- and any other incrementally-performed imports
- ; updateEps_ (\eps -> eps { eps_is_boot = dep_mods }) ;
+ ; when (isOneShot (ghcMode (hsc_dflags hsc_env))) $ do {
+ updateEps_ $ \eps -> eps { eps_is_boot = imp_boot_mods imports }
+ }
-- Update the gbl env
; updGblEnv ( \ gbl ->
@@ -399,7 +397,7 @@ tcRnImports hsc_env import_decls
tcg_hpc = hpc_info
}) $ do {
- ; traceRn "rn1" (ppr (imp_dep_mods imports))
+ ; traceRn "rn1" (ppr (imp_direct_dep_mods imports))
-- Fail if there are any errors so far
-- The error printing (if needed) takes advantage
-- of the tcg_env we have now set
@@ -2070,7 +2068,7 @@ runTcInteractive hsc_env thing_inside
; setEnvs (gbl_env', lcl_env') thing_inside }
where
- (home_insts, home_fam_insts) = hptInstances hsc_env (\_ -> True)
+ (home_insts, home_fam_insts) = hptAllInstances hsc_env
icxt = hsc_IC hsc_env
(ic_insts, ic_finsts) = ic_instances icxt
@@ -2952,9 +2950,9 @@ pprTcGblEnv (TcGblEnv { tcg_type_env = type_env,
, ppr_fam_insts fam_insts
, ppr_rules rules
, text "Dependent modules:" <+>
- pprUFM (imp_dep_mods imports) (ppr . sort)
+ pprUFM (imp_direct_dep_mods imports) (ppr . sort)
, text "Dependent packages:" <+>
- ppr (S.toList $ imp_dep_pkgs imports)]
+ ppr (S.toList $ imp_dep_direct_pkgs imports)]
-- The use of sort is just to reduce unnecessary
-- wobbling in testsuite output
diff --git a/compiler/GHC/Tc/Types.hs b/compiler/GHC/Tc/Types.hs
index 0145ee9b43..2d80039234 100644
--- a/compiler/GHC/Tc/Types.hs
+++ b/compiler/GHC/Tc/Types.hs
@@ -1346,31 +1346,11 @@ data ImportAvails
-- different packages. (currently not the case, but might be in the
-- future).
- imp_dep_mods :: ModuleNameEnv ModuleNameWithIsBoot,
- -- ^ Home-package modules needed by the module being compiled
- --
- -- It doesn't matter whether any of these dependencies
- -- are actually /used/ when compiling the module; they
- -- are listed if they are below it at all. For
- -- example, suppose M imports A which imports X. Then
- -- compiling M might not need to consult X.hi, but X
- -- is still listed in M's dependencies.
-
- imp_dep_pkgs :: Set UnitId,
- -- ^ Packages needed by the module being compiled, whether directly,
- -- or via other modules in this package, or via modules imported
- -- from other packages.
+ imp_direct_dep_mods :: ModuleNameEnv ModuleNameWithIsBoot,
+ -- ^ Home-package modules directly imported by the module being compiled.
- imp_trust_pkgs :: Set UnitId,
- -- ^ This is strictly a subset of imp_dep_pkgs and records the
- -- packages the current module needs to trust for Safe Haskell
- -- compilation to succeed. A package is required to be trusted if
- -- we are dependent on a trustworthy module in that package.
- -- While perhaps making imp_dep_pkgs a tuple of (UnitId, Bool)
- -- where True for the bool indicates the package is required to be
- -- trusted is the more logical design, doing so complicates a lot
- -- of code not concerned with Safe Haskell.
- -- See Note [Tracking Trust Transitively] in "GHC.Rename.Names"
+ imp_dep_direct_pkgs :: Set UnitId,
+ -- ^ Packages directly needed by the module being compiled
imp_trust_own_pkg :: Bool,
-- ^ Do we require that our own package is trusted?
@@ -1378,6 +1358,23 @@ data ImportAvails
-- a Trustworthy module that resides in the same package as it.
-- See Note [Trust Own Package] in "GHC.Rename.Names"
+ -- Transitive information below here
+
+ imp_trust_pkgs :: Set UnitId,
+ -- ^ This records the
+ -- packages the current module needs to trust for Safe Haskell
+ -- compilation to succeed. A package is required to be trusted if
+ -- we are dependent on a trustworthy module in that package.
+ -- See Note [Tracking Trust Transitively] in "GHC.Rename.Names"
+
+ imp_boot_mods :: ModuleNameEnv ModuleNameWithIsBoot,
+ -- ^ Domain is all modules which have hs-boot files, and whether
+ -- we should import the boot version of interface file. Only used
+ -- in one-shot mode to populate eps_is_boot.
+
+ imp_sig_mods :: [ModuleName],
+ -- ^ Signature modules below this one
+
imp_orphs :: [Module],
-- ^ Orphan modules below us in the import tree (and maybe including
-- us for imported modules)
@@ -1393,6 +1390,20 @@ mkModDeps deps = foldl' add emptyUFM deps
where
add env elt = addToUFM env (gwib_mod elt) elt
+plusModDeps :: ModuleNameEnv ModuleNameWithIsBoot
+ -> ModuleNameEnv ModuleNameWithIsBoot
+ -> ModuleNameEnv ModuleNameWithIsBoot
+plusModDeps = plusUFM_C plus_mod_dep
+ where
+ plus_mod_dep r1@(GWIB { gwib_mod = m1, gwib_isBoot = boot1 })
+ r2@(GWIB {gwib_mod = m2, gwib_isBoot = boot2})
+ | assertPpr (m1 == m2) ((ppr m1 <+> ppr m2) $$ (ppr (boot1 == IsBoot) <+> ppr (boot2 == IsBoot)))
+ boot1 == IsBoot = r2
+ | otherwise = r1
+ -- If either side can "see" a non-hi-boot interface, use that
+ -- Reusing existing tuples saves 10% of allocations on test
+ -- perf/compiler/MultiLayerModules
+
modDepsElts
:: ModuleNameEnv ModuleNameWithIsBoot
-> [ModuleNameWithIsBoot]
@@ -1402,10 +1413,12 @@ modDepsElts = sort . nonDetEltsUFM
emptyImportAvails :: ImportAvails
emptyImportAvails = ImportAvails { imp_mods = emptyModuleEnv,
- imp_dep_mods = emptyUFM,
- imp_dep_pkgs = S.empty,
+ imp_direct_dep_mods = emptyUFM,
+ imp_dep_direct_pkgs = S.empty,
+ imp_sig_mods = [],
imp_trust_pkgs = S.empty,
imp_trust_own_pkg = False,
+ imp_boot_mods = emptyUFM,
imp_orphs = [],
imp_finsts = [] }
@@ -1417,29 +1430,28 @@ emptyImportAvails = ImportAvails { imp_mods = emptyModuleEnv,
plusImportAvails :: ImportAvails -> ImportAvails -> ImportAvails
plusImportAvails
(ImportAvails { imp_mods = mods1,
- imp_dep_mods = dmods1, imp_dep_pkgs = dpkgs1,
+ imp_direct_dep_mods = ddmods1,
+ imp_dep_direct_pkgs = ddpkgs1,
+ imp_boot_mods = srs1,
+ imp_sig_mods = sig_mods1,
imp_trust_pkgs = tpkgs1, imp_trust_own_pkg = tself1,
imp_orphs = orphs1, imp_finsts = finsts1 })
(ImportAvails { imp_mods = mods2,
- imp_dep_mods = dmods2, imp_dep_pkgs = dpkgs2,
+ imp_direct_dep_mods = ddmods2,
+ imp_dep_direct_pkgs = ddpkgs2,
+ imp_boot_mods = srcs2,
+ imp_sig_mods = sig_mods2,
imp_trust_pkgs = tpkgs2, imp_trust_own_pkg = tself2,
imp_orphs = orphs2, imp_finsts = finsts2 })
= ImportAvails { imp_mods = plusModuleEnv_C (++) mods1 mods2,
- imp_dep_mods = plusUFM_C plus_mod_dep dmods1 dmods2,
- imp_dep_pkgs = dpkgs1 `S.union` dpkgs2,
+ imp_direct_dep_mods = ddmods1 `plusModDeps` ddmods2,
+ imp_dep_direct_pkgs = ddpkgs1 `S.union` ddpkgs2,
imp_trust_pkgs = tpkgs1 `S.union` tpkgs2,
imp_trust_own_pkg = tself1 || tself2,
+ imp_boot_mods = srs1 `plusModDeps` srcs2,
+ imp_sig_mods = sig_mods1 `unionLists` sig_mods2,
imp_orphs = orphs1 `unionLists` orphs2,
imp_finsts = finsts1 `unionLists` finsts2 }
- where
- plus_mod_dep r1@(GWIB { gwib_mod = m1, gwib_isBoot = boot1 })
- r2@(GWIB {gwib_mod = m2, gwib_isBoot = boot2})
- | assertPpr (m1 == m2) ((ppr m1 <+> ppr m2) $$ (ppr (boot1 == IsBoot) <+> ppr (boot2 == IsBoot))) $
- boot1 == IsBoot = r2
- | otherwise = r1
- -- If either side can "see" a non-hi-boot interface, use that
- -- Reusing existing tuples saves 10% of allocations on test
- -- perf/compiler/MultiLayerModules
{-
************************************************************************
diff --git a/compiler/GHC/Types/Unique/FM.hs b/compiler/GHC/Types/Unique/FM.hs
index 102025bda2..35a8a2b3fc 100644
--- a/compiler/GHC/Types/Unique/FM.hs
+++ b/compiler/GHC/Types/Unique/FM.hs
@@ -54,6 +54,7 @@ module GHC.Types.Unique.FM (
plusUFM_C,
plusUFM_CD,
plusUFM_CD2,
+ mergeUFM,
plusMaybeUFM_C,
plusUFMList,
minusUFM,
@@ -88,6 +89,7 @@ import qualified Data.IntSet as S
import Data.Data
import qualified Data.Semigroup as Semi
import Data.Functor.Classes (Eq1 (..))
+import Data.Coerce
-- | A finite map from @uniques@ of one type to
-- elements in another type.
@@ -273,6 +275,20 @@ plusUFM_CD2 f (UFM xm) (UFM ym)
(MS.map (\y -> Nothing `f` Just y))
xm ym
+mergeUFM
+ :: (elta -> eltb -> Maybe eltc)
+ -> (UniqFM key elta -> UniqFM key eltc) -- map X
+ -> (UniqFM key eltb -> UniqFM key eltc) -- map Y
+ -> UniqFM key elta
+ -> UniqFM key eltb
+ -> UniqFM key eltc
+mergeUFM f g h (UFM xm) (UFM ym)
+ = UFM $ MS.mergeWithKey
+ (\_ x y -> (x `f` y))
+ (coerce g)
+ (coerce h)
+ xm ym
+
plusMaybeUFM_C :: (elt -> elt -> Maybe elt)
-> UniqFM key elt -> UniqFM key elt -> UniqFM key elt
plusMaybeUFM_C f (UFM xm) (UFM ym)
diff --git a/compiler/GHC/Unit/Module/Deps.hs b/compiler/GHC/Unit/Module/Deps.hs
index 5bdd23239b..2de3fe710d 100644
--- a/compiler/GHC/Unit/Module/Deps.hs
+++ b/compiler/GHC/Unit/Module/Deps.hs
@@ -17,25 +17,41 @@ import GHC.Utils.Fingerprint
import GHC.Utils.Binary
-- | Dependency information about ALL modules and packages below this one
--- in the import hierarchy.
+-- in the import hierarchy. This is the serialisable version of `ImportAvails`.
--
-- Invariant: the dependencies of a module @M@ never includes @M@.
--
-- Invariant: none of the lists contain duplicates.
+--
+-- See Note [Transitive Information in Dependencies]
data Dependencies = Deps
- { dep_mods :: [ModuleNameWithIsBoot]
- -- ^ All home-package modules transitively below this one
- -- I.e. modules that this one imports, or that are in the
- -- dep_mods of those directly-imported modules
-
- , dep_pkgs :: [(UnitId, Bool)]
- -- ^ All packages transitively below this module
- -- I.e. packages to which this module's direct imports belong,
- -- or that are in the dep_pkgs of those modules
- -- The bool indicates if the package is required to be
- -- trusted when the module is imported as a safe import
+ { dep_direct_mods :: [ModuleNameWithIsBoot]
+ -- ^ All home-package modules which are directly imported by this one.
+
+ , dep_direct_pkgs :: [UnitId]
+ -- ^ All packages directly imported by this module
+ -- I.e. packages to which this module's direct imports belong.
+ --
+ , dep_plgins :: [ModuleName]
+ -- ^ All the plugins used while compiling this module.
+
+
+ -- Transitive information below here
+ , dep_sig_mods :: ![ModuleName]
+ -- ^ Transitive closure of hsig files in the home package
+
+
+ , dep_trusted_pkgs :: [UnitId]
+ -- Packages which we are required to trust
+ -- when the module is imported as a safe import
-- (Safe Haskell). See Note [Tracking Trust Transitively] in GHC.Rename.Names
+ , dep_boot_mods :: [ModuleNameWithIsBoot]
+ -- ^ All modules which have boot files below this one, and whether we
+ -- should use the boot file or not.
+ -- This information is only used to populate the eps_is_boot field.
+ -- See Note [Structure of dep_boot_mods]
+
, dep_orphs :: [Module]
-- ^ Transitive closure of orphan modules (whether
-- home or external pkg).
@@ -53,30 +69,39 @@ data Dependencies = Deps
-- does NOT include us, unlike 'imp_finsts'. See Note
-- [The type family instance consistency story].
- , dep_plgins :: [ModuleName]
- -- ^ All the plugins used while compiling this module.
}
deriving( Eq )
-- Equality used only for old/new comparison in GHC.Iface.Recomp.addFingerprints
-- See 'GHC.Tc.Utils.ImportAvails' for details on dependencies.
instance Binary Dependencies where
- put_ bh deps = do put_ bh (dep_mods deps)
- put_ bh (dep_pkgs deps)
+ put_ bh deps = do put_ bh (dep_direct_mods deps)
+ put_ bh (dep_direct_pkgs deps)
+ put_ bh (dep_trusted_pkgs deps)
+ put_ bh (dep_sig_mods deps)
+ put_ bh (dep_boot_mods deps)
put_ bh (dep_orphs deps)
put_ bh (dep_finsts deps)
put_ bh (dep_plgins deps)
- get bh = do ms <- get bh
- ps <- get bh
+ get bh = do dms <- get bh
+ dps <- get bh
+ tps <- get bh
+ hsigms <- get bh
+ sms <- get bh
os <- get bh
fis <- get bh
pl <- get bh
- return (Deps { dep_mods = ms, dep_pkgs = ps, dep_orphs = os,
+ return (Deps { dep_direct_mods = dms
+ , dep_direct_pkgs = dps
+ , dep_sig_mods = hsigms
+ , dep_boot_mods = sms
+ , dep_trusted_pkgs = tps
+ , dep_orphs = os,
dep_finsts = fis, dep_plgins = pl })
noDependencies :: Dependencies
-noDependencies = Deps [] [] [] [] []
+noDependencies = Deps [] [] [] [] [] [] [] []
-- | Records modules for which changes may force recompilation of this module
-- See wiki: https://gitlab.haskell.org/ghc/ghc/wikis/commentary/compiler/recompilation-avoidance
@@ -193,3 +218,75 @@ instance Binary Usage where
hash <- get bh
return UsageMergedRequirement { usg_mod = mod, usg_mod_hash = hash }
i -> error ("Binary.get(Usage): " ++ show i)
+
+
+{-
+Note [Transitive Information in Dependencies]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is important to be careful what information we put in 'Dependencies' because
+ultimately it ends up serialised in an interface file. Interface files must always
+be kept up-to-date with the state of the world, so if `Dependencies` needs to be updated
+then the module had to be recompiled just to update `Dependencies`.
+
+Before #16885, the dependencies used to contain the transitive closure of all
+home modules. Therefore, if you added an import somewhere low down in the home package
+it would recompile nearly every module in your project, just to update this information.
+
+Now, we are a bit more careful about what we store and
+explicitly store transitive information only if it is really needed.
+
+# Direct Information
+
+* dep_direct_mods - Directly imported home package modules
+* dep_direct_pkgs - Directly imported packages
+* dep_plgins - Directly used plugins
+
+# Transitive Information
+
+Some features of the compiler require transitive information about what is currently
+being compiled, so that is explicitly stored separately in the form they need.
+
+* dep_trusted_pkgs - Only used for the -fpackage-trust feature
+* dep_boot_mods - Only used to populate eps_is_boot in -c mode
+* dep_orphs - Modules with orphan instances
+* dep_finsts - Modules with type family instances
+
+Important note: If you add some transitive information to the interface file then
+you need to make sure recompilation is triggered when it could be out of date.
+The correct way to do this is to include the transitive information in the export
+hash of the module. The export hash is computed in `GHC.Iface.Recomp.addFingerprints`.
+-}
+
+{-
+Note [Structure of mod_boot_deps]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In `-c` mode we always need to know whether to load the normal or boot version of
+an interface file, and this can't be determined from just looking at the direct imports.
+
+Consider modules with dependencies:
+
+```
+A -(S)-> B
+A -> C -> B -(S)-> B
+```
+
+Say when compiling module `A` that we need to load the interface for `B`, do we load
+`B.hi` or `B.hi-boot`? Well, `A` does directly {-# SOURCE #-} import B, so you might think
+that we would load the `B.hi-boot` file, however this is wrong because `C` imports
+`B` normally. Therefore in the interface file for `C` we still need to record that
+there is a hs-boot file for `B` below it but that we now want `B.hi` rather than
+`B.hi-boot`. When `C` is imported, the fact that it needs `B.hi` clobbers the `{- SOURCE -}`
+import for `B`.
+
+Therefore in mod_boot_deps we store the names of any modules which have hs-boot files,
+and whether we want to import the .hi or .hi-boot version of the interface file.
+
+If you get this wrong, then GHC fails to compile, so there is a test but you might
+not make it that far if you get this wrong!
+
+Question: does this happen even across packages?
+No: if I need to load the interface for module X from package P I always look for p:X.hi.
+
+-}
diff --git a/compiler/GHC/Unit/Module/ModIface.hs b/compiler/GHC/Unit/Module/ModIface.hs
index b7e0235730..18101e309b 100644
--- a/compiler/GHC/Unit/Module/ModIface.hs
+++ b/compiler/GHC/Unit/Module/ModIface.hs
@@ -282,7 +282,7 @@ mi_free_holes iface =
-> renameFreeHoles (mkUniqDSet cands) (instUnitInsts (moduleUnit indef))
_ -> emptyUniqDSet
where
- cands = map gwib_mod $ dep_mods $ mi_deps iface
+ cands = dep_sig_mods $ mi_deps iface
-- | Given a set of free holes, and a unit identifier, rename
-- the free holes according to the instantiation of the unit