diff options
author | Matthew Pickering <matthewtpickering@gmail.com> | 2021-04-27 12:09:13 +0100 |
---|---|---|
committer | Matthew Pickering <matthewtpickering@gmail.com> | 2021-04-27 13:24:48 +0100 |
commit | 95eadc384aab0dda15b046765355dfb89a8368b1 (patch) | |
tree | 817be8c6ab950c556d29f609bc83ecd4baa19562 | |
parent | da604f40afb66665ff30d5e704d19231c5d7b147 (diff) | |
download | haskell-95eadc384aab0dda15b046765355dfb89a8368b1.tar.gz |
Remove concept of stable module
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 |