{-# LANGUAGE CPP #-}{-# LANGUAGE TupleSections #-}{-# LANGUAGE ViewPatterns #-}moduleDsUsage(-- * Dependency/fingerprinting code (used by MkIface)mkUsageInfo ,mkUsedNames ,mkDependencies )where#include "HsVersions.h"
importGhcPrelude importDynFlags importHscTypes importTcRnTypes importName importNameSet importModule importOutputable importUtil importUniqSet importUniqFM importFingerprint importMaybes importPackages importFinder importControl.Monad(filterM)importData.ListimportData.IORefimportData.Map(Map)importqualifiedData.MapasMapimportqualifiedData.SetasSetimportSystem.DirectoryimportSystem.FilePath{- Note [Module self-dependency]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RnNames.calculateAvails asserts the invariant that a module must not occur in
its own dep_orphs or dep_finsts. However, if we aren't careful this can occur
in the presence of hs-boot files: Consider that we have two modules, A and B,
both with hs-boot files,
 A.hs contains a SOURCE import of B B.hs-boot contains a SOURCE import of A
 A.hs-boot declares an orphan instance A.hs defines the orphan instance
In this case, B's dep_orphs will contain A due to its SOURCE import of A.
Consequently, A will contain itself in its imp_orphs due to its import of B.
This fact would end up being recorded in A's interface file. This would then
break the invariant asserted by calculateAvails that a module does not itself in
its dep_orphs. This was the cause of Trac #14128.
-}-- | Extract information from the rename and typecheck phases to produce-- a dependencies information for the module being compiled.---- The first argument is additional dependencies from pluginsmkDependencies::InstalledUnitId ->[Module ]->TcGblEnv ->IODependencies mkDependencies iuid pluginModules (TcGblEnv {tcg_mod=mod ,tcg_imports=imports ,tcg_th_used=th_var })=do-- Template Haskell used?let(dep_plgins ,ms )=unzip[(moduleNamemn ,mn )|mn <-pluginModules ]plugin_dep_pkgs =filter(/=iuid )(map(toInstalledUnitId .moduleUnitId)ms )th_used <-readIORefth_var letdep_mods =modDepsElts (delFromUFM (imp_dep_modsimports )(moduleNamemod ))-- 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-- loadHiBootInterface can see if M's direct imports depend-- on M.hi-boot, and hence that we should do the hi-boot consistency-- check.)dep_orphs =filter(/=mod )(imp_orphsimports )-- We must also remove self-references from imp_orphs. See-- Note [Module self-dependency]raw_pkgs =foldrSet.insert(imp_dep_pkgsimports )plugin_dep_pkgs pkgs |th_used =Set.insert(toInstalledUnitId thUnitId )raw_pkgs |otherwise=raw_pkgs -- Set the packages required to be Safe according to Safe Haskell.-- See Note [RnNames . Tracking Trust Transitively]sorted_pkgs =sort(Set.toListpkgs )trust_pkgs =imp_trust_pkgsimports dep_pkgs' =map(\x ->(x ,x `Set.member`trust_pkgs ))sorted_pkgs returnDeps {dep_mods=dep_mods ,dep_pkgs=dep_pkgs' ,dep_orphs=dep_orphs ,dep_plgins=dep_plgins ,dep_finsts=sortBystableModuleCmp (imp_finstsimports )}-- sort to get into canonical order-- NB. remember to use lexicographic orderingmkUsedNames::TcGblEnv ->NameSet mkUsedNames TcGblEnv {tcg_dus=dus }=allUses dus mkUsageInfo::HscEnv ->Module ->ImportedMods ->NameSet ->[FilePath]->[(Module ,Fingerprint)]->[ModIface ]->IO[Usage ]mkUsageInfo hsc_env this_mod dir_imp_mods used_names dependent_files merged pluginModules =doeps <-hscEPS hsc_env hashes <-mapMgetFileHashdependent_files plugin_usages <-mapM(mkPluginUsage hsc_env )pluginModules letmod_usages =mk_mod_usage_info (eps_PITeps )hsc_env this_mod dir_imp_mods used_names usages =mod_usages ++[UsageFile {usg_file_path=f ,usg_file_hash=hash }|(f ,hash )<-zipdependent_files hashes ]++[UsageMergedRequirement {usg_mod=mod ,usg_mod_hash=hash }|(mod ,hash )<-merged ]++concatplugin_usages usages `seqList `returnusages -- seq the list of Usages returned: occasionally these-- don't get evaluated for a while and we can end up hanging on to-- the entire collection of Ifaces.{- Note [Plugin dependencies]
Modules for which plugins were used in the compilation process, should be
recompiled whenever one of those plugins changes. But how do we know if a
plugin changed from the previous time a module was compiled?
We could try storing the fingerprints of the interface files of plugins in
the interface file of the module. And see if there are changes between
compilation runs. However, this is pretty much a non-option because interface
fingerprints of plugin modules are fairly stable, unless you compile plugins
with optimisations turned on, and give basically all binders an INLINE pragma.
So instead:
 * For plugins that were built locally: we store the filepath and hash of the
 object files of the module with the `plugin` binder, and the object files of
 modules that are dependencies of the plugin module and belong to the same
 `UnitId` as the plugin
 * For plugins in an external package: we store the filepath and hash of
 the dynamic library containing the plugin module.
During recompilation we then compare the hashes of those files again to see
if anything has changed.
One issue with this approach is that object files are currently (GHC 8.6.1)
not created fully deterministicly, which could sometimes induce accidental
recompilation of a module for which plugins were used in the compile process.
One way to improve this is to either:
 * Have deterministic object file creation
 * Create and store implementation hashes, which would be based on the Core
 of the module and the implementation hashes of its dependencies, and then
 compare implementation hashes for recompilation. Creation of implementation
 hashes is however potentially expensive.
-}mkPluginUsage::HscEnv ->ModIface ->IO[Usage ]mkPluginUsage hsc_env pluginModule =caselookupPluginModuleWithSuggestions dflags pNm NothingofLookupFound _pkg ->do-- The plugin is from an external package:-- search for the library files containing the plugin.letsearchPaths =collectLibraryPaths dflags [pkg ]useDyn =WayDyn `elem`waysdflags suffix =ifuseDyn thensoExt platform else"a"libLocs =[searchPath </>"lib"++libLoc <.>suffix |searchPath <-searchPaths ,libLoc <-packageHsLibs dflags pkg ]-- we also try to find plugin library files by adding WayDyn way,-- if it isn't already present (see trac #15492)paths =ifuseDyn thenlibLocs elseletdflags' =updateWays (addWay' WayDyn dflags )dlibLocs =[searchPath </>mkHsSOName platform dlibLoc |searchPath <-searchPaths ,dlibLoc <-packageHsLibs dflags' pkg ]inlibLocs ++dlibLocs files <-filterMdoesFileExistpaths casefiles of[]->pprPanic ("mkPluginUsage: missing plugin library, tried:\n"++unlinespaths )(ppr pNm )_->mapMhashFile (nubfiles )_->dofoundM <-findPluginModule hsc_env pNm casefoundM of-- The plugin was built locally: look up the object file containing-- the `plugin` binder, and all object files belong to modules that are-- transitive dependencies of the plugin that belong to the same package.Found ml _->dopluginObject <-hashFile (ml_obj_fileml )depObjects <-catMaybes<$>mapMlookupObjectFile deps return(nub(pluginObject :depObjects ))_->pprPanic "mkPluginUsage: no object file found"(ppr pNm )wheredflags =hsc_dflagshsc_env platform =targetPlatform dflags pNm =moduleName(mi_modulepluginModule )pPkg =moduleUnitId(mi_modulepluginModule )deps =mapfst(dep_mods(mi_depspluginModule ))-- Lookup object file for a plugin dependency,-- from the same package as the plugin.lookupObjectFile nm =dofoundM <-findImportedModule hsc_env nm NothingcasefoundM ofFound ml m |moduleUnitIdm ==pPkg ->Just<$>hashFile (ml_obj_fileml )|otherwise->returnNothing_->pprPanic "mkPluginUsage: no object for dependency"(ppr pNm <+> ppr nm )hashFile f =dofExist <-doesFileExistf iffExist thendoh <-getFileHashf return(UsageFile f h )elsepprPanic "mkPluginUsage: file not found"(ppr pNm <+> text f )mk_mod_usage_info::PackageIfaceTable ->HscEnv ->Module ->ImportedMods ->NameSet ->[Usage ]mk_mod_usage_info pit hsc_env this_mod direct_imports used_names =mapMaybemkUsage usage_mods wherehpt =hsc_HPThsc_env dflags =hsc_dflagshsc_env this_pkg =thisPackage dflags used_mods =moduleEnvKeys ent_map dir_imp_mods =moduleEnvKeys direct_imports all_mods =used_mods ++filter(`notElem`used_mods )dir_imp_mods usage_mods =sortBystableModuleCmp all_mods -- canonical order is imported, to avoid interface-file-- wobblage.-- ent_map groups together all the things imported and used-- from a particular moduleent_map::ModuleEnv [OccName ]ent_map =nonDetFoldUniqSet add_mv emptyModuleEnv used_names -- nonDetFoldUFM is OK here. If you follow the logic, we sort by OccName-- in ent_hashswhereadd_mv name mv_map |isWiredInName name =mv_map -- ignore wired-in names|otherwise=casenameModule_maybe name ofNothing->ASSERT2(isSystemNamename ,ppr name)mv_map-- See Note [Internal used_names]Justmod ->-- See Note [Identity versus semantic module]letmod' =ifisHoleModule mod thenmkModule this_pkg (moduleNamemod )elsemod -- This lambda function is really just a-- specialised (++); originally came about to-- avoid quadratic behaviour (trac #2680)inextendModuleEnvWith (\_xs ->occ :xs )mv_map mod' [occ ]whereocc =nameOccName name -- We want to create a Usage for a home module if-- a) we used something from it; has something in used_names-- b) we imported it, even if we used nothing from it-- (need to recompile if its export list changes: export_fprint)mkUsage::Module ->MaybeUsage mkUsage mod |isNothingmaybe_iface -- We can't depend on it if we didn't-- load its interface.||mod ==this_mod -- We don't care about usages of-- things in *this* module=Nothing|moduleUnitIdmod /=this_pkg =JustUsagePackageModule {usg_mod=mod ,usg_mod_hash=mod_hash ,usg_safe=imp_safe }-- for package modules, we record the module hash only|(nullused_occs &&isNothingexport_hash &&notis_direct_import &&notfinsts_mod )=Nothing-- Record no usage info-- for directly-imported modules, we always want to record a usage-- on the orphan hash. This is what triggers a recompilation if-- an orphan is added or removed somewhere below us in the future.|otherwise=JustUsageHomeModule {usg_mod_name=moduleNamemod ,usg_mod_hash=mod_hash ,usg_exports=export_hash ,usg_entities=Map.toListent_hashs ,usg_safe=imp_safe }wheremaybe_iface =lookupIfaceByModule dflags hpt pit mod -- In one-shot mode, the interfaces for home-package-- modules accumulate in the PIT not HPT. Sigh.Justiface =maybe_iface finsts_mod =mi_finstsiface hash_env =mi_hash_fniface mod_hash =mi_mod_hashiface export_hash |depend_on_exports =Just(mi_exp_hashiface )|otherwise=Nothingby_is_safe (ImportedByUser imv )=imv_is_safeimv by_is_safe_=False(is_direct_import ,imp_safe )=caselookupModuleEnv direct_imports mod of-- ezyang: I'm not sure if any is the correct-- metric here. If safety was guaranteed to be uniform-- across all imports, why did the old code only look-- at the first import?Justbys ->(True,anyby_is_safe bys )Nothing->(False,safeImplicitImpsReq dflags )-- Nothing case is for references to entities which were-- not directly imported (NB: the "implicit" Prelude import-- counts as directly imported! An entity is not directly-- imported if, e.g., we got a reference to it from a-- reexport of another module.)used_occs =lookupModuleEnv ent_map mod `orElse `[]-- Making a Map here ensures that (a) we remove duplicates-- when we have usages on several subordinates of a single parent,-- and (b) that the usages emerge in a canonical order, which-- is why we use Map rather than OccEnv: Map works-- using Ord on the OccNames, which is a lexicographic ordering.ent_hashs::MapOccName Fingerprintent_hashs =Map.fromList(maplookup_occ used_occs )lookup_occ occ =casehash_env occ ofNothing->pprPanic "mkUsage"(ppr mod <+> ppr occ <+> ppr used_names )Justr ->r depend_on_exports =is_direct_import {- True
 Even if we used 'import M ()', we have to register a
 usage on the export list because we are sensitive to
 changes in orphan instances/rules.
 False
 In GHC 6.8.x we always returned true, and in
 fact it recorded a dependency on *all* the
 modules underneath in the dependency tree. This
 happens to make orphans work right, but is too
 expensive: it'll read too many interface files.
 The 'isNothing maybe_iface' check above saved us
 from generating many of these usages (at least in
 one-shot mode), but that's even more bogus!
 -}

AltStyle によって変換されたページ (->オリジナル) /