diff options
Diffstat (limited to 'compiler/GHC')
-rw-r--r-- | compiler/GHC/Core/Opt/Pipeline.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Core/Opt/Specialise.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Driver/Env.hs | 55 | ||||
-rw-r--r-- | compiler/GHC/Driver/Main.hs | 3 | ||||
-rw-r--r-- | compiler/GHC/Driver/Pipeline.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/HsToCore/Usage.hs | 33 | ||||
-rw-r--r-- | compiler/GHC/Iface/Load.hs | 19 | ||||
-rw-r--r-- | compiler/GHC/Iface/Recomp.hs | 119 | ||||
-rw-r--r-- | compiler/GHC/Iface/Tidy.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Linker/Loader.hs | 10 | ||||
-rw-r--r-- | compiler/GHC/Rename/Module.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Rename/Names.hs | 83 | ||||
-rw-r--r-- | compiler/GHC/Tc/Module.hs | 20 | ||||
-rw-r--r-- | compiler/GHC/Tc/Types.hs | 90 | ||||
-rw-r--r-- | compiler/GHC/Types/Unique/FM.hs | 16 | ||||
-rw-r--r-- | compiler/GHC/Unit/Module/Deps.hs | 137 | ||||
-rw-r--r-- | compiler/GHC/Unit/Module/ModIface.hs | 2 |
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 |