Simplify type of ms_srcimps and ms_textual_imps.
[ghc.git] / compiler / main / GhcMake.hs
index 3581aa0..123cc9e 100644 (file)
@@ -1,4 +1,8 @@
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE BangPatterns, CPP, NondecreasingIndentation, ScopedTypeVariables #-}
+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
+-- NB: we specifically ignore deprecations. GHC 7.6 marks the .QSem module as
+-- deprecated, although it became un-deprecated later. As a result, using 7.6
+-- as your bootstrap compiler throws annoying warnings.
 
 -- -----------------------------------------------------------------------------
 --
 -- by --make and GHCi.
 --
 -- -----------------------------------------------------------------------------
-module GhcMake( 
-        depanal, 
+module GhcMake(
+        depanal,
         load, LoadHowMuch(..),
 
-        topSortModuleGraph, 
+        topSortModuleGraph,
 
         noModError, cyclicModuleErr
     ) where
@@ -30,10 +34,8 @@ import ErrUtils
 import Finder
 import GhcMonad
 import HeaderInfo
-import HsSyn
 import HscTypes
 import Module
-import RdrName          ( RdrName )
 import TcIface          ( typecheckIface )
 import TcRnMonad        ( initIfaceCheck )
 
@@ -42,8 +44,9 @@ import BasicTypes
 import Digraph
 import Exception        ( tryIO, gbracket, gfinally )
 import FastString
-import Maybes           ( expectJust, mapCatMaybes )
-import MonadUtils       ( allM )
+import Maybes           ( expectJust )
+import Name
+import MonadUtils       ( allM, MonadIO )
 import Outputable
 import Panic
 import SrcLoc
@@ -52,12 +55,14 @@ import SysTools
 import UniqFM
 import Util
 
+import Data.Either ( rights, partitionEithers )
 import qualified Data.Map as Map
 import Data.Map (Map)
 import qualified Data.Set as Set
 import qualified FiniteMap as Map ( insertListWith )
 
 import Control.Concurrent ( forkIOWithUnmask, killThread )
+import qualified GHC.Conc as CC
 import Control.Concurrent.MVar
 import Control.Concurrent.QSem
 import Control.Exception
@@ -75,6 +80,11 @@ import System.IO.Error  ( isDoesNotExistError )
 
 import GHC.Conc ( getNumProcessors, getNumCapabilities, setNumCapabilities )
 
+label_self :: String -> IO ()
+label_self thread_name = do
+    self_tid <- CC.myThreadId
+    CC.labelThread self_tid thread_name
+
 -- -----------------------------------------------------------------------------
 -- Loading the program
 
@@ -86,7 +96,7 @@ import GHC.Conc ( getNumProcessors, getNumCapabilities, setNumCapabilities )
 --
 -- Note that each 'ModSummary' in the module graph caches its 'DynFlags'.
 -- These 'DynFlags' are determined by the /current/ session 'DynFlags' and the
--- @OPTIONS@ and @LANGUAGE@ pragmas of the parsed module.  Thus if you want to
+-- @OPTIONS@ and @LANGUAGE@ pragmas of the parsed module.  Thus if you want
 -- changes to the 'DynFlags' to take effect you need to call this function
 -- again.
 --
@@ -100,13 +110,14 @@ depanal excluded_mods allow_dup_roots = do
          dflags  = hsc_dflags hsc_env
          targets = hsc_targets hsc_env
          old_graph = hsc_mod_graph hsc_env
-        
+
   liftIO $ showPass dflags "Chasing dependencies"
   liftIO $ debugTraceMsg dflags 2 (hcat [
              text "Chasing modules from: ",
              hcat (punctuate comma (map pprTarget targets))])
 
-  mod_graph <- liftIO $ downsweep hsc_env old_graph excluded_mods allow_dup_roots
+  mod_graphE <- liftIO $ downsweep hsc_env old_graph excluded_mods allow_dup_roots
+  mod_graph <- reportImportErrors mod_graphE
   modifySession $ \_ -> hsc_env { hsc_mod_graph = mod_graph }
   return mod_graph
 
@@ -124,15 +135,15 @@ data LoadHowMuch
 --
 -- This function implements the core of GHC's @--make@ mode.  It preprocesses,
 -- compiles and loads the specified modules, avoiding re-compilation wherever
--- possible.  Depending on the target (see 'DynFlags.hscTarget') compilating
+-- possible.  Depending on the target (see 'DynFlags.hscTarget') compiling
 -- and loading may result in files being created on disk.
 --
--- Calls the 'reportModuleCompilationResult' callback after each compiling
--- each module, whether successful or not.
+-- Calls the 'defaultWarnErrLogger' after each compiling each module, whether
+-- successful or not.
 --
 -- Throw a 'SourceError' if errors are encountered before the actual
 -- compilation starts (e.g., during dependency analysis).  All other errors
--- are reported using the callback.
+-- are reported using the 'defaultWarnErrLogger'.
 --
 load :: GhcMonad m => LoadHowMuch -> m SuccessFlag
 load how_much = do
@@ -147,11 +158,14 @@ load how_much = do
     -- B.hs-boot in the module graph, but no B.hs
     -- The downsweep should have ensured this does not happen
     -- (see msDeps)
-    let all_home_mods = [ms_mod_name s 
+    let all_home_mods = [ms_mod_name s
                         | s <- mod_graph, not (isBootSummary s)]
-        bad_boot_mods = [s        | s <- mod_graph, isBootSummary s,
-                                    not (ms_mod_name s `elem` all_home_mods)]
-    ASSERT( null bad_boot_mods ) return ()
+    -- TODO: Figure out what the correct form of this assert is. It's violated
+    -- when you have HsBootMerge nodes in the graph: then you'll have hs-boot
+    -- files without corresponding hs files.
+    --  bad_boot_mods = [s        | s <- mod_graph, isBootSummary s,
+    --                              not (ms_mod_name s `elem` all_home_mods)]
+    -- ASSERT( null bad_boot_mods ) return ()
 
     -- check that the module given in HowMuch actually exists, otherwise
     -- topSortModuleGraph will bomb later.
@@ -161,14 +175,14 @@ load how_much = do
 
         checkMod m and_then
             | m `elem` all_home_mods = and_then
-            | otherwise = do 
+            | otherwise = do
                     liftIO $ errorMsg dflags (text "no such module:" <+>
                                      quotes (ppr m))
                     return Failed
 
     checkHowMuch how_much $ do
 
-    -- mg2_with_srcimps drops the hi-boot nodes, returning a 
+    -- mg2_with_srcimps drops the hi-boot nodes, returning a
     -- graph with cycles.  Among other things, it is used for
     -- backing out partially complete cycles following a failed
     -- upsweep, and for removing from hpt all the modules
@@ -187,7 +201,7 @@ load how_much = do
 
         -- prune bits of the HPT which are definitely redundant now,
         -- to save space.
-        pruned_hpt = pruneHomePackageTable hpt1 
+        pruned_hpt = pruneHomePackageTable hpt1
                             (flattenSCCs mg2_with_srcimps)
                             stable_mods
 
@@ -196,7 +210,7 @@ load how_much = do
     -- before we unload anything, make sure we don't leave an old
     -- interactive context around pointing to dead bindings.  Also,
     -- write the pruned HPT to allow the old HPT to be GC'd.
-    modifySession $ \_ -> discardIC $ hsc_env { hsc_HPT = pruned_hpt }
+    setSession $ discardIC $ hsc_env { hsc_HPT = pruned_hpt }
 
     liftIO $ debugTraceMsg dflags 2 (text "Stable obj:" <+> ppr stable_obj $$
                             text "Stable BCO:" <+> ppr stable_bco)
@@ -240,17 +254,17 @@ load how_much = do
         -- is stable).
         partial_mg
             | LoadDependenciesOf _mod <- how_much
-            = ASSERT( case last partial_mg0 of 
+            = ASSERT( case last partial_mg0 of
                         AcyclicSCC ms -> ms_mod_name ms == _mod; _ -> False )
               List.init partial_mg0
             | otherwise
             = partial_mg0
 
-        stable_mg = 
+        stable_mg =
             [ AcyclicSCC ms
             | AcyclicSCC ms <- full_mg,
               ms_mod_name ms `elem` stable_obj++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
@@ -291,7 +305,7 @@ load how_much = do
 
     if succeeded upsweep_ok
 
-     then 
+     then
        -- Easy; just relink it all.
        do liftIO $ debugTraceMsg dflags 2 (text "Upsweep completely successful.")
 
@@ -307,25 +321,27 @@ load how_much = do
           --
           let ofile = outputFile dflags
           let no_hs_main = gopt Opt_NoHsMain dflags
-          let 
+          let
             main_mod = mainModIs dflags
             a_root_is_Main = any ((==main_mod).ms_mod) mod_graph
             do_linking = a_root_is_Main || no_hs_main || ghcLink dflags == LinkDynLib || ghcLink dflags == LinkStaticLib
 
-          when (ghcLink dflags == LinkBinary 
-                && isJust ofile && not do_linking) $
-            liftIO $ debugTraceMsg dflags 1 $
-                text ("Warning: output was redirected with -o, " ++
-                      "but no output will be generated\n" ++
-                      "because there is no " ++ 
-                      moduleNameString (moduleName main_mod) ++ " module.")
-
           -- link everything together
           linkresult <- liftIO $ link (ghcLink dflags) dflags do_linking (hsc_HPT hsc_env1)
 
-          loadFinish Succeeded linkresult
-
-     else 
+          if ghcLink dflags == LinkBinary && isJust ofile && not do_linking
+             then do
+                liftIO $ errorMsg dflags $ text
+                   ("output was redirected with -o, " ++
+                    "but no output will be generated\n" ++
+                    "because there is no " ++
+                    moduleNameString (moduleName main_mod) ++ " module.")
+                -- This should be an error, not a warning (#10895).
+                loadFinish Failed linkresult
+             else
+                loadFinish Succeeded linkresult
+
+     else
        -- Tricky.  We need to back out the effects of compiling any
        -- half-done cycles, both so as to clean up the top level envs
        -- and to avoid telling the interactive linker to link them.
@@ -333,15 +349,15 @@ load how_much = do
 
           let modsDone_names
                  = map ms_mod modsDone
-          let mods_to_zap_names 
-                 = findPartiallyCompletedCycles modsDone_names 
+          let mods_to_zap_names
+                 = findPartiallyCompletedCycles modsDone_names
                       mg2_with_srcimps
           let mods_to_keep
-                 = filter ((`notElem` mods_to_zap_names).ms_mod) 
+                 = filter ((`notElem` mods_to_zap_names).ms_mod)
                       modsDone
 
           hsc_env1 <- getSession
-          let hpt4 = retainInTopLevelEnvs (map ms_mod_name mods_to_keep) 
+          let hpt4 = retainInTopLevelEnvs (map ms_mod_name mods_to_keep)
                                           (hsc_HPT hsc_env1)
 
           -- Clean up after ourselves
@@ -349,7 +365,7 @@ load how_much = do
 
           -- there should be no Nothings where linkables should be, now
           ASSERT(all (isJust.hm_linkable) (eltsUFM (hsc_HPT hsc_env))) do
-    
+
           -- Link everything together
           linkresult <- liftIO $ link (ghcLink dflags) dflags False hpt4
 
@@ -380,10 +396,23 @@ discardProg hsc_env
   = discardIC $ hsc_env { hsc_mod_graph = emptyMG
                         , hsc_HPT = emptyHomePackageTable }
 
--- | Discard the contents of the InteractiveContext, but keep the DynFlags
+-- | Discard the contents of the InteractiveContext, but keep the DynFlags.
+-- It will also keep ic_int_print and ic_monad if their names are from
+-- external packages.
 discardIC :: HscEnv -> HscEnv
 discardIC hsc_env
-  = hsc_env { hsc_IC = emptyInteractiveContext (ic_dflags (hsc_IC hsc_env)) }
+  = hsc_env { hsc_IC = new_ic { ic_int_print = keep_external_name ic_int_print
+                              , ic_monad = keep_external_name ic_monad } }
+  where
+  dflags = ic_dflags old_ic
+  old_ic = hsc_IC hsc_env
+  new_ic = emptyInteractiveContext dflags
+  keep_external_name ic_name
+    | nameIsFromExternalPackage this_pkg old_name = old_name
+    | otherwise = ic_name new_ic
+    where
+    this_pkg = thisPackage dflags
+    old_name = ic_name old_ic
 
 intermediateCleanTempFiles :: DynFlags -> [ModSummary] -> HscEnv -> IO ()
 intermediateCleanTempFiles dflags summaries hsc_env
@@ -415,14 +444,22 @@ guessOutputFile = modifySession $ \env ->
             ml_hs_file (ms_location ms)
         name = fmap dropExtension mainModuleSrcPath
 
+        name_exe = do
 #if defined(mingw32_HOST_OS)
-        -- we must add the .exe extention unconditionally here, otherwise
-        -- when name has an extension of its own, the .exe extension will
-        -- not be added by DriverPipeline.exeFileName.  See #2248
-        name_exe = fmap (<.> "exe") name
+          -- we must add the .exe extention unconditionally here, otherwise
+          -- when name has an extension of its own, the .exe extension will
+          -- not be added by DriverPipeline.exeFileName.  See #2248
+          name' <- fmap (<.> "exe") name
 #else
-        name_exe = name
+          name' <- name
 #endif
+          mainModuleSrcPath' <- mainModuleSrcPath
+          -- #9930: don't clobber input files (unless they ask for it)
+          if name' == mainModuleSrcPath'
+            then throwGhcException . UsageError $
+                 "default output name would overwrite the input file; " ++
+                 "must specify -o explicitly"
+            else Just name'
     in
     case outputFile dflags of
         Just _ -> env
@@ -476,11 +513,11 @@ findPartiallyCompletedCycles modsDone theGraph
         chew ((AcyclicSCC _):rest) = chew rest    -- acyclic?  not interesting.
         chew ((CyclicSCC vs):rest)
            = let names_in_this_cycle = nub (map ms_mod vs)
-                 mods_in_this_cycle  
-                    = nub ([done | done <- modsDone, 
+                 mods_in_this_cycle
+                    = nub ([done | done <- modsDone,
                                    done `elem` names_in_this_cycle])
                  chewed_rest = chew rest
-             in 
+             in
              if   notNull mods_in_this_cycle
                   && length mods_in_this_cycle < length names_in_this_cycle
              then mods_in_this_cycle ++ chewed_rest
@@ -507,7 +544,7 @@ unload hsc_env stable_linkables -- Unload everthing *except* 'stable_linkables'
 
   Stability tells us which modules definitely do not need to be recompiled.
   There are two main reasons for having stability:
-  
+
    - avoid doing a complete upsweep of the module graph in GHCi when
      modules near the bottom of the tree have not changed.
 
@@ -522,7 +559,7 @@ unload hsc_env stable_linkables -- Unload everthing *except* 'stable_linkables'
 @
   stable m = stableObject m || stableBCO m
 
-  stableObject m = 
+  stableObject m =
         all stableObject (imports m)
         && old linkable does not exist, or is == on-disk .o
         && date(on-disk .o) > date(.hs)
@@ -571,15 +608,15 @@ checkStability hpt sccs all_home_mods = foldl checkSCC ([],[]) sccs
 
         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 (`elem` stable_obj) scc_allimps
         stable_bco_imps = map (`elem` stable_bco) scc_allimps
 
-        stableObjects = 
+        stableObjects =
            and stable_obj_imps
            && all object_ok scc
 
-        stableBCOs = 
+        stableBCOs =
            and (zipWith (||) stable_obj_imps stable_bco_imps)
            && all bco_ok scc
 
@@ -595,7 +632,7 @@ checkStability hpt sccs all_home_mods = foldl checkSCC ([],[]) sccs
                                 _other  -> True
                 -- why '>=' rather than '>' above?  If the filesystem stores
                 -- times to the nearset second, we may occasionally find that
-                -- the object & source have the same modification time, 
+                -- the object & source have the same modification time,
                 -- especially if the source was automatically generated
                 -- and compiled.  Using >= is slightly unsafe, but it matches
                 -- make's behaviour.
@@ -607,7 +644,7 @@ checkStability hpt sccs all_home_mods = foldl checkSCC ([],[]) sccs
           | gopt Opt_ForceRecomp (ms_hspp_opts ms) = False
           | otherwise = case lookupUFM hpt (ms_mod_name ms) of
                 Just hmi  | Just l <- hm_linkable hmi ->
-                        not (isObjectLinkable l) && 
+                        not (isObjectLinkable l) &&
                         linkableTime l >= ms_hs_date ms
                 _other  -> False
 
@@ -661,10 +698,22 @@ buildCompGraph (scc:sccs) = case scc of
     CyclicSCC mss -> return ([], Just mss)
 
 -- A Module and whether it is a boot module.
-type BuildModule = (Module, Bool)
+type BuildModule = (Module, IsBoot)
+
+-- | 'Bool' indicating if a module is a boot module or not.  We need to treat
+-- boot modules specially when building compilation graphs, since they break
+-- cycles.  Regular source files and signature files are treated equivalently.
+data IsBoot = IsBoot | NotBoot
+    deriving (Ord, Eq, Show, Read)
+
+-- | Tests if an 'HscSource' is a boot file, primarily for constructing
+-- elements of 'BuildModule'.
+hscSourceToIsBoot :: HscSource -> IsBoot
+hscSourceToIsBoot HsBootFile = IsBoot
+hscSourceToIsBoot _ = NotBoot
 
 mkBuildModule :: ModSummary -> BuildModule
-mkBuildModule ms = (ms_mod ms, isBootSummary ms)
+mkBuildModule ms = (ms_mod ms, if isBootSummary ms then IsBoot else NotBoot)
 
 -- | The entry point to the parallel upsweep.
 --
@@ -738,10 +787,18 @@ parUpsweep n_jobs old_hpt stable_mods cleanup sccs = do
                          | ((ms,mvar,_),idx) <- comp_graph_w_idx ]
 
 
+    liftIO $ label_self "main --make thread"
     -- For each module in the module graph, spawn a worker thread that will
     -- compile this module.
     let { spawnWorkers = forM comp_graph_w_idx $ \((mod,!mvar,!log_queue),!mod_idx) ->
             forkIOWithUnmask $ \unmask -> do
+                liftIO $ label_self $ unwords
+                    [ "worker --make thread"
+                    , "for module"
+                    , show (moduleNameString (ms_mod_name mod))
+                    , "number"
+                    , show mod_idx
+                    ]
                 -- Replace the default log_action with one that writes each
                 -- message to the module's log_queue. The main thread will
                 -- deal with synchronously printing these messages.
@@ -821,7 +878,7 @@ parUpsweep n_jobs old_hpt stable_mods cleanup sccs = do
   where
     writeLogQueue :: LogQueue -> Maybe (Severity,SrcSpan,PprStyle,MsgDoc) -> IO ()
     writeLogQueue (LogQueue ref sem) msg = do
-        atomicModifyIORef ref $ \msgs -> (msg:msgs,())
+        atomicModifyIORef' ref $ \msgs -> (msg:msgs,())
         _ <- tryPutMVar sem ()
         return ()
 
@@ -837,7 +894,7 @@ parUpsweep n_jobs old_hpt stable_mods cleanup sccs = do
     printLogs !dflags (LogQueue ref sem) = read_msgs
       where read_msgs = do
                 takeMVar sem
-                msgs <- atomicModifyIORef ref $ \xs -> ([], reverse xs)
+                msgs <- atomicModifyIORef' ref $ \xs -> ([], reverse xs)
                 print_loop msgs
 
             print_loop [] = read_msgs
@@ -884,8 +941,8 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_dflags cleanup par_sem
 
     -- All the textual imports of this module.
     let textual_deps = Set.fromList $ mapFst (mkModule (thisPackage lcl_dflags)) $
-                            zip home_imps     (repeat False) ++
-                            zip home_src_imps (repeat True)
+                            zip home_imps     (repeat NotBoot) ++
+                            zip home_src_imps (repeat IsBoot)
 
     -- Dealing with module loops
     -- ~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -989,7 +1046,7 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_dflags cleanup par_sem
 
                 -- Prune the old HPT unless this is an hs-boot module.
                 unless (isBootSummary mod) $
-                    atomicModifyIORef old_hpt_var $ \old_hpt ->
+                    atomicModifyIORef' old_hpt_var $ \old_hpt ->
                         (delFromUFM old_hpt this_mod, ())
 
                 -- Update and fetch the global HscEnv.
@@ -1058,8 +1115,8 @@ upsweep old_hpt stable_mods cleanup sccs = do
 
   upsweep' old_hpt done
      (AcyclicSCC mod:mods) mod_index nmods
-   = do -- putStrLn ("UPSWEEP_MOD: hpt = " ++ 
-        --           show (map (moduleUserString.moduleName.mi_module.hm_iface) 
+   = do -- putStrLn ("UPSWEEP_MOD: hpt = " ++
+        --           show (map (moduleUserString.moduleName.mi_module.hm_iface)
         --                     (moduleEnvElts (hsc_HPT hsc_env)))
         let logger _mod = defaultWarnErrLogger
 
@@ -1104,6 +1161,15 @@ upsweep old_hpt stable_mods cleanup sccs = do
 
                 upsweep' old_hpt1 done' mods (mod_index+1) nmods
 
+maybeGetIfaceDate :: DynFlags -> ModLocation -> IO (Maybe UTCTime)
+maybeGetIfaceDate dflags location
+ | writeInterfaceOnlyMode dflags
+    -- Minor optimization: it should be harmless to check the hi file location
+    -- always, but it's better to avoid hitting the filesystem if possible.
+    = modificationTimeIfExists (ml_hi_file location)
+ | otherwise
+    = return Nothing
+
 -- | Compile a single module.  Always produce a Linkable for it if
 -- successful.  If no compilation happened, return the old Linkable.
 upsweep_mod :: HscEnv
@@ -1114,10 +1180,11 @@ upsweep_mod :: HscEnv
             -> Int  -- total number of modules
             -> IO HomeModInfo
 upsweep_mod hsc_env old_hpt (stable_obj, stable_bco) summary mod_index nmods
-   =    let 
+   =    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)
             hs_date     = ms_hs_date summary
 
@@ -1140,7 +1207,7 @@ upsweep_mod hsc_env old_hpt (stable_obj, stable_bco) summary mod_index nmods
                         && (not (isObjectTarget prevailing_target)
                             || not (isObjectTarget local_target))
                         then prevailing_target
-                        else local_target 
+                        else local_target
 
             -- store the corrected hscTarget into the summary
             summary' = summary{ ms_hspp_opts = dflags { hscTarget = target } }
@@ -1153,14 +1220,14 @@ upsweep_mod hsc_env old_hpt (stable_obj, stable_bco) summary mod_index nmods
             -- real source file on the second iteration of the compilation
             -- manager, but that does no harm.  Otherwise the hs-boot file
             -- will always be recompiled
-            
-            mb_old_iface 
+
+            mb_old_iface
                 = case old_hmi of
                      Nothing                              -> Nothing
                      Just hm_info | isBootSummary summary -> Just iface
                                   | not (mi_boot iface)   -> Just iface
                                   | otherwise             -> Nothing
-                                   where 
+                                   where
                                      iface = hm_iface hm_info
 
             compile_it :: Maybe Linkable -> SourceModified -> IO HomeModInfo
@@ -1255,11 +1322,26 @@ upsweep_mod hsc_env old_hpt (stable_obj, stable_bco) summary mod_index nmods
                           linkable <- liftIO $ findObjectLinkable this_mod obj_fn obj_date
                           compile_it_discard_iface (Just linkable) SourceUnmodified
 
+          -- See Note [Recompilation checking when typechecking only]
+          | writeInterfaceOnlyMode dflags,
+            Just if_date <- mb_if_date,
+            if_date >= hs_date -> do
+                liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5
+                           (text "skipping tc'd mod:" <+> ppr this_mod_name)
+                compile_it Nothing SourceUnmodified
+
          _otherwise -> do
                 liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5
                            (text "compiling mod:" <+> ppr this_mod_name)
                 compile_it Nothing SourceModified
 
+-- Note [Recompilation checking when typechecking only]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- If we are compiling with -fno-code -fwrite-interface, there won't
+-- be any object code that we can compare against, nor should there
+-- be: we're *just* generating interface files.  In this case, we
+-- want to check if the interface file is new, in lieu of the object
+-- file.  See also Trac #9243.
 
 
 -- Filter modules in the HPT
@@ -1303,7 +1385,8 @@ Following this fix, GHC can compile itself with --make -O2.
 reTypecheckLoop :: HscEnv -> ModSummary -> ModuleGraph -> IO HscEnv
 reTypecheckLoop hsc_env ms graph
   | Just loop <- getModLoop ms graph
-  = typecheckLoop (hsc_dflags hsc_env) hsc_env (map ms_mod_name loop)
+  , let non_boot = filter (not.isBootSummary) loop
+  = typecheckLoop (hsc_dflags hsc_env) hsc_env (map ms_mod_name non_boot)
   | otherwise
   = return hsc_env
 
@@ -1312,8 +1395,7 @@ getModLoop ms graph
   | not (isBootSummary ms)
   , any (\m -> ms_mod m == this_mod && isBootSummary m) graph
   , let mss = reachableBackwards (ms_mod_name ms) graph
-  , let non_boot = filter (not.isBootSummary) mss
-  = Just non_boot
+  = Just mss
   | otherwise
   = Nothing
  where
@@ -1326,9 +1408,9 @@ typecheckLoop dflags hsc_env mods = do
   new_hpt <-
     fixIO $ \new_hpt -> do
       let new_hsc_env = hsc_env{ hsc_HPT = new_hpt }
-      mds <- initIfaceCheck new_hsc_env $ 
+      mds <- initIfaceCheck new_hsc_env $
                 mapM (typecheckIface . hm_iface) hmis
-      let new_hpt = addListToUFM old_hpt 
+      let new_hpt = addListToUFM old_hpt
                         (zip mods [ hmi{ hm_details = details }
                                   | (hmi,details) <- zip hmis mds ])
       return new_hpt
@@ -1342,7 +1424,7 @@ reachableBackwards mod summaries
   = [ ms | (ms,_,_) <- reachableG (transposeG graph) root ]
   where -- the rest just sets up the graph:
         (graph, lookup_node) = moduleGraphNodes False summaries
-        root  = expectJust "reachableBackwards" (lookup_node HsBootFile mod)
+        root  = expectJust "reachableBackwards" (lookup_node IsBoot mod)
 
 -- ---------------------------------------------------------------------------
 --
@@ -1360,7 +1442,7 @@ topSortModuleGraph
 -- dependency graph (ie compile them first) and ending with the ones at
 -- the top.
 --
--- Drop hi-boot nodes (first boolean arg)? 
+-- Drop hi-boot nodes (first boolean arg)?
 --
 -- - @False@:   treat the hi-boot summaries as nodes of the graph,
 --              so the graph must be acyclic
@@ -1373,7 +1455,7 @@ topSortModuleGraph drop_hs_boot_nodes summaries mb_root_mod
   = map (fmap summaryNodeSummary) $ stronglyConnCompG initial_graph
   where
     (graph, lookup_node) = moduleGraphNodes drop_hs_boot_nodes summaries
-    
+
     initial_graph = case mb_root_mod of
         Nothing -> graph
         Just root_mod ->
@@ -1381,7 +1463,8 @@ topSortModuleGraph drop_hs_boot_nodes summaries mb_root_mod
             -- the specified module.  We do this by building a graph with
             -- the full set of nodes, and determining the reachable set from
             -- the specified node.
-            let root | Just node <- lookup_node HsSrcFile root_mod, graph `hasVertexG` node = node
+            let root | Just node <- lookup_node NotBoot root_mod
+                     , graph `hasVertexG` node = node
                      | otherwise = throwGhcException (ProgramError "module does not exist")
             in graphFromEdgedVertices (seq root (reachableG graph root))
 
@@ -1394,35 +1477,48 @@ summaryNodeSummary :: SummaryNode -> ModSummary
 summaryNodeSummary (s, _, _) = s
 
 moduleGraphNodes :: Bool -> [ModSummary]
-  -> (Graph SummaryNode, HscSource -> ModuleName -> Maybe SummaryNode)
+  -> (Graph SummaryNode, IsBoot -> ModuleName -> Maybe SummaryNode)
 moduleGraphNodes drop_hs_boot_nodes summaries = (graphFromEdgedVertices nodes, lookup_node)
   where
     numbered_summaries = zip summaries [1..]
 
-    lookup_node :: HscSource -> ModuleName -> Maybe SummaryNode
-    lookup_node hs_src mod = Map.lookup (mod, hs_src) node_map
+    lookup_node :: IsBoot -> ModuleName -> Maybe SummaryNode
+    lookup_node is_boot mod = Map.lookup (mod, is_boot) node_map
 
-    lookup_key :: HscSource -> ModuleName -> Maybe Int
-    lookup_key hs_src mod = fmap summaryNodeKey (lookup_node hs_src mod)
+    lookup_key :: IsBoot -> ModuleName -> Maybe Int
+    lookup_key is_boot mod = fmap summaryNodeKey (lookup_node is_boot mod)
 
     node_map :: NodeMap SummaryNode
-    node_map = Map.fromList [ ((moduleName (ms_mod s), ms_hsc_src s), node)
+    node_map = Map.fromList [ ((moduleName (ms_mod s),
+                                hscSourceToIsBoot (ms_hsc_src s)), node)
                             | node@(s, _, _) <- nodes ]
 
+    hasImplSet :: Set.Set ModuleName
+    hasImplSet = Set.fromList [ ms_mod_name s
+                              | s <- summaries, ms_hsc_src s == HsSrcFile ]
+
+    hasImpl :: ModuleName -> Bool
+    hasImpl modname = modname `Set.member` hasImplSet
+
     -- We use integers as the keys for the SCC algorithm
     nodes :: [SummaryNode]
     nodes = [ (s, key, out_keys)
             | (s, key) <- numbered_summaries
              -- Drop the hi-boot ones if told to do so
-            , not (isBootSummary s && drop_hs_boot_nodes)
-            , let out_keys = out_edge_keys hs_boot_key (map unLoc (ms_home_srcimps s)) ++
-                             out_edge_keys HsSrcFile   (map unLoc (ms_home_imps s)) ++
-                             (-- see [boot-edges] below
-                              if drop_hs_boot_nodes || ms_hsc_src s == HsBootFile 
-                              then [] 
-                              else case lookup_key HsBootFile (ms_mod_name s) of
-                                    Nothing -> []
-                                    Just k  -> [k]) ]
+            , not (isBootSummary s && hasImpl (ms_mod_name s)
+                                   && drop_hs_boot_nodes)
+            , let out_keys
+                    = out_edge_keys IsBoot  (map unLoc (ms_home_srcimps s)) ++
+                      out_edge_keys NotBoot (map unLoc (ms_home_imps s)) ++
+                      (if fst (ms_merge_imps s)
+                        then out_edge_keys IsBoot [moduleName (ms_mod s)]
+                        else []) ++
+                      (-- see [boot-edges] below
+                       if drop_hs_boot_nodes || ms_hsc_src s /= HsSrcFile
+                       then []
+                       else case lookup_key IsBoot (ms_mod_name s) of
+                             Nothing -> []
+                             Just k  -> [k]) ]
 
     -- [boot-edges] if this is a .hs and there is an equivalent
     -- .hs-boot, add a link from the former to the latter.  This
@@ -1432,25 +1528,29 @@ moduleGraphNodes drop_hs_boot_nodes summaries = (graphFromEdgedVertices nodes, l
     -- the .hs, and so the HomePackageTable will always have the
     -- most up to date information.
 
-    -- Drop hs-boot nodes by using HsSrcFile as the key
-    hs_boot_key | drop_hs_boot_nodes = HsSrcFile
-                | otherwise          = HsBootFile
+    out_edge_keys :: IsBoot -> [ModuleName] -> [Int]
+    out_edge_keys hi_boot ms = mapMaybe (lookup_out_edge_key hi_boot) ms
 
-    out_edge_keys :: HscSource -> [ModuleName] -> [Int]
-    out_edge_keys hi_boot ms = mapCatMaybes (lookup_key hi_boot) ms
+    lookup_out_edge_key :: IsBoot -> ModuleName -> Maybe Int
+    lookup_out_edge_key hi_boot m
+        | hasImpl m, drop_hs_boot_nodes = lookup_key NotBoot m
+        | otherwise                     = lookup_key hi_boot m
         -- If we want keep_hi_boot_nodes, then we do lookup_key with
-        -- the IsBootInterface parameter True; else False
+        -- IsBoot; else NotBoot
 
-
-type NodeKey   = (ModuleName, HscSource)  -- The nodes of the graph are 
-type NodeMap a = Map.Map NodeKey a        -- keyed by (mod, src_file_type) pairs
+-- The nodes of the graph are keyed by (mod, is boot?) pairs
+-- NB: hsig files show up as *normal* nodes (not boot!), since they don't
+-- participate in cycles (for now)
+type NodeKey   = (ModuleName, IsBoot)
+type NodeMap a = Map.Map NodeKey a
 
 msKey :: ModSummary -> NodeKey
-msKey (ModSummary { ms_mod = mod, ms_hsc_src = boot }) = (moduleName mod,boot)
+msKey (ModSummary { ms_mod = mod, ms_hsc_src = boot })
+    = (moduleName mod, hscSourceToIsBoot boot)
 
 mkNodeMap :: [ModSummary] -> NodeMap ModSummary
 mkNodeMap summaries = Map.fromList [ (msKey s, s) | s <- summaries]
-        
+
 nodeMapElts :: NodeMap a -> [a]
 nodeMapElts = Map.elems
 
@@ -1461,7 +1561,8 @@ nodeMapElts = Map.elems
 warnUnnecessarySourceImports :: GhcMonad m => [SCC ModSummary] -> m ()
 warnUnnecessarySourceImports sccs = do
   dflags <- getDynFlags
-  logWarnings (listToBag (concatMap (check dflags . flattenSCC) sccs))
+  when (wopt Opt_WarnUnusedImports dflags)
+    (logWarnings (listToBag (concatMap (check dflags . flattenSCC) sccs)))
   where check dflags ms =
            let mods_in_this_cycle = map ms_mod_name ms in
            [ warn dflags i | m <- ms, i <- ms_home_srcimps m,
@@ -1473,6 +1574,16 @@ warnUnnecessarySourceImports sccs = do
                 (ptext (sLit "Warning: {-# SOURCE #-} unnecessary in import of ")
                  <+> quotes (ppr mod))
 
+
+reportImportErrors :: MonadIO m => [Either ErrMsg b] -> m [b]
+reportImportErrors xs | null errs = return oks
+                      | otherwise = throwManyErrors errs
+  where (errs, oks) = partitionEithers xs
+
+throwManyErrors :: MonadIO m => [ErrMsg] -> m ab
+throwManyErrors errs = liftIO $ throwIO $ mkSrcErr $ listToBag errs
+
+
 -----------------------------------------------------------------------------
 --
 -- | Downsweep (dependency analysis)
@@ -1486,47 +1597,58 @@ warnUnnecessarySourceImports sccs = do
 -- unchanged.
 --
 -- The returned list of [ModSummary] nodes has one node for each home-package
--- module, plus one for any hs-boot files.  The imports of these nodes 
+-- module, plus one for any hs-boot files.  The imports of these nodes
 -- are all there, including the imports of non-home-package modules.
 downsweep :: HscEnv
           -> [ModSummary]       -- Old summaries
           -> [ModuleName]       -- Ignore dependencies on these; treat
                                 -- them as if they were package modules
-          -> Bool               -- True <=> allow multiple targets to have 
-                                --          the same module name; this is 
+          -> Bool               -- True <=> allow multiple targets to have
+                                --          the same module name; this is
                                 --          very useful for ghc -M
-          -> IO [ModSummary]
+          -> IO [Either ErrMsg ModSummary]
                 -- The elts of [ModSummary] all have distinct
                 -- (Modules, IsBoot) identifiers, unless the Bool is true
                 -- in which case there can be repeats
 downsweep hsc_env old_summaries excl_mods allow_dup_roots
    = do
        rootSummaries <- mapM getRootSummary roots
-       let root_map = mkRootMap rootSummaries
+       rootSummariesOk <- reportImportErrors rootSummaries
+       let root_map = mkRootMap rootSummariesOk
        checkDuplicates root_map
-       summs <- loop (concatMap msDeps rootSummaries) root_map
+       summs <- loop (concatMap calcDeps rootSummariesOk) root_map
        return summs
      where
+        -- When we're compiling a signature file, we have an implicit
+        -- dependency on what-ever the signature's implementation is.
+        -- (But not when we're type checking!)
+        calcDeps summ
+          | HsBootFile <- ms_hsc_src summ
+          , Just m <- getSigOf (hsc_dflags hsc_env) (moduleName (ms_mod summ))
+          , modulePackageKey m == thisPackage (hsc_dflags hsc_env)
+                      = (noLoc (moduleName m), NotBoot) : msDeps summ
+          | otherwise = msDeps summ
+
         dflags = hsc_dflags hsc_env
         roots = hsc_targets hsc_env
 
         old_summary_map :: NodeMap ModSummary
         old_summary_map = mkNodeMap old_summaries
 
-        getRootSummary :: Target -> IO ModSummary
+        getRootSummary :: Target -> IO (Either ErrMsg ModSummary)
         getRootSummary (Target (TargetFile file mb_phase) obj_allowed maybe_buf)
            = do exists <- liftIO $ doesFileExist file
-                if exists 
-                    then summariseFile hsc_env old_summaries file mb_phase 
+                if exists
+                    then Right `fmap` summariseFile hsc_env old_summaries file mb_phase
                                        obj_allowed maybe_buf
-                    else throwOneError $ mkPlainErrMsg dflags noSrcSpan $
+                    else return $ Left $ mkPlainErrMsg dflags noSrcSpan $
                            text "can't find file:" <+> text file
         getRootSummary (Target (TargetModule modl) obj_allowed maybe_buf)
-           = do maybe_summary <- summariseModule hsc_env old_summary_map False 
-                                           (L rootLoc modl) obj_allowed 
+           = do maybe_summary <- summariseModule hsc_env old_summary_map NotBoot
+                                           (L rootLoc modl) obj_allowed
                                            maybe_buf excl_mods
                 case maybe_summary of
-                   Nothing -> packageModErr dflags modl
+                   Nothing -> return $ Left $ packageModErr dflags modl
                    Just s  -> return s
 
         rootLoc = mkGeneralSrcSpan (fsLit "<command line>")
@@ -1535,44 +1657,46 @@ downsweep hsc_env old_summaries excl_mods allow_dup_roots
         -- name, so we have to check that there aren't multiple root files
         -- defining the same module (otherwise the duplicates will be silently
         -- ignored, leading to confusing behaviour).
-        checkDuplicates :: NodeMap [ModSummary] -> IO ()
-        checkDuplicates root_map 
+        checkDuplicates :: NodeMap [Either ErrMsg ModSummary] -> IO ()
+        checkDuplicates root_map
            | allow_dup_roots = return ()
            | null dup_roots  = return ()
            | otherwise       = liftIO $ multiRootsErr dflags (head dup_roots)
            where
              dup_roots :: [[ModSummary]]        -- Each at least of length 2
-             dup_roots = filterOut isSingleton (nodeMapElts root_map)
+             dup_roots = filterOut isSingleton $ map rights $ nodeMapElts root_map
 
-        loop :: [(Located ModuleName,IsBootInterface)]
+        loop :: [(Located ModuleName,IsBoot)]
                         -- Work list: process these modules
-             -> NodeMap [ModSummary]
+             -> NodeMap [Either ErrMsg ModSummary]
                         -- Visited set; the range is a list because
                         -- the roots can have the same module names
                         -- if allow_dup_roots is True
-             -> IO [ModSummary]
+             -> IO [Either ErrMsg ModSummary]
                         -- The result includes the worklist, except
                         -- for those mentioned in the visited set
         loop [] done      = return (concat (nodeMapElts done))
-        loop ((wanted_mod, is_boot) : ss) done 
+        loop ((wanted_mod, is_boot) : ss) done
           | Just summs <- Map.lookup key done
           = if isSingleton summs then
                 loop ss done
             else
-                do { multiRootsErr dflags summs; return [] }
+                do { multiRootsErr dflags (rights summs); return [] }
           | otherwise
-          = do mb_s <- summariseModule hsc_env old_summary_map 
+          = do mb_s <- summariseModule hsc_env old_summary_map
                                        is_boot wanted_mod True
                                        Nothing excl_mods
                case mb_s of
                    Nothing -> loop ss done
-                   Just s  -> loop (msDeps s ++ ss) (Map.insert key [s] done)
+                   Just (Left e) -> loop ss (Map.insert key [Left e] done)
+                   Just (Right s)-> loop (calcDeps s ++ ss)
+                                         (Map.insert key [Right s] done)
           where
-            key = (unLoc wanted_mod, if is_boot then HsBootFile else HsSrcFile)
+            key = (unLoc wanted_mod, is_boot)
 
-mkRootMap :: [ModSummary] -> NodeMap [ModSummary]
+mkRootMap :: [ModSummary] -> NodeMap [Either ErrMsg ModSummary]
 mkRootMap summaries = Map.insertListWith (flip (++))
-                                         [ (msKey s, [s]) | s <- summaries ]
+                                         [ (msKey s, [Right s]) | s <- summaries ]
                                          Map.empty
 
 -- | Returns the dependencies of the ModSummary s.
@@ -1583,13 +1707,20 @@ mkRootMap summaries = Map.insertListWith (flip (++))
 -- modules always contains B.hs if it contains B.hs-boot.
 -- Remember, this pass isn't doing the topological sort.  It's
 -- just gathering the list of all relevant ModSummaries
-msDeps :: ModSummary -> [(Located ModuleName, IsBootInterface)]
-msDeps s = 
-    concat [ [(m,True), (m,False)] | m <- ms_home_srcimps s ] 
-         ++ [ (m,False) | m <- ms_home_imps s ] 
-
-home_imps :: [Located (ImportDecl RdrName)] -> [Located ModuleName]
-home_imps imps = [ ideclName i |  L _ i <- imps, isLocal (ideclPkgQual i) ]
+--
+-- NB: for signatures, (m,NotBoot) is "special"; the Haskell file
+-- may not exist; we just synthesize it ourselves.
+msDeps :: ModSummary -> [(Located ModuleName, IsBoot)]
+msDeps s =
+    concat [ [(m,IsBoot), (m,NotBoot)] | m <- ms_home_srcimps s ]
+        ++ [ (m,NotBoot) | m <- ms_home_imps s ]
+        ++ if fst (ms_merge_imps s)
+            then [ (noLoc (moduleName (ms_mod s)), IsBoot) ]
+            else []
+
+home_imps :: [(Maybe FastString, Located ModuleName)] -> [Located ModuleName]
+home_imps imps = [ lmodname |  (mb_pkg, lmodname) <- imps,
+                                  isLocal mb_pkg ]
   where isLocal Nothing = True
         isLocal (Just pkg) | pkg == fsLit "this" = True -- "this" is special
         isLocal _ = False
@@ -1632,22 +1763,26 @@ summariseFile hsc_env old_summaries file mb_phase obj_allowed maybe_buf
    | Just old_summary <- findSummaryBySourceFile old_summaries file
    = do
         let location = ms_location old_summary
+            dflags = hsc_dflags hsc_env
 
         src_timestamp <- get_src_timestamp
                 -- The file exists; we checked in getRootSummary above.
-                -- If it gets removed subsequently, then this 
+                -- If it gets removed subsequently, then this
                 -- getModificationUTCTime may fail, but that's the right
                 -- behaviour.
 
                 -- return the cached summary if the source didn't change
-        if ms_hs_date old_summary == src_timestamp
+        if ms_hs_date old_summary == src_timestamp &&
+           not (gopt Opt_ForceRecomp (hsc_dflags hsc_env))
            then do -- update the object-file timestamp
                   obj_timestamp <-
-                    if isObjectTarget (hscTarget (hsc_dflags hsc_env)) 
+                    if isObjectTarget (hscTarget (hsc_dflags hsc_env))
                         || obj_allowed -- bug #1205
-                        then liftIO $ getObjTimestamp location False
+                        then liftIO $ getObjTimestamp location NotBoot
                         else return Nothing
-                  return old_summary{ ms_obj_date = obj_timestamp }
+                  hi_timestamp <- maybeGetIfaceDate dflags location
+                  return old_summary{ ms_obj_date = obj_timestamp
+                                    , ms_iface_date = hi_timestamp }
            else
                 new_summary src_timestamp
 
@@ -1678,18 +1813,25 @@ summariseFile hsc_env old_summaries file mb_phase obj_allowed maybe_buf
         -- when the user asks to load a source file by name, we only
         -- use an object file if -fobject-code is on.  See #1205.
         obj_timestamp <-
-            if isObjectTarget (hscTarget (hsc_dflags hsc_env)) 
+            if isObjectTarget (hscTarget (hsc_dflags hsc_env))
                || obj_allowed -- bug #1205
                 then liftIO $ modificationTimeIfExists (ml_obj_file location)
                 else return Nothing
 
-        return (ModSummary { ms_mod = mod, ms_hsc_src = HsSrcFile,
+        hi_timestamp <- maybeGetIfaceDate dflags location
+
+        return (ModSummary { ms_mod = mod,
+                             ms_hsc_src = if "boot" `isSuffixOf` file
+                                            then HsBootFile
+                                            else HsSrcFile,
                              ms_location = location,
                              ms_hspp_file = hspp_fn,
                              ms_hspp_opts = dflags',
                              ms_hspp_buf  = Just buf,
                              ms_srcimps = srcimps, ms_textual_imps = the_imps,
+                             ms_merge_imps = (False, []),
                              ms_hs_date = src_timestamp,
+                             ms_iface_date = hi_timestamp,
                              ms_obj_date = obj_timestamp })
 
 findSummaryBySourceFile :: [ModSummary] -> FilePath -> Maybe ModSummary
@@ -1703,20 +1845,20 @@ findSummaryBySourceFile summaries file
 summariseModule
           :: HscEnv
           -> NodeMap ModSummary -- Map of old summaries
-          -> IsBootInterface    -- True <=> a {-# SOURCE #-} import
+          -> IsBoot             -- IsBoot <=> a {-# SOURCE #-} import
           -> Located ModuleName -- Imported module to be summarised
           -> Bool               -- object code allowed?
           -> Maybe (StringBuffer, UTCTime)
           -> [ModuleName]               -- Modules to exclude
-          -> IO (Maybe ModSummary)      -- Its new summary
+          -> IO (Maybe (Either ErrMsg ModSummary))      -- Its new summary
 
-summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod) 
+summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod)
                 obj_allowed maybe_buf excl_mods
   | wanted_mod `elem` excl_mods
   = return Nothing
 
-  | Just old_summary <- Map.lookup (wanted_mod, hsc_src) old_summary_map
-  = do          -- Find its new timestamp; all the 
+  | Just old_summary <- Map.lookup (wanted_mod, is_boot) old_summary_map
+  = do          -- Find its new timestamp; all the
                 -- ModSummaries in the old map have valid ml_hs_files
         let location = ms_location old_summary
             src_fn = expectJust "summariseModule" (ml_hs_file location)
@@ -1733,22 +1875,34 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod)
                    Left e | isDoesNotExistError e -> find_it
                           | otherwise             -> ioError e
 
+  | NotBoot <- is_boot
+  , Just _ <- getSigOf dflags wanted_mod
+  = do mod_summary0 <- makeMergeRequirementSummary hsc_env
+                                                   obj_allowed
+                                                   wanted_mod
+       hi_timestamp <- maybeGetIfaceDate dflags (ms_location mod_summary0)
+       let mod_summary = mod_summary0 {
+            ms_iface_date = hi_timestamp
+            }
+       return (Just (Right mod_summary))
+
   | otherwise  = find_it
   where
     dflags = hsc_dflags hsc_env
 
-    hsc_src = if is_boot then HsBootFile else HsSrcFile
-
     check_timestamp old_summary location src_fn src_timestamp
-        | ms_hs_date old_summary == src_timestamp = do
+        | ms_hs_date old_summary == src_timestamp &&
+          not (gopt Opt_ForceRecomp dflags) = do
                 -- update the object-file timestamp
-                obj_timestamp <- 
+                obj_timestamp <-
                     if isObjectTarget (hscTarget (hsc_dflags hsc_env))
                        || obj_allowed -- bug #1205
                        then getObjTimestamp location is_boot
                        else return Nothing
-                return (Just old_summary{ ms_obj_date = obj_timestamp })
-        | otherwise = 
+                hi_timestamp <- maybeGetIfaceDate dflags location
+                return (Just (Right old_summary{ ms_obj_date = obj_timestamp
+                                               , ms_iface_date = hi_timestamp}))
+        | otherwise =
                 -- source changed: re-summarise.
                 new_summary location (ms_mod old_summary) src_fn src_timestamp
 
@@ -1760,30 +1914,30 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod)
         uncacheModule hsc_env wanted_mod
         found <- findImportedModule hsc_env wanted_mod Nothing
         case found of
-             Found location mod 
+             Found location mod
                 | isJust (ml_hs_file location) ->
                         -- Home package
                          just_found location mod
-                | otherwise -> 
+                | otherwise ->
                         -- Drop external-pkg
-                        ASSERT(modulePackageId mod /= thisPackage dflags)
+                        ASSERT(modulePackageKey mod /= thisPackage dflags)
                         return Nothing
-                        
-             err -> noModError dflags loc wanted_mod err
+
+             err -> return $ Just $ Left $ noModError dflags loc wanted_mod err
                         -- Not found
 
     just_found location mod = do
-                -- Adjust location to point to the hs-boot source file, 
+                -- Adjust location to point to the hs-boot source file,
                 -- hi file, object file, when is_boot says so
-        let location' | is_boot   = addBootSuffixLocn location
-                      | otherwise = location
+        let location' | IsBoot <- is_boot = addBootSuffixLocn location
+                      | otherwise         = location
             src_fn = expectJust "summarise2" (ml_hs_file location')
 
                 -- Check that it exists
                 -- It might have been deleted since the Finder last found it
         maybe_t <- modificationTimeIfExists src_fn
         case maybe_t of
-          Nothing -> noHsFileErr dflags loc src_fn
+          Nothing -> return $ Just $ Left $ noHsFileErr dflags loc src_fn
           Just t  -> new_summary location' mod src_fn t
 
 
@@ -1794,9 +1948,14 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod)
         (dflags', hspp_fn, buf) <- preprocessFile hsc_env src_fn Nothing maybe_buf
         (srcimps, the_imps, L mod_loc mod_name) <- getImports dflags' buf hspp_fn src_fn
 
+        let hsc_src =
+                case is_boot of
+                    IsBoot  -> HsBootFile
+                    NotBoot -> HsSrcFile
+
         when (mod_name /= wanted_mod) $
                 throwOneError $ mkPlainErrMsg dflags' mod_loc $
-                              text "File name does not match module name:" 
+                              text "File name does not match module name:"
                               $$ text "Saw:" <+> quotes (ppr mod_name)
                               $$ text "Expected:" <+> quotes (ppr wanted_mod)
 
@@ -1807,7 +1966,9 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod)
               then getObjTimestamp location is_boot
               else return Nothing
 
-        return (Just (ModSummary { ms_mod       = mod,
+        hi_timestamp <- maybeGetIfaceDate dflags location
+
+        return (Just (Right (ModSummary { ms_mod       = mod,
                               ms_hsc_src   = hsc_src,
                               ms_location  = location,
                               ms_hspp_file = hspp_fn,
@@ -1815,14 +1976,16 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod)
                               ms_hspp_buf  = Just buf,
                               ms_srcimps      = srcimps,
                               ms_textual_imps = the_imps,
+                              ms_merge_imps = (False, []),
                               ms_hs_date   = src_timestamp,
-                              ms_obj_date  = obj_timestamp }))
+                              ms_iface_date = hi_timestamp,
+                              ms_obj_date  = obj_timestamp })))
 
 
-getObjTimestamp :: ModLocation -> Bool -> IO (Maybe UTCTime)
+getObjTimestamp :: ModLocation -> IsBoot -> IO (Maybe UTCTime)
 getObjTimestamp location is_boot
-  = if is_boot then return Nothing
-               else modificationTimeIfExists (ml_obj_file location)
+  = if is_boot == IsBoot then return Nothing
+                         else modificationTimeIfExists (ml_obj_file location)
 
 
 preprocessFile :: HscEnv
@@ -1864,25 +2027,25 @@ preprocessFile hsc_env src_fn mb_phase (Just (buf, _time))
 --                      Error messages
 -----------------------------------------------------------------------------
 
-noModError :: DynFlags -> SrcSpan -> ModuleName -> FindResult -> IO ab
+noModError :: DynFlags -> SrcSpan -> ModuleName -> FindResult -> ErrMsg
 -- ToDo: we don't have a proper line number for this error
 noModError dflags loc wanted_mod err
-  = throwOneError $ mkPlainErrMsg dflags loc $ cannotFindModule dflags wanted_mod err
-                                
-noHsFileErr :: DynFlags -> SrcSpan -> String -> IO a
+  = mkPlainErrMsg dflags loc $ cannotFindModule dflags wanted_mod err
+
+noHsFileErr :: DynFlags -> SrcSpan -> String -> ErrMsg
 noHsFileErr dflags loc path
-  = throwOneError $ mkPlainErrMsg dflags loc $ text "Can't find" <+> text path
-packageModErr :: DynFlags -> ModuleName -> IO a
+  = mkPlainErrMsg dflags loc $ text "Can't find" <+> text path
+
+packageModErr :: DynFlags -> ModuleName -> ErrMsg
 packageModErr dflags mod
-  = throwOneError $ mkPlainErrMsg dflags noSrcSpan $
+  = mkPlainErrMsg dflags noSrcSpan $
         text "module" <+> quotes (ppr mod) <+> text "is a package module"
 
 multiRootsErr :: DynFlags -> [ModSummary] -> IO ()
 multiRootsErr _      [] = panic "multiRootsErr"
 multiRootsErr dflags summs@(summ1:_)
   = throwOneError $ mkPlainErrMsg dflags noSrcSpan $
-        text "module" <+> quotes (ppr mod) <+> 
+        text "module" <+> quotes (ppr mod) <+>
         text "is defined in multiple files:" <+>
         sep (map text files)
   where
@@ -1890,7 +2053,7 @@ multiRootsErr dflags summs@(summ1:_)
     files = map (expectJust "checkDup" . ml_hs_file . ms_location) summs
 
 cyclicModuleErr :: [ModSummary] -> SDoc
--- From a strongly connected component we find 
+-- From a strongly connected component we find
 -- a single cycle to report
 cyclicModuleErr mss
   = ASSERT( not (null mss) )
@@ -1903,8 +2066,8 @@ cyclicModuleErr mss
     graph = [(ms, msKey ms, get_deps ms) | ms <- mss]
 
     get_deps :: ModSummary -> [NodeKey]
-    get_deps ms = ([ (unLoc m, HsBootFile) | m <- ms_home_srcimps ms ] ++
-                   [ (unLoc m, HsSrcFile)  | m <- ms_home_imps    ms ])
+    get_deps ms = ([ (unLoc m, IsBoot)  | m <- ms_home_srcimps ms ] ++
+                   [ (unLoc m, NotBoot) | m <- ms_home_imps    ms ])
 
     show_path []         = panic "show_path"
     show_path [m]        = ptext (sLit "module") <+> ppr_ms m
@@ -1915,9 +2078,10 @@ cyclicModuleErr mss
        where
          go []     = [ptext (sLit "which imports") <+> ppr_ms m1]
          go (m:ms) = (ptext (sLit "which imports") <+> ppr_ms m) : go ms
-       
 
-    ppr_ms :: ModSummary -> SDoc
-    ppr_ms ms = quotes (ppr (moduleName (ms_mod ms))) <+> 
-                (parens (text (msHsFilePath ms)))
 
+    ppr_ms :: ModSummary -> SDoc
+    ppr_ms ms = quotes (ppr (moduleName (ms_mod ms))) <+>
+                case msHsFilePath ms of
+                    Just path -> parens (text path)
+                    Nothing -> empty