Zubin pushed to branch wip/9.14.2-backports at Glasgow Haskell Compiler / GHC Commits: 2a285613 by Ian-Woo Kim at 2026-07-20T13:16:54+05:30 Make the order of usages deterministic It has been observed that the ordering of usages can be non-determinstic in parallel builds. Therefore, this contribution introduces sorting of usages based on a platform- and race-independent sorting criterion. Resolves #26877. Co-authored-by: Wolfgang Jeltsch <wolfgang@well-typed.com> (cherry picked from commit d216412babfd5b5746365f0686ec370fb0892ec7) - - - - - 0b75a0c4 by Wolfgang Jeltsch at 2026-07-20T13:16:54+05:30 Change the descriptions of two existing changelog entries The descriptions now describe the changes in a user-friendly manner, as opposed to describing the contributions that led to these changes in a developer-friendly manner. (cherry picked from commit 8e1cc105acae69b1fabd1a9b89e2d1823861f518) - - - - - 4955f0ca by Andrea Vezzosi at 2026-07-20T13:16:54+05:30 [Fix #27287] preserve ModBreaks in ModIface (cherry picked from commit 4396a6f2a4c7799908e1e0b88a218a51d063fdca) - - - - - 26 changed files: - + changelog.d/deterministic-usage-order - changelog.d/more-efficient-home-unit-imports-finding - compiler/GHC/ByteCode/Breakpoints.hs - compiler/GHC/ByteCode/Types.hs - compiler/GHC/Driver/Main.hs - compiler/GHC/HsToCore/Breakpoints.hs - + compiler/GHC/HsToCore/Breakpoints/Types.hs - compiler/GHC/HsToCore/Usage.hs - compiler/GHC/Iface/Load.hs - compiler/GHC/Iface/Make.hs - compiler/GHC/Iface/Recomp.hs - compiler/GHC/Linker/Types.hs - compiler/GHC/Runtime/Interpreter.hs - compiler/GHC/Unit/Module/Deps.hs - compiler/GHC/Unit/Module/ModGuts.hs - compiler/GHC/Unit/Module/ModIface.hs - compiler/GHC/Unit/Module/WholeCoreBindings.hs - compiler/GHC/Utils/Binary.hs - compiler/ghc.cabal.in - testsuite/tests/count-deps/CountDepsAst.stdout - testsuite/tests/count-deps/CountDepsParser.stdout - testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout - testsuite/tests/ghci/should_run/Makefile - + testsuite/tests/ghci/should_run/T27287.hs - + testsuite/tests/ghci/should_run/T27287.stdout - testsuite/tests/ghci/should_run/all.T Changes: ===================================== changelog.d/deterministic-usage-order ===================================== @@ -0,0 +1,8 @@ +section: compiler +synopsis: Make the order of usages deterministic +issues: #26877 +mrs: !15484 +description: { + The order in which usages appear in interface files is now + deterministic. +} ===================================== changelog.d/more-efficient-home-unit-imports-finding ===================================== @@ -3,13 +3,10 @@ synopsis: Introduce a cache of home module name providers issues: #27055 mrs: !15888 description: { - This contribution optimizes the algorithm for finding out which home - unit provides the module that a certain import declaration refers - to. The previous approach has been to simply search all home units - in no particular order. This change introduces a cache that allows - for efficiently determining those complete home units that provide a - certain module name and changes the module-finding algorithm such - that it searches these units before the other home units. This leads - to significant performance improvements in situations where there - are lots of home units. + For finding out which home unit provides the module that a certain + import declaration refers to, we now use a better algorithm. The + previous approach was to simply search all home units in no + particular order. The new algorithm first searches those complete + home units that provide a certain module name, before searching the + other home units. } ===================================== compiler/GHC/ByteCode/Breakpoints.hs ===================================== @@ -40,7 +40,7 @@ import Control.DeepSeq import Data.IntMap.Strict (IntMap) import qualified Data.IntMap.Strict as IM -import GHC.HsToCore.Breakpoints +import GHC.HsToCore.Breakpoints.Types import GHC.Iface.Syntax import GHC.Unit.Module (Module) ===================================== compiler/GHC/ByteCode/Types.hs ===================================== @@ -42,7 +42,7 @@ import GHC.Types.Name.Env import GHC.Utils.Outputable import GHC.Builtin.PrimOps import GHC.Types.SptEntry -import GHC.HsToCore.Breakpoints +import GHC.HsToCore.Breakpoints.Types import GHC.ByteCode.Breakpoints import GHCi.Message import GHCi.RemoteTypes @@ -305,4 +305,3 @@ instance Outputable UnlinkedBCO where = sep [text "BCO", ppr nm, text "with", ppr (sizeFlatBag lits), text "lits", ppr (sizeFlatBag ptrs), text "ptrs" ] - ===================================== compiler/GHC/Driver/Main.hs ===================================== @@ -693,7 +693,7 @@ hsc_typecheck keep_rn mod_summary mb_rdr_module = do Nothing -> hscParse' mod_summary tc_result0 <- tcRnModule' mod_summary keep_rn' hpm if hsc_src == HsigFile - then do (iface, _) <- liftIO $ hscSimpleIface hsc_env Nothing tc_result0 mod_summary + then do (iface, _) <- liftIO $ hscSimpleIface hsc_env Nothing Nothing tc_result0 mod_summary ioMsgMaybe $ hoistTcRnMessage $ tcRnMergeSignatures hsc_env hpm tc_result0 iface else return tc_result0 @@ -871,7 +871,7 @@ hscRecompStatus -- we will decide if we need them or not. bc_linkable <- checkByteCode checked_iface mod_summary (homeMod_bytecode old_linkable) obj_linkable <- liftIO $ checkObjects lcl_dflags (homeMod_object old_linkable) mod_summary - trace_if (hsc_logger hsc_env) (vcat [text "BCO linkable", nest 2 (ppr bc_linkable), text "Object Linkable", ppr obj_linkable]) + trace_if (hsc_logger hsc_env) (vcat [text "BCO linkable", nest 2 (ppr bc_linkable), text "Object Linkable", nest 2 (ppr obj_linkable)]) let just_bc = justBytecode <$> bc_linkable just_o = justObjects <$> obj_linkable @@ -1018,12 +1018,13 @@ compile_for_interpreter hsc_env use = -- | Assemble 'WholeCoreBindings' if the interface contains Core bindings. iface_core_bindings :: ModIface -> ModLocation -> Maybe WholeCoreBindings iface_core_bindings iface wcb_mod_location = - mi_simplified_core <&> \(IfaceSimplifiedCore bindings foreign') -> + mi_simplified_core <&> \(IfaceSimplifiedCore bindings wcb_modBreaks foreign') -> WholeCoreBindings { wcb_bindings = bindings, wcb_module = mi_module, wcb_mod_location, - wcb_foreign = foreign' + wcb_foreign = foreign', + wcb_modBreaks } where ModIface {mi_module, mi_simplified_core} = iface @@ -1161,11 +1162,11 @@ compileWholeCoreBindings hsc_env type_env wcb = do gen_bytecode core_binds stubs foreign_files = do let cgi_guts = CgInteractiveGuts wcb_module core_binds (typeEnvTyCons type_env) stubs foreign_files - Nothing [] + wcb_modBreaks [] trace_if logger (text "Generating ByteCode for" <+> ppr wcb_module) generateByteCode hsc_env cgi_guts wcb_mod_location - WholeCoreBindings {wcb_module, wcb_mod_location, wcb_foreign} = wcb + WholeCoreBindings {wcb_module, wcb_mod_location, wcb_foreign, wcb_modBreaks} = wcb logger = hsc_logger hsc_env @@ -1292,7 +1293,8 @@ hscDesugarAndSimplify summary (FrontendTypecheck tc_result) tc_warnings mb_old_h liftIO $ hscTidy hsc_env simplified_guts (iface, _details) <- liftIO $ - hscSimpleIface hsc_env (Just $ cg_binds cg_guts) tc_result summary + hscSimpleIface hsc_env (Just $ cg_binds cg_guts) + (cg_modBreaks cg_guts) tc_result summary liftIO $ hscMaybeWriteIface logger dflags True iface mb_old_hash (ms_location summary) @@ -1307,7 +1309,7 @@ hscDesugarAndSimplify summary (FrontendTypecheck tc_result) tc_warnings mb_old_h -- and generate a simple interface. _ -> do (iface, _details) <- liftIO $ - hscSimpleIface hsc_env Nothing tc_result summary + hscSimpleIface hsc_env Nothing Nothing tc_result summary liftIO $ hscMaybeWriteIface logger dflags True iface mb_old_hash (ms_location summary) @@ -1886,17 +1888,19 @@ hscSimplify' plugins ds_result = do -- generates interface files. See Note [simpleTidyPgm - mkBootModDetailsTc] hscSimpleIface :: HscEnv -> Maybe CoreProgram + -> Maybe ModBreaks -> TcGblEnv -> ModSummary -> IO (ModIface, ModDetails) -hscSimpleIface hsc_env mb_core_program tc_result summary - = runHsc hsc_env $ hscSimpleIface' mb_core_program tc_result summary +hscSimpleIface hsc_env mb_core_program mb_modBreaks tc_result summary + = runHsc hsc_env $ hscSimpleIface' mb_core_program mb_modBreaks tc_result summary hscSimpleIface' :: Maybe CoreProgram + -> Maybe ModBreaks -> TcGblEnv -> ModSummary -> Hsc (ModIface, ModDetails) -hscSimpleIface' mb_core_program tc_result summary = do +hscSimpleIface' mb_core_program mb_modBreaks tc_result summary = do hsc_env <- getHscEnv logger <- getLogger details <- liftIO $ mkBootModDetailsTc logger tc_result @@ -1904,7 +1908,7 @@ hscSimpleIface' mb_core_program tc_result summary = do new_iface <- {-# SCC "MkFinalIface" #-} liftIO $ - mkIfaceTc hsc_env safe_mode details summary mb_core_program tc_result + mkIfaceTc hsc_env safe_mode details summary mb_core_program mb_modBreaks tc_result -- And the answer is ... liftIO $ dumpIfaceStats hsc_env return (new_iface, details) ===================================== compiler/GHC/HsToCore/Breakpoints.hs ===================================== @@ -15,7 +15,7 @@ -- See Note [ModBreaks vs InternalModBreaks] and Note [Breakpoint identifiers] module GHC.HsToCore.Breakpoints ( -- * ModBreaks - mkModBreaks, ModBreaks(..) + mkModBreaks, ModBreaks(..), modBreaks_locs -- ** Re-exports BreakpointId , BreakpointId(..), BreakTickIndex @@ -25,46 +25,12 @@ import GHC.Prelude import Data.Array import GHC.HsToCore.Ticks (Tick (..)) +import GHC.HsToCore.Breakpoints.Types import GHC.Data.SizedSeq -import GHC.Types.SrcLoc (SrcSpan) -import GHC.Types.Name (OccName) -import GHC.Types.Tickish (BreakTickIndex, BreakpointId(..)) import GHC.Unit.Module (Module) import GHC.Utils.Outputable import Data.List (intersperse) - --------------------------------------------------------------------------------- --- ModBreaks --------------------------------------------------------------------------------- - --- | All the information about the source-relevant breakpoints for a module --- --- This information is constructed once during desugaring (with `mkModBreaks`) --- from breakpoint ticks and fixed/unchanged from there on forward. It could be --- exported as an abstract datatype because it should never be updated after --- construction, only queried. --- --- The arrays can be indexed using the int in the corresponding 'BreakpointId' --- (i.e. the 'BreakpointId' whose 'Module' matches the 'Module' corresponding --- to these 'ModBreaks') with the accessors 'modBreaks_locs', 'modBreaks_vars', --- and 'modBreaks_decls'. -data ModBreaks - = ModBreaks - { modBreaks_locs :: !(Array BreakTickIndex SrcSpan) - -- ^ An array giving the source span of each breakpoint. - , modBreaks_vars :: !(Array BreakTickIndex [OccName]) - -- ^ An array giving the names of the free variables at each breakpoint. - , modBreaks_decls :: !(Array BreakTickIndex [String]) - -- ^ An array giving the names of the declarations enclosing each breakpoint. - -- See Note [Field modBreaks_decls] - , modBreaks_ccs :: !(Array BreakTickIndex (String, String)) - -- ^ Array pointing to cost centre info for each breakpoint; - -- actual 'CostCentre' allocation is done at link-time. - , modBreaks_module :: !Module - -- ^ The module to which this ModBreaks is associated. - -- We also cache this here for internal sanity checks. - } - +import GHC.Utils.Binary (BinSrcSpan(BinSrcSpan)) -- | Initialize memory for breakpoint data that is shared between the bytecode -- generator and the interpreter. -- @@ -91,7 +57,7 @@ mkModBreaks interpreterProfiled modl extendedMixEntries ] | otherwise = listArray (0, -1) [] in ModBreaks - { modBreaks_locs = locsTicks + { modBreaks_locs_ = fmap BinSrcSpan locsTicks , modBreaks_vars = varsTicks , modBreaks_decls = declsTicks , modBreaks_ccs = ccs ===================================== compiler/GHC/HsToCore/Breakpoints/Types.hs ===================================== @@ -0,0 +1,81 @@ +{-# LANGUAGE RecordWildCards #-} + +-- | Information attached to Breakpoints generated from Ticks +-- +-- The breakpoint information stored in 'ModBreaks' is generated during +-- desugaring from the ticks annotating the source expressions. +-- +-- This information can be queried per-breakpoint using the 'BreakpointId' +-- datatype, which indexes tick-level breakpoint information. +-- +-- 'ModBreaks' and 'BreakpointId's are not to be confused with +-- 'InternalModBreaks' and 'InternalBreakId's. The latter are constructed +-- during bytecode generation and can be found in 'GHC.ByteCode.Breakpoints'. +-- +-- See Note [ModBreaks vs InternalModBreaks] and Note [Breakpoint identifiers] +module GHC.HsToCore.Breakpoints.Types + ( -- * ModBreaks + ModBreaks(..), modBreaks_locs + + -- ** Re-exports BreakpointId + , BreakpointId(..), BreakTickIndex + ) where + +import GHC.Prelude +import Data.Array + +import GHC.Types.SrcLoc (SrcSpan) +import GHC.Types.Name (OccName) +import GHC.Types.Tickish (BreakTickIndex, BreakpointId(..)) +import GHC.Unit.Module (Module) +import Data.Coerce +import GHC.Utils.Binary (BinSrcSpan(..), Binary(..)) +import Control.DeepSeq + +-------------------------------------------------------------------------------- +-- ModBreaks +-------------------------------------------------------------------------------- + +-- | All the information about the source-relevant breakpoints for a module +-- +-- This information is constructed once during desugaring (with `mkModBreaks`) +-- from breakpoint ticks and fixed/unchanged from there on forward. It could be +-- exported as an abstract datatype because it should never be updated after +-- construction, only queried. +-- +-- The arrays can be indexed using the int in the corresponding 'BreakpointId' +-- (i.e. the 'BreakpointId' whose 'Module' matches the 'Module' corresponding +-- to these 'ModBreaks') with the accessors 'modBreaks_locs', 'modBreaks_vars', +-- and 'modBreaks_decls'. +data ModBreaks + = ModBreaks + { modBreaks_locs_ :: !(Array BreakTickIndex BinSrcSpan) + -- ^ An array giving the source span of each breakpoint. + , modBreaks_vars :: !(Array BreakTickIndex [OccName]) + -- ^ An array giving the names of the free variables at each breakpoint. + , modBreaks_decls :: !(Array BreakTickIndex [String]) + -- ^ An array giving the names of the declarations enclosing each breakpoint. + -- See Note [Field modBreaks_decls] + , modBreaks_ccs :: !(Array BreakTickIndex (String, String)) + -- ^ Array pointing to cost centre info for each breakpoint; + -- actual 'CostCentre' allocation is done at link-time. + , modBreaks_module :: !Module + -- ^ The module to which this ModBreaks is associated. + -- We also cache this here for internal sanity checks. + } + +modBreaks_locs :: ModBreaks -> Array BreakTickIndex SrcSpan +modBreaks_locs = coerce . modBreaks_locs_ + +instance Binary ModBreaks where + get bh = ModBreaks <$> get bh <*> get bh <*> get bh <*> get bh <*> get bh + + put_ bh ModBreaks {..} = + put_ bh modBreaks_locs_ + *> put_ bh modBreaks_vars + *> put_ bh modBreaks_decls + *> put_ bh modBreaks_ccs + *> put_ bh modBreaks_module + +instance NFData ModBreaks where + rnf (ModBreaks a b c d e) = rnf a `seq` rnf b `seq` rnf c `seq` rnf d `seq` rnf e \ No newline at end of file ===================================== compiler/GHC/HsToCore/Usage.hs ===================================== @@ -73,6 +73,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 drive recompilation checking. +-- The resulting list is deterministically sorted. mkUsageInfo :: UsageConfig -> Plugins -> FinderCache -> UnitEnv -> Module -> ImportedMods -> [ImportUserSpec] -> NameSet -> [FilePath] -> [(Module, Fingerprint)] -> [Linkable] -> PkgsLoaded @@ -100,10 +102,10 @@ mkUsageInfo uc plugins fc unit_env } | (mod, hash) <- merged ] ++ object_usages - usages `seqList` return 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. + usages `seqList` return (sortBy stableUsageCmp usages) + -- The use of 'seqList' 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/Iface/Load.hs ===================================== @@ -62,6 +62,8 @@ import GHC.Iface.Rename import GHC.Iface.Env import GHC.Iface.Errors as Iface_Errors +import GHC.HsToCore.Breakpoints.Types (modBreaks_locs) + import GHC.Tc.Errors.Types import GHC.Tc.Utils.Monad @@ -112,6 +114,7 @@ import GHC.Unit.Env import GHC.Data.Maybe import Control.Monad +import qualified Data.Foldable as Foldable import Data.Map ( toList ) import System.FilePath import System.Directory @@ -1159,9 +1162,11 @@ pprModIface unit_state iface , vcat [ppr ver $$ nest 2 (ppr decl) | (ver,decl) <- mi_decls iface] , case mi_simplified_core iface of Nothing -> empty - Just (IfaceSimplifiedCore eds fs) -> + Just (IfaceSimplifiedCore eds mbs fs) -> vcat [ text "extra decls:" $$ nest 2 (vcat ([ppr bs | bs <- eds])) + , text "mod breaks:" + $$ nest 2 (ppr $ Foldable.toList . modBreaks_locs <$> mbs) , text "foreign stubs:" $$ nest 2 (ppr fs) ] ===================================== compiler/GHC/Iface/Make.hs ===================================== @@ -34,6 +34,7 @@ import GHC.Iface.Syntax import GHC.Iface.Recomp import GHC.Iface.Load import GHC.Iface.Ext.Fields +import GHC.HsToCore.Breakpoints.Types (ModBreaks) import GHC.CoreToIface @@ -122,11 +123,12 @@ mkPartialIface hsc_env core_prog mod_details mod_summary import_decls , mg_safe_haskell = safe_mode , mg_trust_pkg = self_trust , mg_docs = docs + , mg_modBreaks = modBreaks } = do self_recomp <- traverse (mkSelfRecomp hsc_env this_mod (ms_hs_hash mod_summary)) usages return $ mkIface_ hsc_env this_mod core_prog hsc_src deps rdr_env import_decls fix_env warns self_trust - safe_mode self_recomp docs mod_details + safe_mode self_recomp docs mod_details modBreaks -- | Fully instantiate an interface. Adds fingerprints and potentially code -- generator produced information. @@ -228,9 +230,10 @@ mkIfaceTc :: HscEnv -> ModDetails -- gotten from mkBootModDetails, probably -> ModSummary -> Maybe CoreProgram + -> Maybe ModBreaks -> TcGblEnv -- Usages, deprecations, etc -> IO ModIface -mkIfaceTc hsc_env safe_mode mod_details mod_summary mb_program +mkIfaceTc hsc_env safe_mode mod_details mod_summary mb_program mb_modBreaks tc_result@TcGblEnv{ tcg_mod = this_mod, tcg_src = hsc_src, tcg_imports = imports, @@ -258,6 +261,7 @@ mkIfaceTc hsc_env safe_mode mod_details mod_summary mb_program (imp_trust_own_pkg imports) safe_mode self_recomp docs mod_details + mb_modBreaks mkFullIface hsc_env partial_iface Nothing Nothing NoStubs [] @@ -302,6 +306,7 @@ mkIface_ :: HscEnv -> Module -> CoreProgram -> HscSource -> Maybe IfaceSelfRecomp -> Maybe Docs -> ModDetails + -> Maybe ModBreaks -> PartialModIface mkIface_ hsc_env this_mod core_prog hsc_src deps rdr_env import_decls fix_env src_warns @@ -319,15 +324,17 @@ mkIface_ hsc_env -- only at the TypeEnv. The previous Tidy phase has -- put exactly the info into the TypeEnv that we want -- to expose in the interface - + modBreaks = do let home_unit = hsc_home_unit hsc_env semantic_mod = homeModuleNameInstantiation home_unit (moduleName this_mod) entities = typeEnvElts type_env show_linear_types = xopt LangExt.LinearTypes (hsc_dflags hsc_env) - simplified_core = if gopt Opt_WriteIfSimplifiedCore dflags then Just (IfaceSimplifiedCore [ toIfaceTopBind b | b <- core_prog ] emptyIfaceForeign) - else Nothing + simplified_core = + if gopt Opt_WriteIfSimplifiedCore dflags + then Just (IfaceSimplifiedCore [ toIfaceTopBind b | b <- core_prog ] modBreaks emptyIfaceForeign) + else Nothing decls = [ tyThingToIfaceDecl show_linear_types entity | entity <- entities, let name = getName entity, ===================================== compiler/GHC/Iface/Recomp.hs ===================================== @@ -1208,7 +1208,7 @@ addFingerprints hsc_env iface0 = do sorted_extra_decls :: Maybe IfaceSimplifiedCore sorted_extra_decls = mi_simplified_core iface0 <&> \simpl_core -> - IfaceSimplifiedCore (sortOn binding_key (mi_sc_extra_decls simpl_core)) (mi_sc_foreign simpl_core) + IfaceSimplifiedCore (sortOn binding_key (mi_sc_extra_decls simpl_core)) (mi_sc_modBreaks simpl_core) (mi_sc_foreign simpl_core) -- The interface hash depends on: -- - the ABI hash, plus ===================================== compiler/GHC/Linker/Types.hs ===================================== @@ -47,6 +47,7 @@ module GHC.Linker.Types , linkableFilterByteCode , linkableFilterNative , partitionLinkables + , linkableAllBCOs ) where @@ -352,6 +353,17 @@ linkableIsNativeCodeOnly l = all isNativeCode (NE.toList (linkableParts l)) linkableBCOs :: Linkable -> [CompiledByteCode] linkableBCOs l = [ cbc | BCOs cbc <- NE.toList (linkableParts l) ] +linkableAllBCOs :: Linkable -> [CompiledByteCode] +linkableAllBCOs l = mapMaybe bcos $ NE.toList (linkableParts l) + where + -- Note: explicit match on all constructors to trigger warning when new ones are introduced. + bcos (BCOs bco) = Just bco + bcos (LazyBCOs bco _fs) = Just bco -- TODO: _fs ? + bcos DotA{} = Nothing + bcos DotDLL{} = Nothing + bcos CoreBindings{} = Nothing + bcos DotO{} = Nothing + -- | List the native linkable parts (.o/.so/.dll) of a linkable linkableNativeParts :: Linkable -> [LinkablePart] linkableNativeParts l = NE.filter isNativeCode (linkableParts l) ===================================== compiler/GHC/Runtime/Interpreter.hs ===================================== @@ -737,7 +737,7 @@ getModBreaks :: HomeModInfo -> Maybe InternalModBreaks getModBreaks hmi | Just linkable <- homeModInfoByteCode hmi, -- The linkable may have 'DotO's as well; only consider BCOs. See #20570. - [cbc] <- linkableBCOs linkable + [cbc] <- linkableAllBCOs linkable = bc_breaks cbc | otherwise = Nothing -- probably object code ===================================== compiler/GHC/Unit/Module/Deps.hs ===================================== @@ -2,6 +2,9 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ExplicitNamespaces #-} {-# LANGUAGE DerivingVia #-} + +{-# OPTIONS_GHC -Wwarn=incomplete-record-selectors #-} + -- | Dependencies and Usage of a module module GHC.Unit.Module.Deps ( Dependencies(dep_direct_mods @@ -19,6 +22,7 @@ module GHC.Unit.Module.Deps , noDependencies , pprDeps , Usage (..) + , stableUsageCmp , HomeModImport (..) , HomeModImportedAvails (..) , ImportAvails (..) @@ -45,6 +49,7 @@ import GHC.Utils.Fingerprint import GHC.Utils.Binary import GHC.Utils.Outputable +import Data.Function (on) import Data.List (sortBy, sort, partition) import Data.Set (Set) import qualified Data.Set as Set @@ -464,6 +469,42 @@ instance Binary Usage where return UsageHomeModuleInterface { usg_mod_name = mod, usg_unit_id = uid, usg_iface_hash = hash } i -> error ("Binary.get(Usage): " ++ show i) +-- | 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@UsageHomeModuleInterface {} + usage2@UsageHomeModuleInterface {} + = (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 UsageHomeModuleInterface {} = 3 + constructorIndex UsageMergedRequirement {} = 4 + -- | Records the imports that we depend on from a home module, -- for recompilation checking. -- ===================================== compiler/GHC/Unit/Module/ModGuts.hs ===================================== @@ -7,7 +7,7 @@ where import GHC.Prelude -import GHC.HsToCore.Breakpoints +import GHC.HsToCore.Breakpoints.Types import GHC.ForeignSrcLang import GHC.Hs ===================================== compiler/GHC/Unit/Module/ModIface.hs ===================================== @@ -127,6 +127,8 @@ import GHC.Iface.Flags import GHC.Iface.Ext.Fields import GHC.Iface.Recomp.Types +import GHC.HsToCore.Breakpoints.Types + import GHC.Unit import GHC.Unit.Module.Deps import GHC.Unit.Module.Warnings @@ -425,6 +427,8 @@ data IfaceSimplifiedCore = IfaceSimplifiedCore { -- ^ Extra variable definitions which are **NOT** exposed but when -- combined with mi_decls allows us to restart code generation. -- See Note [Interface Files with Core Definitions] and Note [Interface File with Core: Sharing RHSs] + , mi_sc_modBreaks :: Maybe ModBreaks + -- ^ If breakpoints are present in @mi_sc_extra_decls@ this field provides this field provides the metadata required by the bytecode debugger. , mi_sc_foreign :: IfaceForeign -- ^ Foreign stubs and files to supplement 'mi_extra_decls_'. -- See Note [Foreign stubs and TH bytecode linking] @@ -754,14 +758,16 @@ instance Binary IfaceAbiHashes where } instance Binary IfaceSimplifiedCore where - put_ bh (IfaceSimplifiedCore eds fs) = do + put_ bh (IfaceSimplifiedCore eds mbs fs) = do put_ bh eds + put_ bh mbs put_ bh fs get bh = do eds <- get bh + mbs <- get bh fs <- get bh - return (IfaceSimplifiedCore eds fs) + return (IfaceSimplifiedCore eds mbs fs) emptyPartialModIface :: Module -> PartialModIface emptyPartialModIface mod @@ -870,7 +876,7 @@ instance NFData IfaceModInfo where instance NFData IfaceSimplifiedCore where - rnf (IfaceSimplifiedCore eds fs) = rnf eds `seq` rnf fs + rnf (IfaceSimplifiedCore eds mbs fs) = rnf eds `seq` rnf mbs `seq` rnf fs instance NFData IfaceAbiHashes where rnf (IfaceAbiHashes a1 a2 a3 a4 a5 a6) ===================================== compiler/GHC/Unit/Module/WholeCoreBindings.hs ===================================== @@ -9,6 +9,7 @@ import GHC.Cmm.CLabel import GHC.Driver.DynFlags (DynFlags (targetPlatform), initSDocContext) import GHC.ForeignSrcLang (ForeignSrcLang (..)) import GHC.Iface.Syntax +import GHC.HsToCore.Breakpoints.Types (ModBreaks) import GHC.Prelude import GHC.Types.ForeignStubs import GHC.Unit.Module.Location @@ -127,6 +128,7 @@ the object files. data WholeCoreBindings = WholeCoreBindings { wcb_bindings :: [IfaceBindingX IfaceMaybeRhs IfaceTopBndrInfo] -- ^ serialised tidied core bindings. + , wcb_modBreaks :: Maybe ModBreaks -- ^ if @wcb_bindings@ contains breakpoints, this field provides the metadata required by the bytecode debugger. , wcb_module :: Module -- ^ The module which the bindings are for , wcb_mod_location :: ModLocation -- ^ The location where the sources reside. -- | Stubs for foreign declarations and files added via ===================================== compiler/GHC/Utils/Binary.hs ===================================== @@ -1919,6 +1919,7 @@ instance Binary UnhelpfulSpanReason where _ -> UnhelpfulOther <$> get bh newtype BinSrcSpan = BinSrcSpan { unBinSrcSpan :: SrcSpan } + deriving newtype NFData -- See Note [Source Location Wrappers] instance Binary BinSrcSpan where ===================================== compiler/ghc.cabal.in ===================================== @@ -574,6 +574,7 @@ Library GHC.HsToCore.Arrows GHC.HsToCore.Binds GHC.HsToCore.Breakpoints + GHC.HsToCore.Breakpoints.Types GHC.HsToCore.Coverage GHC.HsToCore.Docs GHC.HsToCore.Errors.Ppr ===================================== testsuite/tests/count-deps/CountDepsAst.stdout ===================================== @@ -105,6 +105,7 @@ GHC.Hs.Pat GHC.Hs.Specificity GHC.Hs.Type GHC.Hs.Utils +GHC.HsToCore.Breakpoints.Types GHC.Iface.Errors.Types GHC.Iface.Ext.Fields GHC.Iface.Flags ===================================== testsuite/tests/count-deps/CountDepsParser.stdout ===================================== @@ -109,6 +109,7 @@ GHC.Hs.Pat GHC.Hs.Specificity GHC.Hs.Type GHC.Hs.Utils +GHC.HsToCore.Breakpoints.Types GHC.HsToCore.Errors.Types GHC.HsToCore.Pmc.Solver.Types GHC.Iface.Errors.Types ===================================== testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout ===================================== @@ -24,9 +24,9 @@ instance Monad Solo -- Defined in ‘GHC.Internal.Base’ instance Bounded a => Bounded (Solo a) -- Defined in ‘GHC.Internal.Enum’ instance Enum a => Enum (Solo a) -- Defined in ‘GHC.Internal.Enum’ -instance Read a => Read (Solo a) -- Defined in ‘GHC.Internal.Read’ instance Eq a => Eq (Solo a) -- Defined in ‘GHC.Internal.Classes’ instance Ord a => Ord (Solo a) -- Defined in ‘GHC.Internal.Classes’ +instance Read a => Read (Solo a) -- Defined in ‘GHC.Internal.Read’ instance Show a => Show (Solo a) -- Defined in ‘GHC.Internal.Show’ instance Monoid a => Monoid (Solo a) -- Defined in ‘GHC.Internal.Base’ ===================================== testsuite/tests/ghci/should_run/Makefile ===================================== @@ -13,3 +13,7 @@ TopEnvIface: # Second compilation starts from interface files, but still can print "a" "$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) TopEnvIface -v1 -e "a" -e ":q" -fwrite-if-simplified-core -fwrite-interface +T27287: + "$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) T27287.hs -v1 -fno-hide-source-paths -e ":q" -fwrite-if-simplified-core -fwrite-interface + # Second compilation starts from interface files, but still can print "a" + "$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) T27287.hs -v1 -fno-hide-source-paths -e ":break T27287 5" -e ":q" -fwrite-if-simplified-core -fwrite-interface ===================================== testsuite/tests/ghci/should_run/T27287.hs ===================================== @@ -0,0 +1,6 @@ +module T27287 where + +myfun :: String -> String +myfun xs = case reverse xs of + [] -> "empty" + xy -> xy ===================================== testsuite/tests/ghci/should_run/T27287.stdout ===================================== @@ -0,0 +1,6 @@ +[1 of 1] Compiling T27287 ( T27287.hs, interpreted )[main] +Ok, one module loaded. +Leaving GHCi. +Ok, one module loaded. +Breakpoint 0 activated at T27287.hs:5:9-15 +Leaving GHCi. ===================================== testsuite/tests/ghci/should_run/all.T ===================================== @@ -8,6 +8,7 @@ test('ghcirun002', just_ghci, compile_and_run, ['']) test('ghcirun003', just_ghci, compile_and_run, ['']) test('T2589', just_ghci, compile_and_run, ['']) test('T2881', just_ghci, compile_and_run, ['']) +test('T27287', [just_ghci, combined_output], makefile_test, []) test('T3171', [when(opsys('mingw32'),skip), View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8d5a1f45431300f3eb59d768877b5a1... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8d5a1f45431300f3eb59d768877b5a1... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help