summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Pickering <matthewtpickering@gmail.com>2021-04-27 12:09:13 +0100
committerMatthew Pickering <matthewtpickering@gmail.com>2021-04-27 13:24:48 +0100
commit95eadc384aab0dda15b046765355dfb89a8368b1 (patch)
tree817be8c6ab950c556d29f609bc83ecd4baa19562
parentda604f40afb66665ff30d5e704d19231c5d7b147 (diff)
downloadhaskell-95eadc384aab0dda15b046765355dfb89a8368b1.tar.gz
Remove concept of stable module
-rw-r--r--compiler/GHC.hs45
-rw-r--r--compiler/GHC/Core/Opt/Specialise.hs2
-rw-r--r--compiler/GHC/Driver/Main.hs108
-rw-r--r--compiler/GHC/Driver/Make.hs264
-rw-r--r--compiler/GHC/Driver/Pipeline.hs75
-rw-r--r--compiler/GHC/Iface/Load.hs19
-rw-r--r--compiler/GHC/Iface/Make.hs5
-rw-r--r--compiler/GHC/Iface/Recomp.hs47
-rw-r--r--compiler/GHC/Rename/Module.hs4
-rw-r--r--compiler/GHC/Types/SourceFile.hs10
-rw-r--r--compiler/GHC/Unit/Module/ModIface.hs4
-rw-r--r--compiler/GHC/Unit/Module/Status.hs5
-rw-r--r--ghc/GHCi/UI.hs4
-rw-r--r--testsuite/tests/driver/recomp019/recomp019.stdout2
-rw-r--r--testsuite/tests/driver/recompHash/A.hs6
-rw-r--r--testsuite/tests/driver/recompHash/B.hs3
-rw-r--r--testsuite/tests/driver/recompHash/Makefile17
-rw-r--r--testsuite/tests/driver/recompHash/all.T3
-rw-r--r--testsuite/tests/driver/recompHash/recompHash.stdout2
-rw-r--r--testsuite/tests/driver/recompNoTH/A.hs6
-rw-r--r--testsuite/tests/driver/recompNoTH/B1.hs3
-rw-r--r--testsuite/tests/driver/recompNoTH/B2.hs3
-rw-r--r--testsuite/tests/driver/recompNoTH/Makefile19
-rw-r--r--testsuite/tests/driver/recompNoTH/all.T3
-rw-r--r--testsuite/tests/driver/recompNoTH/recompNoTH.stdout3
-rw-r--r--testsuite/tests/driver/recompTH/A.hs6
-rw-r--r--testsuite/tests/driver/recompTH/B1.hs3
-rw-r--r--testsuite/tests/driver/recompTH/B2.hs3
-rw-r--r--testsuite/tests/driver/recompTH/Makefile20
-rw-r--r--testsuite/tests/driver/recompTH/all.T3
-rw-r--r--testsuite/tests/driver/recompTH/recompTH.stdout4
-rw-r--r--testsuite/tests/ghc-api/T6145.hs3
-rw-r--r--testsuite/tests/ghci/prog012/prog012.stderr2
33 files changed, 314 insertions, 392 deletions
diff --git a/compiler/GHC.hs b/compiler/GHC.hs
index 9d3e5235f1..f5c1d89b95 100644
--- a/compiler/GHC.hs
+++ b/compiler/GHC.hs
@@ -56,7 +56,7 @@ module GHC (
SuccessFlag(..), succeeded, failed,
defaultWarnErrLogger, WarnErrLogger,
workingDirectoryChanged,
- parseModule, typecheckModule, desugarModule, loadModule,
+ parseModule, typecheckModule, desugarModule,
ParsedModule(..), TypecheckedModule(..), DesugaredModule(..),
TypecheckedSource, ParsedSource, RenamedSource, -- ditto
TypecheckedMod, ParsedMod,
@@ -315,7 +315,6 @@ import GHC.Driver.Config
import GHC.Driver.Main
import GHC.Driver.Make
import GHC.Driver.Hooks
-import GHC.Driver.Pipeline ( compileOne', doesIfaceHashMatch )
import GHC.Driver.Monad
import GHC.Driver.Ppr
@@ -390,7 +389,6 @@ import GHC.Types.TyThing
import GHC.Types.Name.Env
import GHC.Types.Name.Ppr
import GHC.Types.TypeEnv
-import GHC.Types.SourceFile
import GHC.Types.Error ( DiagnosticMessage )
import GHC.Unit
@@ -1188,47 +1186,6 @@ desugarModule tcm = do
dm_core_module = guts
}
--- | Load a module. Input doesn't need to be desugared.
---
--- A module must be loaded before dependent modules can be typechecked. This
--- always includes generating a 'ModIface' and, depending on the
--- @DynFlags@\'s 'GHC.Driver.Session.backend', may also include code generation.
---
--- This function will always cause recompilation and will always overwrite
--- previous compilation results (potentially files on disk).
---
-loadModule :: (TypecheckedMod mod, GhcMonad m) => mod -> m mod
-loadModule tcm = do
- let ms = modSummary tcm
- let mod = ms_mod_name ms
- let loc = ms_location ms
- let (tcg, _details) = tm_internals tcm
-
- hsc_env <- getSession
- mb_linkable <-
- case (ms_iface_date ms, ms_obj_date ms) of
- -- See Note [When source is considered modified]
- (Just hi_date, Just obj_date) | obj_date >= hi_date -> liftIO $ do
- prev_hash_matches <- doesIfaceHashMatch hsc_env ms
- if prev_hash_matches
- then fmap Just $ findObjectLinkable
- (ms_mod ms)
- (ml_obj_file loc)
- obj_date
- else return Nothing
- _ -> return Nothing
-
- let source_modified | isNothing mb_linkable = SourceModified
- | otherwise = SourceUnmodified
- -- we can't determine stability here
-
- -- compile doesn't change the session
- mod_info <- liftIO $ compileOne' (Just tcg) Nothing
- hsc_env ms 1 1 Nothing mb_linkable
- source_modified
-
- modifySession $ hscUpdateHPT (\hpt -> addToHpt hpt mod mod_info)
- return tcm
-- %************************************************************************
diff --git a/compiler/GHC/Core/Opt/Specialise.hs b/compiler/GHC/Core/Opt/Specialise.hs
index fc62f5fa8a..9f121c9c3f 100644
--- a/compiler/GHC/Core/Opt/Specialise.hs
+++ b/compiler/GHC/Core/Opt/Specialise.hs
@@ -2560,7 +2560,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/Main.hs b/compiler/GHC/Driver/Main.hs
index 7d43d6b336..3d5916cc05 100644
--- a/compiler/GHC/Driver/Main.hs
+++ b/compiler/GHC/Driver/Main.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE NondecreasingIndentation #-}
+{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -fprof-auto-top #-}
@@ -86,6 +87,7 @@ module GHC.Driver.Main
, ioMsgMaybe
, showModuleIndex
, hscAddSptEntries
+ , writeInterfaceOnlyMode
) where
import GHC.Prelude
@@ -691,13 +693,14 @@ hscIncrementalFrontend :: Bool -- always do basic recompilation check?
-> Maybe Messager
-> ModSummary
-> SourceModified
+ -> Maybe Linkable
-> Maybe ModIface -- Old interface, if available
-> (Int,Int) -- (i,n) = module i of n (for msgs)
- -> Hsc (Either ModIface (FrontendResult, Maybe Fingerprint))
+ -> Hsc (Either (ModIface, Maybe Linkable) (FrontendResult, Maybe Fingerprint))
hscIncrementalFrontend
always_do_basic_recompilation_check m_tc_result
- mHscMessage mod_summary source_modified mb_old_iface mod_index
+ mHscMessage mod_summary source_modified old_linkable mb_old_iface mod_index
= do
hsc_env <- getHscEnv
@@ -717,19 +720,42 @@ hscIncrementalFrontend
Just h -> h mod_summary
return $ Right (tc_result, mb_old_hash)
- stable = case source_modified of
- SourceUnmodifiedAndStable -> True
- _ -> False
case m_tc_result of
+ -- This case only happens from loadModule, which is not used
+ -- anywhere
Just tc_result
| not always_do_basic_recompilation_check ->
return $ Right (FrontendTypecheck tc_result, Nothing)
+
_ -> do
- (recomp_reqd, mb_checked_iface)
+ -- First check to see if the interface file agrees with the
+ -- source file.
+ (recomp_iface_reqd, mb_checked_iface)
<- {-# SCC "checkOldIface" #-}
liftIO $ checkOldIface hsc_env mod_summary
source_modified mb_old_iface
+
+ -- Check to see whether the expected build products already exist.
+ -- If they don't exists then we trigger recompilation.
+ let lcl_dflags = ms_hspp_opts mod_summary
+ (recomp_obj_reqd, mb_linkable) <-
+ case () of
+ -- No need for a linkable, we're good to go
+ _ | writeInterfaceOnlyMode lcl_dflags -> return (UpToDate, Nothing)
+ -- Interpreter can use either already loaded bytecode or loaded object code
+ | not (backendProducesObject (backend lcl_dflags)) -> do
+ res <- liftIO $ checkByteCode old_linkable
+ case res of
+ (_, Just{}) -> return res
+ _ -> liftIO $ checkObjects old_linkable mod_summary
+ -- Need object files for making object files
+ | backendProducesObject (backend lcl_dflags) -> liftIO $ checkObjects old_linkable mod_summary
+ | otherwise -> pprPanic "hscIncrementalFrontend" (text $ show $ backend lcl_dflags)
+
+
+ let recomp_reqd = recomp_iface_reqd `mappend` recomp_obj_reqd
+
-- save the interface that comes back from checkOldIface.
-- In one-shot mode we don't have the old iface until this
-- point, when checkOldIface reads it from the disk.
@@ -737,31 +763,45 @@ hscIncrementalFrontend
case mb_checked_iface of
Just iface | not (recompileRequired recomp_reqd) ->
- -- If the module used TH splices when it was last
- -- compiled, then the recompilation check is not
- -- accurate enough (#481) and we must ignore
- -- it. However, if the module is stable (none of
- -- the modules it depends on, directly or
- -- indirectly, changed), then we *can* skip
- -- recompilation. This is why the SourceModified
- -- type contains SourceUnmodifiedAndStable, and
- -- it's pretty important: otherwise ghc --make
- -- would always recompile TH modules, even if
- -- nothing at all has changed. Stability is just
- -- the same check that make is doing for us in
- -- one-shot mode.
- case m_tc_result of
- Nothing
- | mi_used_th iface && not stable ->
- compile mb_old_hash (RecompBecause "TH")
- _ ->
- skip iface
+ skip (iface, mb_linkable)
_ ->
- case m_tc_result of
+ case m_tc_result of
Nothing -> compile mb_old_hash recomp_reqd
Just tc_result ->
return $ Right (FrontendTypecheck tc_result, mb_old_hash)
+-- | Check that the .o files produced by compilation are already up-to-date
+-- or not.
+checkObjects :: Maybe Linkable -> ModSummary -> IO (RecompileRequired, Maybe Linkable)
+checkObjects mb_old_linkable summary =
+ let
+ this_mod = ms_mod summary
+ mb_obj_date = ms_obj_date summary
+ mb_if_date = ms_iface_date summary
+ obj_fn = ml_obj_file (ms_location summary)
+ in do
+ case (,) <$> mb_obj_date <*> mb_if_date of
+ Just (obj_date, if_date)
+ | obj_date >= if_date ->
+ case mb_old_linkable of
+ Just old_linkable
+ | isObjectLinkable old_linkable, linkableTime old_linkable == obj_date
+ -> return $ (UpToDate, Just old_linkable)
+ _ -> (UpToDate,) . Just <$> findObjectLinkable this_mod obj_fn obj_date
+ _ -> return (MustCompile, Nothing)
+
+-- | Check to see if we can reuse the old linkable, by this point we will
+-- have just checked that the old interface matches up with the source hash, so
+-- no need to check that again here
+checkByteCode :: Maybe Linkable -> IO (RecompileRequired, Maybe Linkable)
+checkByteCode mb_old_linkable =
+ case mb_old_linkable of
+ Just old_linkable
+ | not (isObjectLinkable old_linkable)
+ -> return $ (UpToDate, Just old_linkable)
+ _ -> return $ (MustCompile, Nothing)
+
+
--------------------------------------------------------------
-- Compilers
--------------------------------------------------------------
@@ -777,11 +817,12 @@ hscIncrementalCompile :: Bool
-> HscEnv
-> ModSummary
-> SourceModified
+ -> Maybe Linkable
-> Maybe ModIface
-> (Int,Int)
-> IO (HscStatus, HscEnv)
hscIncrementalCompile always_do_basic_recompilation_check m_tc_result
- mHscMessage hsc_env' mod_summary source_modified mb_old_iface mod_index
+ mHscMessage hsc_env' mod_summary source_modified old_linkable mb_old_iface mod_index
= do
hsc_env'' <- initializePlugins hsc_env'
@@ -801,13 +842,13 @@ hscIncrementalCompile always_do_basic_recompilation_check m_tc_result
-- because the desugarer runs ioMsgMaybe.)
runHsc hsc_env $ do
e <- hscIncrementalFrontend always_do_basic_recompilation_check m_tc_result mHscMessage
- mod_summary source_modified mb_old_iface mod_index
+ mod_summary source_modified old_linkable mb_old_iface mod_index
case e of
-- We didn't need to do any typechecking; the old interface
-- file on disk was good enough.
- Left iface -> do
+ Left (iface, linkable) -> do
details <- liftIO $ initModDetails hsc_env mod_summary iface
- return (HscUpToDate iface details, hsc_env')
+ return (HscUpToDate (HomeModInfo iface details linkable), hsc_env')
-- We finished type checking. (mb_old_hash is the hash of
-- the interface that existed on disk; it's possible we had
-- to retypecheck but the resulting interface is exactly
@@ -940,7 +981,7 @@ finish summary tc_result mb_old_hash = do
liftIO $ hscMaybeWriteIface logger dflags True iface mb_old_iface_hash (ms_location summary)
return $ case bcknd of
- NoBackend -> HscNotGeneratingCode iface details
+ NoBackend -> HscNotGeneratingCode (HomeModInfo iface details Nothing)
_ -> case hsc_src of
HsBootFile -> HscUpdateBoot iface details
HsigFile -> HscUpdateSig iface details
@@ -2226,3 +2267,8 @@ showModuleIndex (i,n) = text "[" <> pad <> int i <> text " of " <> int n <> text
-- compute the length of x > 0 in base 10
len x = ceiling (logBase 10 (fromIntegral x+1) :: Float)
pad = text (replicate (len n - len i) ' ') -- TODO: use GHC.Utils.Ppr.RStr
+
+writeInterfaceOnlyMode :: DynFlags -> Bool
+writeInterfaceOnlyMode dflags =
+ gopt Opt_WriteInterface dflags &&
+ NoBackend == backend dflags
diff --git a/compiler/GHC/Driver/Make.hs b/compiler/GHC/Driver/Make.hs
index bff2e770cd..e9e152ef7f 100644
--- a/compiler/GHC/Driver/Make.hs
+++ b/compiler/GHC/Driver/Make.hs
@@ -125,7 +125,7 @@ import qualified Control.Monad.Catch as MC
import Data.IORef
import Data.List (nub, sort, sortBy, partition)
import qualified Data.List as List
-import Data.Foldable (toList, foldlM)
+import Data.Foldable (toList)
import Data.Maybe
import Data.Ord ( comparing )
import Data.Time
@@ -477,8 +477,7 @@ load' how_much mHscMessage mod_graph = do
warnUnnecessarySourceImports mg2_with_srcimps
-- check the stability property for each module.
- stable_mods@(stable_obj,stable_bco) <-
- liftIO $ checkStability hsc_env hpt1 mg2_with_srcimps all_home_mods
+ let stable_mods = (emptyUniqSet, emptyUniqSet)
let
-- prune bits of the HPT which are definitely redundant now,
@@ -494,19 +493,9 @@ load' how_much mHscMessage mod_graph = do
-- write the pruned HPT to allow the old HPT to be GC'd.
setSession $ discardIC $ hscUpdateHPT (const pruned_hpt) hsc_env
- liftIO $ debugTraceMsg logger dflags 2 (text "Stable obj:" <+> ppr stable_obj $$
- text "Stable BCO:" <+> ppr stable_bco)
+ -- Unload everything
+ liftIO $ unload interp hsc_env []
- -- Unload any modules which are going to be re-linked this time around.
- let stable_linkables = [ linkable
- | m <- nonDetEltsUniqSet stable_obj ++
- nonDetEltsUniqSet stable_bco,
- -- It's OK to use nonDetEltsUniqSet here
- -- because it only affects linking. Besides
- -- this list only serves as a poor man's set.
- Just hmi <- [lookupHpt pruned_hpt m],
- Just linkable <- [hm_linkable hmi] ]
- liftIO $ unload interp hsc_env stable_linkables
-- We could at this point detect cycles which aren't broken by
-- a source-import, and complain immediately, but it seems better
@@ -524,9 +513,7 @@ load' how_much mHscMessage mod_graph = do
-- This graph should be cycle-free.
-- If we're restricting the upsweep to a portion of the graph, we
-- also want to retain everything that is still stable.
- let full_mg, partial_mg0, partial_mg, unstable_mg :: [SCC ModuleGraphNode]
- stable_mg :: [SCC ExtendedModSummary]
- full_mg = topSortModuleGraph False mod_graph Nothing
+ let partial_mg0, partial_mg:: [SCC ModuleGraphNode]
maybe_top_mod = case how_much of
LoadUpTo m -> Just m
@@ -546,27 +533,7 @@ load' how_much mHscMessage mod_graph = do
| otherwise
= partial_mg0
- stable_mg =
- [ AcyclicSCC ems
- | AcyclicSCC (ModuleNode ems@(ExtendedModSummary ms _)) <- full_mg
- , stable_mod_summary ms
- ]
-
- stable_mod_summary ms =
- ms_mod_name ms `elementOfUniqSet` stable_obj ||
- ms_mod_name ms `elementOfUniqSet` stable_bco
-
- -- the modules from partial_mg that are not also stable
- -- NB. also keep cycles, we need to emit an error message later
- unstable_mg = filter not_stable partial_mg
- where not_stable (CyclicSCC _) = True
- not_stable (AcyclicSCC (InstantiationNode _)) = True
- not_stable (AcyclicSCC (ModuleNode (ExtendedModSummary ms _)))
- = not $ stable_mod_summary ms
-
- -- Load all the stable modules first, before attempting to load
- -- an unstable module (#7231).
- mg = fmap (fmap ModuleNode) stable_mg ++ unstable_mg
+ mg = partial_mg
liftIO $ debugTraceMsg logger dflags 2 (hang (text "Ready for upsweep")
2 (ppr mg))
@@ -579,7 +546,7 @@ load' how_much mHscMessage mod_graph = do
setSession $ hscUpdateHPT (const emptyHomePackageTable) hsc_env
(upsweep_ok, modsUpswept) <- withDeferredDiagnostics $
- upsweep_fn mHscMessage pruned_hpt stable_mods mg
+ upsweep_fn mHscMessage pruned_hpt mg
-- Make modsDone be the summaries for each home module now
-- available; this should equal the domain of hpt3.
@@ -913,76 +880,6 @@ type StableModules =
)
-checkStability
- :: HscEnv
- -> HomePackageTable -- HPT from last compilation
- -> [SCC ModSummary] -- current module graph (cyclic)
- -> UniqSet ModuleName -- all home modules
- -> IO StableModules
-
-checkStability hsc_env hpt sccs all_home_mods =
- foldlM checkSCC (emptyUniqSet, emptyUniqSet) sccs
- where
- checkSCC :: StableModules -> SCC ModSummary -> IO StableModules
- checkSCC (!stable_obj, !stable_bco) scc0 = do
- stableObjects <- checkStableObjects
- return $ case () of
- _ | stableObjects -> (addListToUniqSet stable_obj scc_mods, stable_bco)
- | stableBCOs -> (stable_obj, addListToUniqSet stable_bco scc_mods)
- | otherwise -> (stable_obj, stable_bco)
- where
- scc = flattenSCC scc0
- scc_mods = map ms_mod_name scc
- home_module m =
- m `elementOfUniqSet` all_home_mods && m `notElem` scc_mods
-
- scc_allimps = nub (filter home_module (concatMap ms_home_allimps scc))
- -- all imports outside the current SCC, but in the home pkg
-
- stable_obj_imps = map (`elementOfUniqSet` stable_obj) scc_allimps
- stable_bco_imps = map (`elementOfUniqSet` stable_bco) scc_allimps
-
- checkStableObjects = do
- if and stable_obj_imps
- then allM object_ok scc
- else return False
-
- stableBCOs =
- and (zipWith (||) stable_obj_imps stable_bco_imps)
- && all bco_ok scc
-
- object_ok ms
- | gopt Opt_ForceRecomp (ms_hspp_opts ms) = return False
- | Just obj_date <- ms_obj_date ms
- , Just hi_date <- ms_iface_date ms
- , obj_date >= hi_date = do
- mb_hi_hash <- readIfaceSourceHash' hsc_env ms
- case mb_hi_hash of
- Nothing -> return False
- Just hi_hash -> return $
- hi_hash == ms_hs_hash ms &&
- same_as_prev obj_date
- | otherwise = return False
- where
- same_as_prev t = case lookupHpt hpt (ms_mod_name ms) of
- Just hmi | Just l <- hm_linkable hmi ->
- isObjectLinkable l &&
- t == linkableTime l
- _other -> True
-
- bco_ok ms
- | gopt Opt_ForceRecomp (ms_hspp_opts ms) = False
- | otherwise = case lookupHpt hpt (ms_mod_name ms) of
- Just hmi | Just l <- hm_linkable hmi ->
- not (isObjectLinkable l) &&
- -- We check the hash from the HomeModInfo here
- -- instead of the linkableTime, because if we got
- -- here then the linkable doesn't represent a
- -- file on disk and the time is therefore mostly
- -- meaningless
- mi_src_hash (hm_iface hmi) == ms_hs_hash ms
- _other -> False
-
{- Parallel Upsweep
-
- The parallel upsweep attempts to concurrently compile the modules in the
@@ -1040,13 +937,6 @@ buildCompGraph (scc:sccs) = case scc of
data BuildModule = BuildModule_Unit {-# UNPACK #-} !InstantiatedUnit | BuildModule_Module {-# UNPACK #-} !ModuleWithIsBoot
deriving (Eq, Ord)
--- | Tests if an 'HscSource' is a boot file, primarily for constructing elements
--- of 'BuildModule'. We conflate signatures and modules because they are bound
--- in the same namespace; only boot interfaces can be disambiguated with
--- `import {-# SOURCE #-}`.
-hscSourceToIsBoot :: HscSource -> IsBootInterface
-hscSourceToIsBoot HsBootFile = IsBoot
-hscSourceToIsBoot _ = NotBoot
mkBuildModule :: ModuleGraphNode -> BuildModule
mkBuildModule = \case
@@ -1079,11 +969,10 @@ parUpsweep
-- ^ The number of workers we wish to run in parallel
-> Maybe Messager
-> HomePackageTable
- -> StableModules
-> [SCC ModuleGraphNode]
-> m (SuccessFlag,
[ModuleGraphNode])
-parUpsweep n_jobs mHscMessage old_hpt stable_mods sccs = do
+parUpsweep n_jobs mHscMessage old_hpt sccs = do
hsc_env <- getSession
let dflags = hsc_dflags hsc_env
let logger = hsc_logger hsc_env
@@ -1208,7 +1097,7 @@ parUpsweep n_jobs mHscMessage old_hpt stable_mods sccs = do
lcl_logger lcl_tmpfs dflags (hsc_home_unit hsc_env)
mHscMessage
par_sem hsc_env_var old_hpt_var
- stable_mods mod_idx (length sccs)
+ mod_idx (length sccs)
res <- case m_res of
Right flag -> return flag
@@ -1317,8 +1206,6 @@ parUpsweep_one
-- ^ The MVar that synchronizes updates to the global HscEnv
-> IORef HomePackageTable
-- ^ The old HPT
- -> StableModules
- -- ^ Sets of stable objects and BCOs
-> Int
-- ^ The index of this module
-> Int
@@ -1326,7 +1213,7 @@ parUpsweep_one
-> IO SuccessFlag
-- ^ The result of this compile
parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_tmpfs lcl_dflags home_unit mHscMessage par_sem
- hsc_env_var old_hpt_var stable_mods mod_index num_mods = do
+ hsc_env_var old_hpt_var mod_index num_mods = do
let this_build_mod = mkBuildModule0 mod
@@ -1456,7 +1343,7 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_tmpfs lcl_dflags
map (moduleName . gwib_mod) loop
-- Compile the module.
- mod_info <- upsweep_mod lcl_hsc_env'' mHscMessage old_hpt stable_mods
+ mod_info <- upsweep_mod lcl_hsc_env'' mHscMessage old_hpt
mod mod_index num_mods
return (Just mod_info)
@@ -1510,7 +1397,6 @@ upsweep
. GhcMonad m
=> Maybe Messager
-> HomePackageTable -- ^ HPT from last time round (pruned)
- -> StableModules -- ^ stable modules (see checkStability)
-> [SCC ModuleGraphNode] -- ^ Mods to do (the worklist)
-> m (SuccessFlag,
[ModuleGraphNode])
@@ -1520,7 +1406,7 @@ upsweep
-- 2. The 'HscEnv' in the monad has an updated HPT
-- 3. A list of modules which succeeded loading.
-upsweep mHscMessage old_hpt stable_mods sccs = do
+upsweep mHscMessage old_hpt sccs = do
(res, done) <- upsweep' old_hpt emptyMG sccs 1 (length sccs)
return (res, reverse $ mgModSummaries' done)
where
@@ -1609,7 +1495,7 @@ upsweep mHscMessage old_hpt stable_mods sccs = do
mb_mod_info
<- handleSourceError
(\err -> do logg mod (Just err); return Nothing) $ do
- mod_info <- liftIO $ upsweep_mod hsc_env2 mHscMessage old_hpt stable_mods
+ mod_info <- liftIO $ upsweep_mod hsc_env2 mHscMessage old_hpt
mod mod_index nmods
logg mod Nothing -- log warnings
return (Just mod_info)
@@ -1680,21 +1566,13 @@ upsweep_inst hsc_env mHscMessage mod_index nmods iuid = do
upsweep_mod :: HscEnv
-> Maybe Messager
-> HomePackageTable
- -> StableModules
-> ModSummary
-> Int -- index of module
-> Int -- total number of modules
-> IO HomeModInfo
-upsweep_mod hsc_env mHscMessage old_hpt (stable_obj, stable_bco) summary mod_index nmods
+upsweep_mod hsc_env mHscMessage old_hpt summary mod_index nmods
= let
this_mod_name = ms_mod_name summary
- this_mod = ms_mod summary
- mb_obj_date = ms_obj_date summary
- mb_if_date = ms_iface_date summary
- obj_fn = ml_obj_file (ms_location summary)
-
- is_stable_obj = this_mod_name `elementOfUniqSet` stable_obj
- is_stable_bco = this_mod_name `elementOfUniqSet` stable_bco
old_hmi = lookupHpt old_hpt this_mod_name
@@ -1739,111 +1617,13 @@ upsweep_mod hsc_env mHscMessage old_hpt (stable_obj, stable_bco) summary mod_ind
where
iface = hm_iface hm_info
- compile_it :: Maybe Linkable -> SourceModified -> IO HomeModInfo
- compile_it mb_linkable src_modified =
- compileOne' Nothing mHscMessage hsc_env summary' mod_index nmods
- mb_old_iface mb_linkable src_modified
-
- compile_it_discard_iface :: Maybe Linkable -> SourceModified
- -> IO HomeModInfo
- compile_it_discard_iface mb_linkable src_modified =
+ compile_it :: Maybe Linkable -> IO HomeModInfo
+ compile_it mb_linkable =
compileOne' Nothing mHscMessage hsc_env summary' mod_index nmods
- Nothing mb_linkable src_modified
-
- -- With NoBackend we create empty linkables to avoid recompilation.
- -- We have to detect these to recompile anyway if the backend changed
- -- since the last compile.
- is_fake_linkable
- | Just hmi <- old_hmi, Just l <- hm_linkable hmi =
- null (linkableUnlinked l)
- | otherwise =
- -- we have no linkable, so it cannot be fake
- False
-
- implies False _ = True
- implies True x = x
-
- debug_trace n t = liftIO $ debugTraceMsg (hsc_logger hsc_env) (hsc_dflags hsc_env) n t
+ mb_old_iface mb_linkable
in
- case () of
- _
- -- Regardless of whether we're generating object code or
- -- byte code, we can always use an existing object file
- -- if it is *stable* (see checkStability).
- | is_stable_obj, Just hmi <- old_hmi -> do
- debug_trace 5 (text "skipping stable obj mod:" <+> ppr this_mod_name)
- return hmi
- -- object is stable, and we have an entry in the
- -- old HPT: nothing to do
-
- | is_stable_obj, isNothing old_hmi -> do
- debug_trace 5 (text "compiling stable on-disk mod:" <+> ppr this_mod_name)
- linkable <- findObjectLinkable this_mod obj_fn
- (expectJust "upsweep1" mb_obj_date)
- compile_it (Just linkable) SourceUnmodifiedAndStable
- -- object is stable, but we need to load the interface
- -- off disk to make a HMI.
-
- | not (backendProducesObject bcknd), is_stable_bco,
- (bcknd /= NoBackend) `implies` not is_fake_linkable ->
- ASSERT(isJust old_hmi) -- must be in the old_hpt
- let Just hmi = old_hmi in do
- debug_trace 5 (text "skipping stable BCO mod:" <+> ppr this_mod_name)
- return hmi
- -- BCO is stable: nothing to do
-
- | not (backendProducesObject bcknd),
- Just hmi <- old_hmi,
- Just l <- hm_linkable hmi,
- not (isObjectLinkable l),
- (bcknd /= NoBackend) `implies` not is_fake_linkable,
- mi_src_hash (hm_iface hmi) == ms_hs_hash summary -> do
- debug_trace 5 (text "compiling non-stable BCO mod:" <+> ppr this_mod_name)
- compile_it (Just l) SourceUnmodified
- -- we have an old BCO that is up to date with respect
- -- to the source: do a recompilation check as normal.
-
- -- When generating object code, if there's an up-to-date
- -- object file on the disk, then we can use it.
- -- However, if the object file is new (compared to any
- -- linkable we had from a previous compilation), then we
- -- must discard any in-memory interface, because this
- -- means the user has compiled the source file
- -- separately and generated a new interface, that we must
- -- read from the disk. See Note [When source is considered modified]
- | backendProducesObject bcknd,
- Just obj_date <- mb_obj_date,
- Just if_date <- mb_if_date,
- obj_date >= if_date -> do
- prev_hash_matches <- doesIfaceHashMatch hsc_env summary
- if prev_hash_matches
- then case old_hmi of
- Just hmi
- | Just l <- hm_linkable hmi,
- isObjectLinkable l && linkableTime l == obj_date -> do
- debug_trace 5 (text "compiling mod with new on-disk obj:" <+> ppr this_mod_name)
- compile_it (Just l) SourceUnmodified
- _otherwise -> do
- debug_trace 5 (text "compiling mod with new on-disk obj2:" <+> ppr this_mod_name)
- linkable <- findObjectLinkable this_mod obj_fn obj_date
- compile_it_discard_iface (Just linkable) SourceUnmodified
- else compile_it Nothing SourceModified
-
- -- See Note [When source is considered modified]
- | writeInterfaceOnlyMode lcl_dflags -> do
- prev_hash_matches <- doesIfaceHashMatch hsc_env summary
- if prev_hash_matches
- then do
- debug_trace 5 (text "skipping tc'd mod:" <+> ppr this_mod_name)
- compile_it Nothing SourceUnmodified
- else do
- debug_trace 5 (text "re-tc'ing mod with new on-disk source:" <+> ppr this_mod_name)
- compile_it Nothing SourceModified
-
- _otherwise -> do
- debug_trace 5 (text "compiling mod:" <+> ppr this_mod_name)
- compile_it Nothing SourceModified
+ compile_it (old_hmi >>= hm_linkable)
{- Note [-fno-code mode]
@@ -2865,11 +2645,15 @@ makeNewModSummary hsc_env MakeNewModSummary{..} = do
, emsInstantiatedUnits = inst_deps
}
+
+-- This function used to return Nothing for hs-boot.. not sure why..
+-- 19519dc35bad5649226a9f7015eaabb154722e54
+-- This causes hs-boot files to always be recompiled, they should obey the
+-- same recompilation discipline as normal source files.
getObjTimestamp :: ModLocation -> IsBootInterface -> IO (Maybe UTCTime)
getObjTimestamp location is_boot
= case is_boot of
- IsBoot -> return Nothing
- NotBoot -> modificationTimeIfExists (ml_obj_file location)
+ _ -> modificationTimeIfExists (ml_obj_file location)
data PreprocessedImports
= PreprocessedImports
diff --git a/compiler/GHC/Driver/Pipeline.hs b/compiler/GHC/Driver/Pipeline.hs
index 3c189a8883..c8d2d528c9 100644
--- a/compiler/GHC/Driver/Pipeline.hs
+++ b/compiler/GHC/Driver/Pipeline.hs
@@ -31,7 +31,6 @@ module GHC.Driver.Pipeline (
phaseOutputFilename, getOutputFilename, getPipeState, getPipeEnv,
hscPostBackendPhase, getLocation, setModLocation, setDynFlags,
runPhase,
- readIfaceSourceHash', doesIfaceHashMatch,
doCpp,
linkingNeeded, checkLinkInfo, writeInterfaceOnlyMode
) where
@@ -89,7 +88,7 @@ import GHC.Data.StringBuffer ( hGetStringBuffer, hPutStringBuffer )
import GHC.Data.Maybe ( expectJust )
import GHC.Iface.Make ( mkFullIface )
-import GHC.Iface.Load
+
import GHC.Types.Basic ( SuccessFlag(..) )
import GHC.Types.Target
@@ -175,7 +174,6 @@ compileOne :: HscEnv
-> Int -- ^ ... of M
-> Maybe ModIface -- ^ old interface, if we have one
-> Maybe Linkable -- ^ old linkable, if we have one
- -> SourceModified
-> IO HomeModInfo -- ^ the complete HomeModInfo, if successful
compileOne = compileOne' Nothing (Just batchMsg)
@@ -188,12 +186,10 @@ compileOne' :: Maybe TcGblEnv
-> Int -- ^ ... of M
-> Maybe ModIface -- ^ old interface, if we have one
-> Maybe Linkable -- ^ old linkable, if we have one
- -> SourceModified
-> IO HomeModInfo -- ^ the complete HomeModInfo, if successful
compileOne' m_tc_result mHscMessage
hsc_env0 summary mod_index nmods mb_old_iface mb_old_linkable
- source_modified0
= do
let logger = hsc_logger hsc_env0
@@ -204,7 +200,7 @@ compileOne' m_tc_result mHscMessage
(status, plugin_hsc_env) <- hscIncrementalCompile
always_do_basic_recompilation_check
m_tc_result mHscMessage
- hsc_env summary source_modified mb_old_iface (mod_index, nmods)
+ hsc_env summary source_modified mb_old_linkable mb_old_iface (mod_index, nmods)
-- Use an HscEnv updated with the plugin info
let hsc_env' = plugin_hsc_env
@@ -217,17 +213,17 @@ compileOne' m_tc_result mHscMessage
[ml_obj_file $ ms_location summary]
case (status, bcknd) of
- (HscUpToDate iface hmi_details, _) ->
+ (HscUpToDate hmi, _) ->
-- TODO recomp014 triggers this assert. What's going on?!
-- ASSERT( isJust mb_old_linkable || isNoLink (ghcLink dflags) )
- return $! HomeModInfo iface hmi_details mb_old_linkable
- (HscNotGeneratingCode iface hmi_details, NoBackend) -> do
- unlinked_time <- getCurrentTime
- let mb_linkable = if isHsBootOrSig src_flavour
- then Nothing
- else Just (LM unlinked_time this_mod [])
- return $! HomeModInfo iface hmi_details mb_linkable
- (HscNotGeneratingCode _ _, _) -> panic "compileOne HscNotGeneratingCode"
+ return $! hmi
+ (HscNotGeneratingCode hmi, NoBackend) -> do
+-- unlinked_time <- getCurrentTime
+-- let mb_linkable = if isHsBootOrSig src_flavour
+-- then Nothing
+-- else Just (LM unlinked_time this_mod [])
+ return $! hmi
+ (HscNotGeneratingCode _, _) -> panic "compileOne HscNotGeneratingCode"
(_, NoBackend) -> panic "compileOne NoBackend"
(HscUpdateBoot iface hmi_details, Interpreter) ->
return $! HomeModInfo iface hmi_details Nothing
@@ -367,7 +363,7 @@ compileOne' m_tc_result mHscMessage
-- if available. So, if the "*" prefix was used, force recompilation
-- to make sure byte-code is loaded.
| force_recomp || loadAsByteCode = SourceModified
- | otherwise = source_modified0
+ | otherwise = SourceUnmodified
always_do_basic_recompilation_check = case bcknd of
Interpreter -> True
@@ -1298,6 +1294,8 @@ runPhase (RealPhase (Hsc src_flavour)) input_fn
let fc = hsc_FC hsc_env'
addHomeModuleToFinder fc home_unit mod_name location
+
+ o_mod <- liftIO $ getModTime o_file
-- Make the ModSummary to hand to hscMain
let
mod_summary = ModSummary { ms_mod = mod,
@@ -1307,7 +1305,7 @@ runPhase (RealPhase (Hsc src_flavour)) input_fn
ms_hspp_buf = hspp_buf,
ms_location = location,
ms_hs_hash = src_hash,
- ms_obj_date = Nothing,
+ ms_obj_date = o_mod,
ms_parsed_mod = Nothing,
ms_iface_date = hi_date,
ms_hie_date = Nothing,
@@ -1323,8 +1321,8 @@ runPhase (RealPhase (Hsc src_flavour)) input_fn
-- Note [When source is considered modified]
; if isNothing hi_date then return SourceModified else do {
; hi_timestamp <- getModificationUTCTime hi_file
- ; prev_hash_matches <- doesIfaceHashMatch hsc_env' mod_summary
- ; if not prev_hash_matches then return SourceModified else do {
+-- ; prev_hash_matches <- doesIfaceHashMatch hsc_env' mod_summary
+-- ; if not prev_hash_matches then return SourceModified else do {
; o_file_mod <- if writeInterfaceOnlyMode dflags
then return False
else sourceModified o_file hi_timestamp
@@ -1336,13 +1334,13 @@ runPhase (RealPhase (Hsc src_flavour)) input_fn
else pure False
; if hie_file_mod then return SourceModified else do {
; return SourceUnmodified
- }}}}}}}
+ }}}}}}
-- run the compiler!
let msg hsc_env _ what _ = oneShotMsg hsc_env what
(result, plugin_hsc_env) <-
liftIO $ hscIncrementalCompile True Nothing (Just msg) hsc_env'
- mod_summary source_unchanged Nothing (1,1)
+ mod_summary source_unchanged Nothing Nothing (1,1)
-- In the rest of the pipeline use the loaded plugins
setPlugins (hsc_plugins plugin_hsc_env)
@@ -1363,10 +1361,10 @@ runPhase (HscOut src_flavour mod_name result) _ = do
next_phase = hscPostBackendPhase src_flavour (backend dflags)
case result of
- HscNotGeneratingCode _ _ ->
+ HscNotGeneratingCode _ ->
return (RealPhase StopLn,
panic "No output filename from Hsc when no-code")
- HscUpToDate _ _ ->
+ HscUpToDate _ ->
do liftIO $ touchObjectFile logger dflags o_file
-- The .o file must have a later modification date
-- than the source file (else we wouldn't get Nothing)
@@ -1796,24 +1794,6 @@ runPhase (RealPhase MergeForeign) input_fn = do
runPhase (RealPhase other) _input_fn =
panic ("runPhase: don't know how to run phase " ++ show other)
--- | Read the previously recorded hash from a module's iface file, if any.
-readIfaceSourceHash' :: HscEnv -> ModSummary -> IO (Maybe Fingerprint)
-readIfaceSourceHash' hsc_env ms =
- readIfaceSourceHash
- (hsc_dflags hsc_env)
- (hsc_NC hsc_env)
- (ml_hi_file (ms_location ms))
-
--- | Check whether a module's current hash matches the previously recorded hash
--- in its .hi file, if any. If this function returns False then the module will
--- need recompiling.
-doesIfaceHashMatch :: HscEnv -> ModSummary -> IO Bool
-doesIfaceHashMatch hsc_env ms = do
- mb_iface_hash <- readIfaceSourceHash' hsc_env ms
- case mb_iface_hash of
- Just hash -> return $ hash == ms_hs_hash ms
- Nothing -> return False
-
maybeMergeForeign :: CompPipeline Phase
maybeMergeForeign
= do
@@ -2130,10 +2110,6 @@ joinObjectFiles logger tmpfs dflags o_files output_fn = do
-- -----------------------------------------------------------------------------
-- Misc.
-writeInterfaceOnlyMode :: DynFlags -> Bool
-writeInterfaceOnlyMode dflags =
- gopt Opt_WriteInterface dflags &&
- NoBackend == backend dflags
-- | Figure out if the .hi file was modified after some other output file
-- corresponding to that source file (or if we anyways need to consider the
@@ -2152,6 +2128,15 @@ sourceModified dest_file hi_timestamp = do
else do t2 <- getModificationUTCTime dest_file
return (t2 < hi_timestamp)
+getModTime :: FilePath -> IO (Maybe UTCTime)
+getModTime dest_file = do
+ dest_file_exists <- doesFileExist dest_file
+ if not dest_file_exists
+ then return Nothing
+ else do t2 <- getModificationUTCTime dest_file
+ return (Just t2)
+
+
-- | What phase to run after one of the backend code generators has run
hscPostBackendPhase :: HscSource -> Backend -> Phase
hscPostBackendPhase HsBootFile _ = StopLn
diff --git a/compiler/GHC/Iface/Load.hs b/compiler/GHC/Iface/Load.hs
index bd413ea08f..642f3b45b8 100644
--- a/compiler/GHC/Iface/Load.hs
+++ b/compiler/GHC/Iface/Load.hs
@@ -25,7 +25,7 @@ module GHC.Iface.Load (
-- IfM functions
loadInterface,
loadSysInterface, loadUserInterface, loadPluginInterface,
- findAndReadIface, readIface, readIfaceSourceHash, writeIface,
+ findAndReadIface, readIface, writeIface,
moduleFreeHolesPrecise,
needWiredInHomeIface, loadWiredInHomeIface,
@@ -65,7 +65,6 @@ import GHC.Utils.Outputable as Outputable
import GHC.Utils.Panic
import GHC.Utils.Misc
import GHC.Utils.Logger
-import GHC.Utils.Fingerprint
import GHC.Settings.Constants
@@ -993,22 +992,6 @@ readIface dflags name_cache wanted_mod file_path = do
Left exn -> return (Failed (text (showException exn)))
--- | Like @readIface@, but just get the source file hash out of it if it
--- exists, and don't bother returning the error otherwise.
-readIfaceSourceHash
- :: DynFlags
- -> NameCache
- -> FilePath
- -> IO (Maybe Fingerprint)
-readIfaceSourceHash dflags name_cache file_path = do
- let profile = targetProfile dflags
- res <- tryMost $ readBinIfaceHeader profile name_cache CheckHiWay QuietBinIFace file_path
- case res of
- Right (src_hash, _) ->
- return $ Just src_hash
- Left _ ->
- return Nothing
-
{-
*********************************************************
* *
diff --git a/compiler/GHC/Iface/Make.hs b/compiler/GHC/Iface/Make.hs
index be3d3001bc..10488c75ad 100644
--- a/compiler/GHC/Iface/Make.hs
+++ b/compiler/GHC/Iface/Make.hs
@@ -99,6 +99,8 @@ import Data.List ( findIndex, mapAccumL, sortBy )
import Data.Ord
import Data.IORef
+import GHC.Fingerprint
+
{-
************************************************************************
* *
@@ -286,6 +288,7 @@ mkIface_ hsc_env
trust_info = setSafeMode safe_mode
annotations = map mkIfaceAnnotation anns
icomplete_matches = map mkIfaceCompleteMatch complete_matches
+ used_th_hash = if used_th then Just fingerprint0 else Nothing
ModIface {
mi_module = this_mod,
@@ -309,7 +312,7 @@ mkIface_ hsc_env
mi_warns = warns,
mi_anns = annotations,
mi_globals = maybeGlobalRdrEnv rdr_env,
- mi_used_th = used_th,
+ mi_used_th = used_th_hash,
mi_decls = decls,
mi_hpc = isHpcUsed hpc_info,
mi_trust = trust_info,
diff --git a/compiler/GHC/Iface/Recomp.hs b/compiler/GHC/Iface/Recomp.hs
index b006610084..8463c36cae 100644
--- a/compiler/GHC/Iface/Recomp.hs
+++ b/compiler/GHC/Iface/Recomp.hs
@@ -61,6 +61,7 @@ import GHC.Unit.Module.ModIface
import GHC.Unit.Module.ModSummary
import GHC.Unit.Module.Warnings
import GHC.Unit.Module.Deps
+import GHC.Unit.Home.ModInfo
import Control.Monad
import Data.Function
@@ -113,7 +114,7 @@ data RecompileRequired
| RecompBecause String
-- ^ The .o/.hi files are up to date, but something else has changed
-- to force recompilation; the String says what (one-line summary)
- deriving Eq
+ deriving (Eq, Show)
instance Semigroup RecompileRequired where
UpToDate <> r = r
@@ -237,6 +238,8 @@ checkVersions hsc_env mod_summary iface
-- but we ALSO must make sure the instantiation matches up. See
-- test case bkpcabal04!
; hsc_env <- getTopEnv
+ ; if mi_src_hash iface /= ms_hs_hash mod_summary
+ then return (MustCompile, Nothing) else do {
; if not (isHomeModule home_unit (mi_module iface))
then return (RecompBecause "-this-unit-id changed", Nothing) else do {
; recomp <- liftIO $ checkFlagHash hsc_env iface
@@ -255,6 +258,8 @@ checkVersions hsc_env mod_summary iface
; if recompileRequired recomp then return (recomp, Just iface) else do {
; recomp <- checkPlugins hsc_env iface
; if recompileRequired recomp then return (recomp, Nothing) else do {
+ ; recomp <- checkSources hsc_env iface
+ ; if recompileRequired recomp then return (recomp, Nothing) else do {
-- Source code unchanged and no errors yet... carry on
@@ -274,7 +279,7 @@ checkVersions hsc_env mod_summary iface
; recomp <- checkList [checkModUsage (homeUnitAsUnit home_unit) u
| u <- mi_usages iface]
; return (recomp, Just iface)
- }}}}}}}}}}
+ }}}}}}}}}}}}
where
logger = hsc_logger hsc_env
dflags = hsc_dflags hsc_env
@@ -283,6 +288,7 @@ checkVersions hsc_env mod_summary iface
mod_deps :: ModuleNameEnv ModuleNameWithIsBoot
mod_deps = mkModDeps (dep_mods (mi_deps iface))
+
-- | Check if any plugins are requesting recompilation
checkPlugins :: HscEnv -> ModIface -> IfG RecompileRequired
checkPlugins hsc_env iface = liftIO $ do
@@ -1105,6 +1111,8 @@ addFingerprints hsc_env iface0
plugin_hash <- fingerprintPlugins hsc_env
+ let th_hash = fingerprintSources hsc_env (mi_deps iface0) <$ mi_used_th iface0
+
-- the ABI hash depends on:
-- - decls
-- - export list
@@ -1150,7 +1158,7 @@ addFingerprints hsc_env iface0
, mi_fix_fn = fix_fn
, mi_hash_fn = lookupOccEnv local_env
}
- final_iface = iface0 { mi_decls = sorted_decls, mi_final_exts = final_iface_exts }
+ final_iface = iface0 { mi_used_th = th_hash, mi_decls = sorted_decls, mi_final_exts = final_iface_exts }
--
return final_iface
@@ -1163,6 +1171,39 @@ addFingerprints hsc_env iface0
(non_orph_fis, orph_fis) = mkOrphMap ifFamInstOrph (mi_fam_insts iface0)
ann_fn = mkIfaceAnnCache (mi_anns iface0)
+
+-- | Combine source fingerprints of all transitively imported modules
+-- Used for the stability check for modules which use TH
+fingerprintSources :: HscEnv -> Dependencies -> Fingerprint
+fingerprintSources hsc_env deps =
+ let mod_hashes = map (mi_src_hash . hm_iface) $ mapMaybe (lookupHpt (hsc_HPT hsc_env). gwib_mod) (dep_mods deps)
+ in fingerprintFingerprints mod_hashes
+
+
+ -- If the module used TH splices when it was last
+ -- compiled, then the recompilation check is not
+ -- accurate enough (#481) and we must ignore
+ -- it. However, if the module is stable (none of
+ -- the modules it depends on, directly or
+ -- indirectly, changed), then we *can* skip
+ -- recompilation. This is why the SourceModified
+ -- type contains SourceUnmodifiedAndStable, and
+ -- it's pretty important: otherwise ghc --make
+ -- would always recompile TH modules, even if
+ -- nothing at all has changed. Stability is just
+ -- the same check that make is doing for us in
+ -- one-shot mode.
+
+-- | Check if the source hash is still accurate
+checkSources :: HscEnv -> ModIface -> IfG RecompileRequired
+checkSources hsc_env iface = do
+ case mi_used_th iface of
+ Just old_fingerprint -> do
+ if old_fingerprint == fingerprintSources hsc_env (mi_deps iface)
+ then return UpToDate
+ else return (RecompBecause "TH")
+ Nothing -> return UpToDate
+
-- | Retrieve the orphan hashes 'mi_orphan_hash' for a list of modules
-- (in particular, the orphan modules which are transitively imported by the
-- current module).
diff --git a/compiler/GHC/Rename/Module.hs b/compiler/GHC/Rename/Module.hs
index 8de0c4a34f..8c84a71378 100644
--- a/compiler/GHC/Rename/Module.hs
+++ b/compiler/GHC/Rename/Module.hs
@@ -761,10 +761,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/Types/SourceFile.hs b/compiler/GHC/Types/SourceFile.hs
index e8faec7a58..a1e2c63db1 100644
--- a/compiler/GHC/Types/SourceFile.hs
+++ b/compiler/GHC/Types/SourceFile.hs
@@ -1,6 +1,7 @@
module GHC.Types.SourceFile
( HscSource(..)
, SourceModified (..)
+ , hscSourceToIsBoot
, isHsBootOrSig
, isHsigFile
, hscSourceString
@@ -9,6 +10,7 @@ where
import GHC.Prelude
import GHC.Utils.Binary
+import GHC.Unit.Types
-- Note [HscSource types]
-- ~~~~~~~~~~~~~~~~~~~~~~
@@ -49,6 +51,14 @@ data HscSource
| HsigFile -- ^ .hsig file
deriving (Eq, Ord, Show)
+-- | Tests if an 'HscSource' is a boot file, primarily for constructing elements
+-- of 'BuildModule'. We conflate signatures and modules because they are bound
+-- in the same namespace; only boot interfaces can be disambiguated with
+-- `import {-# SOURCE #-}`.
+hscSourceToIsBoot :: HscSource -> IsBootInterface
+hscSourceToIsBoot HsBootFile = IsBoot
+hscSourceToIsBoot _ = NotBoot
+
instance Binary HscSource where
put_ bh HsSrcFile = putByte bh 0
put_ bh HsBootFile = putByte bh 1
diff --git a/compiler/GHC/Unit/Module/ModIface.hs b/compiler/GHC/Unit/Module/ModIface.hs
index fb8fb422ae..4e563ff9e9 100644
--- a/compiler/GHC/Unit/Module/ModIface.hs
+++ b/compiler/GHC/Unit/Module/ModIface.hs
@@ -169,7 +169,7 @@ data ModIface_ (phase :: ModIfacePhase)
-- exported by this module, and the 'OccName's of those things
- mi_used_th :: !Bool,
+ mi_used_th :: !(Maybe Fingerprint),
-- ^ Module required TH splices when it was compiled.
-- This disables recompilation avoidance (see #481).
@@ -464,7 +464,7 @@ emptyPartialModIface mod
mi_deps = noDependencies,
mi_usages = [],
mi_exports = [],
- mi_used_th = False,
+ mi_used_th = Nothing,
mi_fixities = [],
mi_warns = NoWarnings,
mi_anns = [],
diff --git a/compiler/GHC/Unit/Module/Status.hs b/compiler/GHC/Unit/Module/Status.hs
index 52938154b4..2adb9d1793 100644
--- a/compiler/GHC/Unit/Module/Status.hs
+++ b/compiler/GHC/Unit/Module/Status.hs
@@ -9,15 +9,16 @@ import GHC.Unit
import GHC.Unit.Module.ModGuts
import GHC.Unit.Module.ModIface
import GHC.Unit.Module.ModDetails
+import GHC.Unit.Home.ModInfo
import GHC.Utils.Fingerprint
-- | Status of a module compilation to machine code
data HscStatus
-- | Nothing to do.
- = HscNotGeneratingCode ModIface ModDetails
+ = HscNotGeneratingCode HomeModInfo
-- | Nothing to do because code already exists.
- | HscUpToDate ModIface ModDetails
+ | HscUpToDate HomeModInfo
-- | Update boot file result.
| HscUpdateBoot ModIface ModDetails
-- | Generate signature file (backpack)
diff --git a/ghc/GHCi/UI.hs b/ghc/GHCi/UI.hs
index c53f6771b5..c10f6051ea 100644
--- a/ghc/GHCi/UI.hs
+++ b/ghc/GHCi/UI.hs
@@ -480,6 +480,10 @@ interactiveUI config srcs maybe_exprs = do
LangExt.MonomorphismRestriction xopt_unset)
$ dflags
GHC.setInteractiveDynFlags dflags'
+ GHC.setSessionDynFlags
+ -- Set Opt_KeepGoing so that :reload loads as much as
+ -- possible
+ (gopt_set dflags Opt_KeepGoing)
-- Update the LogAction. Ensure we don't override the user's log action lest
-- we break -ddump-json (#14078)
diff --git a/testsuite/tests/driver/recomp019/recomp019.stdout b/testsuite/tests/driver/recomp019/recomp019.stdout
index f1e4cd4d73..52bb3608a4 100644
--- a/testsuite/tests/driver/recomp019/recomp019.stdout
+++ b/testsuite/tests/driver/recomp019/recomp019.stdout
@@ -6,6 +6,6 @@ Linking Main ...
5
[1 of 1] Compiling B ( B.hs, nothing )
second run
-[2 of 3] Compiling B ( B.hs, B.o )
+[1 of 3] Compiling B ( B.hs, B.o )
Linking Main ...
15
diff --git a/testsuite/tests/driver/recompHash/A.hs b/testsuite/tests/driver/recompHash/A.hs
new file mode 100644
index 0000000000..905110c8cf
--- /dev/null
+++ b/testsuite/tests/driver/recompHash/A.hs
@@ -0,0 +1,6 @@
+{-# LANGUAGE TemplateHaskell #-}
+module A where
+
+import B
+
+main = print 0
diff --git a/testsuite/tests/driver/recompHash/B.hs b/testsuite/tests/driver/recompHash/B.hs
new file mode 100644
index 0000000000..7b1456b488
--- /dev/null
+++ b/testsuite/tests/driver/recompHash/B.hs
@@ -0,0 +1,3 @@
+module B where
+
+c = print 0
diff --git a/testsuite/tests/driver/recompHash/Makefile b/testsuite/tests/driver/recompHash/Makefile
new file mode 100644
index 0000000000..b0e578a05d
--- /dev/null
+++ b/testsuite/tests/driver/recompHash/Makefile
@@ -0,0 +1,17 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+# Recompilation tests
+
+clean:
+ rm -f *.o*
+ rm -f *.dyn_o*
+ rm -f *.hi*
+
+# Touching a file should not cause recompilation
+
+recompHash: clean
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make A.hs
+ touch B.hs
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make A.hs
diff --git a/testsuite/tests/driver/recompHash/all.T b/testsuite/tests/driver/recompHash/all.T
new file mode 100644
index 0000000000..ab0814b62b
--- /dev/null
+++ b/testsuite/tests/driver/recompHash/all.T
@@ -0,0 +1,3 @@
+test('recompHash', [extra_files(['A.hs', 'B.hs']),
+ when(fast(), skip)],
+ makefile_test, [])
diff --git a/testsuite/tests/driver/recompHash/recompHash.stdout b/testsuite/tests/driver/recompHash/recompHash.stdout
new file mode 100644
index 0000000000..50dd203d39
--- /dev/null
+++ b/testsuite/tests/driver/recompHash/recompHash.stdout
@@ -0,0 +1,2 @@
+[1 of 2] Compiling B ( B.hs, B.o, B.dyn_o )
+[2 of 2] Compiling A ( A.hs, A.o, A.dyn_o )
diff --git a/testsuite/tests/driver/recompNoTH/A.hs b/testsuite/tests/driver/recompNoTH/A.hs
new file mode 100644
index 0000000000..905110c8cf
--- /dev/null
+++ b/testsuite/tests/driver/recompNoTH/A.hs
@@ -0,0 +1,6 @@
+{-# LANGUAGE TemplateHaskell #-}
+module A where
+
+import B
+
+main = print 0
diff --git a/testsuite/tests/driver/recompNoTH/B1.hs b/testsuite/tests/driver/recompNoTH/B1.hs
new file mode 100644
index 0000000000..7b1456b488
--- /dev/null
+++ b/testsuite/tests/driver/recompNoTH/B1.hs
@@ -0,0 +1,3 @@
+module B where
+
+c = print 0
diff --git a/testsuite/tests/driver/recompNoTH/B2.hs b/testsuite/tests/driver/recompNoTH/B2.hs
new file mode 100644
index 0000000000..c7f392c91a
--- /dev/null
+++ b/testsuite/tests/driver/recompNoTH/B2.hs
@@ -0,0 +1,3 @@
+module B where
+
+c = print 1
diff --git a/testsuite/tests/driver/recompNoTH/Makefile b/testsuite/tests/driver/recompNoTH/Makefile
new file mode 100644
index 0000000000..89f0f26738
--- /dev/null
+++ b/testsuite/tests/driver/recompNoTH/Makefile
@@ -0,0 +1,19 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+# Recompilation tests
+
+clean:
+ rm -f *.o*
+ rm -f *.dyn_o*
+ rm -f *.hi*
+
+# If the source changes, but not the ABI, then only B should be recompiled.
+
+recompNoTH: clean
+ '$(CP)' B1.hs B.hs
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make A.hs
+ '$(CP)' B2.hs B.hs
+ # Should print that only B has been recompiled.
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make A.hs
diff --git a/testsuite/tests/driver/recompNoTH/all.T b/testsuite/tests/driver/recompNoTH/all.T
new file mode 100644
index 0000000000..db66a0af41
--- /dev/null
+++ b/testsuite/tests/driver/recompNoTH/all.T
@@ -0,0 +1,3 @@
+test('recompNoTH', [extra_files(['A.hs', 'B1.hs', 'B2.hs' ]),
+ when(fast(), skip)],
+ makefile_test, [])
diff --git a/testsuite/tests/driver/recompNoTH/recompNoTH.stdout b/testsuite/tests/driver/recompNoTH/recompNoTH.stdout
new file mode 100644
index 0000000000..310ab29692
--- /dev/null
+++ b/testsuite/tests/driver/recompNoTH/recompNoTH.stdout
@@ -0,0 +1,3 @@
+[1 of 2] Compiling B ( B.hs, B.o, B.dyn_o )
+[2 of 2] Compiling A ( A.hs, A.o, A.dyn_o )
+[1 of 2] Compiling B ( B.hs, B.o, B.dyn_o )
diff --git a/testsuite/tests/driver/recompTH/A.hs b/testsuite/tests/driver/recompTH/A.hs
new file mode 100644
index 0000000000..53ba525e01
--- /dev/null
+++ b/testsuite/tests/driver/recompTH/A.hs
@@ -0,0 +1,6 @@
+{-# LANGUAGE TemplateHaskell #-}
+module A where
+
+import B
+
+main = $([| print () |])
diff --git a/testsuite/tests/driver/recompTH/B1.hs b/testsuite/tests/driver/recompTH/B1.hs
new file mode 100644
index 0000000000..7b1456b488
--- /dev/null
+++ b/testsuite/tests/driver/recompTH/B1.hs
@@ -0,0 +1,3 @@
+module B where
+
+c = print 0
diff --git a/testsuite/tests/driver/recompTH/B2.hs b/testsuite/tests/driver/recompTH/B2.hs
new file mode 100644
index 0000000000..c7f392c91a
--- /dev/null
+++ b/testsuite/tests/driver/recompTH/B2.hs
@@ -0,0 +1,3 @@
+module B where
+
+c = print 1
diff --git a/testsuite/tests/driver/recompTH/Makefile b/testsuite/tests/driver/recompTH/Makefile
new file mode 100644
index 0000000000..758dd9a37f
--- /dev/null
+++ b/testsuite/tests/driver/recompTH/Makefile
@@ -0,0 +1,20 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+# Recompilation tests
+
+clean:
+ rm -f *.o*
+ rm -f *.dyn_o*
+ rm -f *.hi*
+
+# Test that using a TH splice in a module causes recompilation when the *source*
+# of a dependency changes.
+
+recompTH: clean
+ '$(CP)' B1.hs B.hs
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make A.hs
+ '$(CP)' B2.hs B.hs
+ # Should print that A has been recompiled.
+ '$(TEST_HC)' $(TEST_HC_OPTS) --make A.hs
diff --git a/testsuite/tests/driver/recompTH/all.T b/testsuite/tests/driver/recompTH/all.T
new file mode 100644
index 0000000000..f6d447d397
--- /dev/null
+++ b/testsuite/tests/driver/recompTH/all.T
@@ -0,0 +1,3 @@
+test('recompTH', [extra_files(['A.hs', 'B1.hs', 'B2.hs' ]),
+ when(fast(), skip)],
+ makefile_test, [])
diff --git a/testsuite/tests/driver/recompTH/recompTH.stdout b/testsuite/tests/driver/recompTH/recompTH.stdout
new file mode 100644
index 0000000000..1af356d229
--- /dev/null
+++ b/testsuite/tests/driver/recompTH/recompTH.stdout
@@ -0,0 +1,4 @@
+[1 of 2] Compiling B ( B.hs, B.o, B.dyn_o )
+[2 of 2] Compiling A ( A.hs, A.o, A.dyn_o )
+[1 of 2] Compiling B ( B.hs, B.o, B.dyn_o )
+[2 of 2] Compiling A ( A.hs, A.o, A.dyn_o ) [TH]
diff --git a/testsuite/tests/ghc-api/T6145.hs b/testsuite/tests/ghc-api/T6145.hs
index 3d929c8c9d..392c318768 100644
--- a/testsuite/tests/ghc-api/T6145.hs
+++ b/testsuite/tests/ghc-api/T6145.hs
@@ -30,8 +30,7 @@ main = do
p <- parseModule modSum
t <- typecheckModule p
d <- desugarModule t
- l <- loadModule d
- let ts=typecheckedSource l
+ let ts=typecheckedSource d
-- liftIO (putStr (showSDocDebug (ppr ts)))
let fs=filterBag isDataCon ts
return $ not $ isEmptyBag fs
diff --git a/testsuite/tests/ghci/prog012/prog012.stderr b/testsuite/tests/ghci/prog012/prog012.stderr
index 71d2bd385a..2145bfbbfb 100644
--- a/testsuite/tests/ghci/prog012/prog012.stderr
+++ b/testsuite/tests/ghci/prog012/prog012.stderr
@@ -1,2 +1,4 @@
Bar.hs:3:7: error: Variable not in scope: nonexistent
+-fkeep-going in use, removing the following dependencies and continuing:
+ FooBar