+ -- since an scc can contain only all objects or no objects at all,
+ -- we have to check whether we got all objects or not, and re-do
+ -- the linkable check if not.
+ adjusted_linkables
+ <- if objects_allowed && not (all isObjectLinkable these_linkables)
+ then foldM (getValidLinkable old_linkables False) [] scc
+ else return these_linkables
+
+ return (adjusted_linkables ++ new_linkables)
+
+
+getValidLinkable :: [Linkable] -> Bool -> [Linkable] -> ModSummary
+ -> IO [Linkable]
+getValidLinkable old_linkables objects_allowed new_linkables summary
+ = do let mod_name = name_of_summary summary
+
+ maybe_disk_linkable
+ <- if (not objects_allowed)
+ then return Nothing
+ else case ml_obj_file (ms_location summary) of
+ Just obj_fn -> maybe_getFileLinkable mod_name obj_fn
+ Nothing -> return Nothing
+
+ let old_linkable = findModuleLinkable_maybe old_linkables mod_name
+ maybe_old_linkable =
+ case old_linkable of
+ Just l | not (isObjectLinkable l) || stillThere l
+ -> old_linkable
+ -- ToDo: emit a warning if not (stillThere l)
+ | otherwise
+ -> Nothing
+
+ -- make sure that if we had an old disk linkable around, that it's
+ -- still there on the disk (in case we need to re-link it).
+ stillThere l =
+ case maybe_disk_linkable of
+ Nothing -> False
+ Just l_disk -> linkableTime l == linkableTime l_disk
+
+ -- we only look for objects on disk the first time around;
+ -- if the user compiles a module on the side during a GHCi session,
+ -- it won't be picked up until the next ":load". This is what the
+ -- "null old_linkables" test below is.
+ linkable | null old_linkables = maybeToList maybe_disk_linkable
+ | otherwise = maybeToList maybe_old_linkable
+
+ -- only linkables newer than the source code are valid
+ src_date = ms_hs_date summary
+
+ valid_linkable
+ = filter (\l -> linkableTime l > src_date) linkable
+
+ return (valid_linkable ++ new_linkables)
+
+
+
+maybe_getFileLinkable :: ModuleName -> FilePath -> IO (Maybe Linkable)
+maybe_getFileLinkable mod_name obj_fn
+ = do obj_exist <- doesFileExist obj_fn
+ if not obj_exist
+ then return Nothing
+ else
+ do let stub_fn = case splitFilename3 obj_fn of
+ (dir, base, ext) -> dir ++ "/" ++ base ++ ".stub_o"
+ stub_exist <- doesFileExist stub_fn
+ obj_time <- getModificationTime obj_fn
+ if stub_exist
+ then return (Just (LM obj_time mod_name [DotO obj_fn, DotO stub_fn]))
+ else return (Just (LM obj_time mod_name [DotO obj_fn]))
+
+
+-----------------------------------------------------------------------------
+-- Do a pre-upsweep without use of "compile", to establish a
+-- (downward-closed) set of stable modules for which we won't call compile.
+
+-- a stable module:
+-- * has a valid linkable (see getValidLinkables above)
+-- * depends only on stable modules
+-- * has an interface in the HIT (interactive mode only)
+
+preUpsweep :: [Linkable] -- new valid linkables
+ -> HomeIfaceTable
+ -> [ModuleName] -- names of all mods encountered in downsweep
+ -> [ModuleName] -- accumulating stable modules
+ -> [SCC ModSummary] -- scc-ified mod graph, including src imps
+ -> IO [ModuleName] -- stable modules
+
+preUpsweep valid_lis hit all_home_mods stable [] = return stable
+preUpsweep valid_lis hit all_home_mods stable (scc0:sccs)
+ = do let scc = flattenSCC scc0
+ scc_allhomeimps :: [ModuleName]
+ scc_allhomeimps
+ = nub (filter (`elem` all_home_mods) (concatMap ms_allimps scc))
+ all_imports_in_scc_or_stable
+ = all in_stable_or_scc scc_allhomeimps
+ scc_names
+ = map name_of_summary scc
+ in_stable_or_scc m
+ = m `elem` scc_names || m `elem` stable
+
+ -- now we check for valid linkables: each module in the SCC must
+ -- have a valid linkable (see getValidLinkables above).
+ has_valid_linkable new_summary
+ = isJust (findModuleLinkable_maybe valid_lis modname)
+ where modname = name_of_summary new_summary
+
+ has_interface summary = ms_mod summary `elemUFM` hit
+
+ scc_is_stable = all_imports_in_scc_or_stable
+ && all has_valid_linkable scc
+ && all has_interface scc
+
+ if scc_is_stable
+ then preUpsweep valid_lis hit all_home_mods (scc_names++stable) sccs
+ else preUpsweep valid_lis hit all_home_mods stable sccs
+
+
+-- Helper for preUpsweep. Assuming that new_summary's imports are all
+-- stable (in the sense of preUpsweep), determine if new_summary is itself
+-- stable, and, if so, in batch mode, return its linkable.
+findInSummaries :: [ModSummary] -> ModuleName -> [ModSummary]
+findInSummaries old_summaries mod_name
+ = [s | s <- old_summaries, name_of_summary s == mod_name]
+
+findModInSummaries :: [ModSummary] -> Module -> Maybe ModSummary
+findModInSummaries old_summaries mod
+ = case [s | s <- old_summaries, ms_mod s == mod] of
+ [] -> Nothing
+ (s:_) -> Just s