Wolfgang Jeltsch pushed to branch wip/sort-usages at Glasgow Haskell Compiler / GHC Commits: f49f411f by Wolfgang Jeltsch at 2026-06-09T13:50:52+03:00 Switch to 'Usage' sorting by constructor and string IDs - - - - - 3 changed files: - compiler/GHC/HsToCore/Usage.hs - compiler/GHC/Unit/Module/Deps.hs - testsuite/tests/driver/recomp016/recomp016.stdout Changes: ===================================== compiler/GHC/HsToCore/Usage.hs ===================================== @@ -12,7 +12,6 @@ import GHC.Tc.Types import GHC.Iface.Load import GHC.Utils.Outputable -import GHC.Utils.Misc import GHC.Utils.Fingerprint import GHC.Utils.Panic import GHC.Utils.Monad @@ -33,7 +32,7 @@ import GHC.Data.Maybe import GHC.Data.FastString import Data.Containers.ListUtils (nubOrdOn) -import Data.List (sortBy, sortOn) +import Data.List (sortBy) import Data.Map (Map) import qualified Data.Map as Map import qualified Data.Set as Set @@ -70,8 +69,8 @@ data UsageConfig = UsageConfig { uc_safe_implicit_imps_req :: !Bool -- ^ Are all implicit imports required to be safe for this Safe Haskell mode? } --- | Build the list of 'Usage's that drives recompilation checking. --- The resulting list is deterministically sorted (see 'usageFingerprint'). +-- | Build the list of 'Usage's that drive recompilation checking. +-- The resulting list is deterministically sorted. mkUsageInfo :: UsageConfig -> Plugins -> FinderCache -> UnitEnv -> Module -> ImportedMods -> [ImportUserSpec] -> NameSet -> [FilePath] -> [FilePath] -> [(Module, Fingerprint)] -> [LinkableUsage] -> PkgsLoaded @@ -102,13 +101,14 @@ mkUsageInfo uc plugins fc unit_env } | (mod, hash) <- merged ] ++ object_usages - - -- Sort all the Usages to ensure a deterministic ordering. - let sorted_usages = sortOn usageFingerprint usages - sorted_usages `seqList` return sorted_usages - -- 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. + return (sortBy stableUsageCmp usages) + -- Note that the sorting serves two purposes: + -- * It makes the order of usages deterministic. + -- * It evaluates the spine of 'usages' and reduces all of its elements to + -- at least WHNF und thus has at least the effect of 'seqList'. + -- The latter is important because occasionally the returned list is not + -- evaluated for a while, so that with too much laziness here we could end + -- up hanging on to the entire collection of 'Iface's. {- Note [Plugin dependencies] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ===================================== compiler/GHC/Unit/Module/Deps.hs ===================================== @@ -1,5 +1,8 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE DerivingVia #-} + +{-# OPTIONS_GHC -Wwarn=incomplete-record-selectors #-} + -- | Dependencies and Usage of a module module GHC.Unit.Module.Deps ( Dependencies(dep_direct_mods @@ -17,7 +20,7 @@ module GHC.Unit.Module.Deps , noDependencies , pprDeps , Usage (..) - , usageFingerprint + , stableUsageCmp , HomeModImport (..) , HomeModImportedAvails (..) , ImportAvails (..) @@ -53,6 +56,7 @@ import GHC.Utils.Outputable import Control.DeepSeq import Data.Bifunctor import qualified Data.Foldable as Foldable +import Data.Function (on) import Data.List (sortBy, sort, partition) import Data.Set (Set) import qualified Data.Set as Set @@ -498,16 +502,46 @@ instance Binary Usage where i -> error ("Binary.get(Usage): " ++ show i) --- | Extract the distinguishing fingerprint carried by a particular 'Usage' --- constructor. Every constructor stores a hash capturing the bit of state --- that drives recompilation decisions, so we can sort on it directly. -usageFingerprint :: Usage -> Fingerprint -usageFingerprint UsagePackageModule{ usg_mod_hash = fp } = fp -usageFingerprint UsageHomeModule{ usg_mod_hash = fp } = fp -usageFingerprint UsageFile{ usg_file_hash = fp } = fp -usageFingerprint UsageDirectory{ usg_dir_hash = fp } = fp -usageFingerprint UsageHomeModuleBytecode{ usg_bytecode_hash = fp } = fp -usageFingerprint UsageMergedRequirement{ usg_mod_hash = fp } = fp +-- | Compares 'Usage's by constructor and, if the constructors are the same, by +-- identifying strings, to achieve a predictable ordering. +stableUsageCmp :: Usage -> Usage -> Ordering +stableUsageCmp + usage1@UsagePackageModule {} + usage2@UsagePackageModule {} + = (compare `on` usg_mod) usage1 usage2 +stableUsageCmp + usage1@UsageHomeModule {} + usage2@UsageHomeModule {} + = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2 +stableUsageCmp + usage1@UsageFile {} + usage2@UsageFile {} + = (lexicalCompareFS `on` usg_file_path) usage1 usage2 +stableUsageCmp + usage1@UsageDirectory {} + usage2@UsageDirectory {} + = (lexicalCompareFS `on` usg_dir_path) usage1 usage2 +stableUsageCmp + usage1@UsageHomeModuleBytecode {} + usage2@UsageHomeModuleBytecode {} + = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2 +stableUsageCmp + usage1@UsageMergedRequirement {} + usage2@UsageMergedRequirement {} + = (compare `on` usg_mod) usage1 usage2 +stableUsageCmp + usage1 + usage2 + = (compare `on` constructorIndex) usage1 usage2 + where + + constructorIndex :: Usage -> Int + constructorIndex UsagePackageModule {} = 0 + constructorIndex UsageHomeModule {} = 1 + constructorIndex UsageFile {} = 2 + constructorIndex UsageDirectory {} = 3 + constructorIndex UsageHomeModuleBytecode {} = 4 + constructorIndex UsageMergedRequirement {} = 5 -- | Records the imports that we depend on from a home module, -- for recompilation checking. ===================================== testsuite/tests/driver/recomp016/recomp016.stdout ===================================== @@ -9,4 +9,4 @@ second run [2 of 5] Compiling B ( B.hs, B.o ) [Source file changed] [3 of 5] Compiling C ( C.hs, C.o ) [B changed] [4 of 5] Compiling D ( D.hs, D.o ) [C changed] -[5 of 5] Compiling E ( E.hs, E.o ) [D changed] +[5 of 5] Compiling E ( E.hs, E.o ) [B changed] View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f49f411f5a429f2a2b725e5a025c9e03... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f49f411f5a429f2a2b725e5a025c9e03... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Wolfgang Jeltsch (@jeltsch)