[project @ 2001-02-26 16:43:31 by simonmar]
[ghc-hetmet.git] / ghc / compiler / compMan / CompManager.lhs
index befb5b3..ad14b26 100644 (file)
@@ -4,12 +4,19 @@
 \section[CompManager]{The Compilation Manager}
 
 \begin{code}
-module CompManager ( cmInit, cmLoadModule, cmUnload,
+module CompManager ( 
+    cmInit,      -- :: GhciMode -> IO CmState
+    cmLoadModule, -- :: CmState -> FilePath -> IO (CmState, [String])
+    cmUnload,    -- :: CmState -> IO CmState
+    cmTypeOfName, -- :: CmState -> Name -> IO (Maybe String)
+
+    cmSetContext, -- :: CmState -> String -> IO CmState
+    cmGetContext, -- :: CmState -> IO String
 #ifdef GHCI
-                     cmGetExpr, cmRunExpr,
+    cmRunStmt,   --  :: CmState -> DynFlags -> String -> IO (CmState, [Name])
 #endif
-                     CmState, emptyCmState  -- abstract
-                   )
+    CmState, emptyCmState  -- abstract
+  )
 where
 
 #include "HsVersions.h"
@@ -17,16 +24,22 @@ where
 import CmLink
 import CmTypes
 import HscTypes
+import RnEnv           ( unQualInScope )
+import Id              ( idType, idName )
+import Name            ( Name, lookupNameEnv, extendNameEnvList, 
+                         NamedThing(..) )
+import RdrName         ( emptyRdrEnv )
 import Module          ( Module, ModuleName, moduleName, isHomeModule,
-                         mkModuleName, moduleNameUserString )
+                         mkModuleName, moduleNameUserString, moduleUserString )
 import CmStaticInfo    ( GhciMode(..) )
 import DriverPipeline
 import GetImports
-import HscTypes                ( HomeSymbolTable, HomeIfaceTable, 
-                         PersistentCompilerState, ModDetails(..) )
+import Type            ( tidyType )
+import VarEnv          ( emptyTidyEnv )
+import HscTypes
 import HscMain         ( initPersistentCompilerState )
 import Finder
-import UniqFM          ( emptyUFM, lookupUFM, addToUFM, delListFromUFM,
+import UniqFM          ( lookupUFM, addToUFM, delListFromUFM,
                          UniqFM, listToUFM )
 import Unique          ( Uniquable )
 import Digraph         ( SCC(..), stronglyConnComp, flattenSCC )
@@ -36,6 +49,7 @@ import DriverUtil     ( splitFilename3 )
 import ErrUtils                ( showPass )
 import Util
 import DriverUtil
+import TmpFiles
 import Outputable
 import Panic
 import CmdLineOpts     ( DynFlags(..) )
@@ -43,8 +57,7 @@ import IOExts
 
 #ifdef GHCI
 import Interpreter     ( HValue )
-import HscMain         ( hscExpr )
-import Type            ( Type )
+import HscMain         ( hscStmt )
 import PrelGHC         ( unsafeCoerce# )
 #endif
 
@@ -62,43 +75,6 @@ import Maybe         ( catMaybes, fromMaybe, isJust, fromJust )
 
 
 \begin{code}
-cmInit :: GhciMode -> IO CmState
-cmInit gmode
-   = emptyCmState gmode
-
-#ifdef GHCI
-cmGetExpr :: CmState
-         -> DynFlags
-         -> Bool       -- True <=> wrap in 'print' to get an IO-typed result
-          -> Module
-          -> String
-          -> IO (CmState, Maybe (HValue, PrintUnqualified, Type))
-cmGetExpr cmstate dflags wrap_io mod expr
-   = do (new_pcs, maybe_stuff) <- 
-          hscExpr dflags wrap_io hst hit pcs mod expr
-        case maybe_stuff of
-          Nothing     -> return (cmstate{ pcs=new_pcs }, Nothing)
-          Just (bcos, print_unqual, ty) -> do
-               hValue <- linkExpr pls bcos
-               return (cmstate{ pcs=new_pcs }, 
-                       Just (hValue, print_unqual, ty))
-
-   -- ToDo: check that the module we passed in is sane/exists?
-   where
-       CmState{ hst=hst, hit=hit, pcs=pcs, pls=pls } = cmstate
-
--- The HValue should represent a value of type IO () (Perhaps IO a?)
-cmRunExpr :: HValue -> IO ()
-cmRunExpr hval
-   = do unsafeCoerce# hval :: IO ()
-       -- putStrLn "done."
-#endif
-
-emptyHIT :: HomeIfaceTable
-emptyHIT = emptyUFM
-emptyHST :: HomeSymbolTable
-emptyHST = emptyUFM
-
 -- Persistent state for the entire system
 data CmState
    = CmState {
@@ -107,23 +83,33 @@ data CmState
         ui    :: UnlinkedImage,      -- the unlinked images
         mg    :: ModuleGraph,        -- the module graph
         gmode :: GhciMode,           -- NEVER CHANGES
+       ic    :: InteractiveContext, -- command-line binding info
 
         pcs    :: PersistentCompilerState, -- compile's persistent state
         pls    :: PersistentLinkerState    -- link's persistent state
      }
 
-emptyCmState :: GhciMode -> IO CmState
-emptyCmState gmode
+emptyCmState :: GhciMode -> Module -> IO CmState
+emptyCmState gmode mod
     = do pcs     <- initPersistentCompilerState
          pls     <- emptyPLS
-         return (CmState { hst = emptyHST,
-                           hit = emptyHIT,
-                           ui  = emptyUI,
-                           mg  = emptyMG, 
-                           gmode = gmode,
+         return (CmState { hst    = emptySymbolTable,
+                           hit    = emptyIfaceTable,
+                           ui     = emptyUI,
+                           mg     = emptyMG, 
+                           gmode  = gmode,
+                          ic     = emptyInteractiveContext mod,
                            pcs    = pcs,
                            pls    = pls })
 
+emptyInteractiveContext mod
+  = InteractiveContext { ic_module = mod, 
+                        ic_rn_env = emptyRdrEnv,
+                        ic_type_env = emptyTypeEnv }
+
+defaultCurrentModuleName = mkModuleName "Prelude"
+GLOBAL_VAR(defaultCurrentModule, error "no defaultCurrentModule", Module)
+
 -- CM internal types
 type UnlinkedImage = [Linkable]        -- the unlinked images (should be a set, really)
 emptyUI :: UnlinkedImage
@@ -133,12 +119,126 @@ type ModuleGraph = [ModSummary]  -- the module graph, topologically sorted
 emptyMG :: ModuleGraph
 emptyMG = []
 
-\end{code}
+-----------------------------------------------------------------------------
+-- Produce an initial CmState.
 
-Unload the compilation manager's state: everything it knows about the
-current collection of modules in the Home package.
+cmInit :: GhciMode -> IO CmState
+cmInit mode = do
+   prel <- moduleNameToModule defaultCurrentModuleName
+   writeIORef defaultCurrentModule prel
+   emptyCmState mode prel
+
+-----------------------------------------------------------------------------
+-- Setting the context doesn't throw away any bindings; the bindings
+-- we've built up in the InteractiveContext simply move to the new
+-- module.  They always shadow anything in scope in the current context.
+
+cmSetContext :: CmState -> String -> IO CmState
+cmSetContext cmstate str
+   = do let mn = mkModuleName str
+           modules_loaded = [ (name_of_summary s, ms_mod s)  | s <- mg cmstate ]
+
+        m <- case lookup mn modules_loaded of
+               Just m  -> return m
+               Nothing -> do
+                  mod <- moduleNameToModule mn
+                  if isHomeModule mod 
+                       then throwDyn (OtherError (showSDoc 
+                               (quotes (ppr (moduleName mod))
+                                 <+> text "is not currently loaded")))
+                       else return mod
+
+       return cmstate{ ic = (ic cmstate){ic_module=m} }
+               
+cmGetContext :: CmState -> IO String
+cmGetContext cmstate = return (moduleUserString (ic_module (ic cmstate)))
+
+moduleNameToModule :: ModuleName -> IO Module
+moduleNameToModule mn
+ = do maybe_stuff <- findModule mn
+      case maybe_stuff of
+       Nothing -> throwDyn (OtherError ("can't find module `"
+                                   ++ moduleNameUserString mn ++ "'"))
+       Just (m,_) -> return m
+
+-----------------------------------------------------------------------------
+-- cmRunStmt:  Run a statement/expr.
+
+#ifdef GHCI
+cmRunStmt :: CmState -> DynFlags -> String -> IO (CmState, [Name])
+cmRunStmt cmstate dflags expr
+   = do 
+       let icontext = ic cmstate
+           InteractiveContext { 
+               ic_rn_env = rn_env, 
+               ic_type_env = type_env,
+               ic_module   = this_mod } = icontext
+
+        (new_pcs, maybe_stuff) <- hscStmt dflags hst hit pcs icontext expr
+        case maybe_stuff of
+          Nothing -> return (cmstate{ pcs=new_pcs }, [])
+          Just (ids, bcos) -> do
+               let 
+                   new_rn_env   = extendLocalRdrEnv rn_env (map idName ids)
+
+                       -- Extend the renamer-env from bound_ids, not
+                       -- bound_names, because the latter may contain
+                       -- [it] when the former is empty
+                   new_type_env = extendNameEnvList type_env   
+                                       [ (getName id, AnId id) | id <- ids]
+
+                   new_ic = icontext { ic_rn_env   = new_rn_env, 
+                                       ic_type_env = new_type_env }
+
+               hval <- linkExpr pls bcos
+               hvals <- unsafeCoerce# hval :: IO [HValue]
+               let names = map idName ids
+               new_pls <- updateClosureEnv pls (zip names hvals)
+               return (cmstate{ pcs=new_pcs, pls=new_pls, ic=new_ic }, names)
+
+   -- ToDo: check that the module we passed in is sane/exists?
+   where
+       CmState{ hst=hst, hit=hit, pcs=pcs, pls=pls } = cmstate
+#endif
+
+-----------------------------------------------------------------------------
+-- cmTypeOf: returns a string representing the type of a name.
+
+cmTypeOfName :: CmState -> Name -> IO (Maybe String)
+cmTypeOfName CmState{ hit=hit, pcs=pcs, ic=ic } name
+ = case lookupNameEnv (ic_type_env ic) name of
+       Nothing -> return Nothing
+       Just (AnId id) -> 
+          let pit = pcs_PIT pcs
+              modname = moduleName (ic_module ic)
+              ty = tidyType emptyTidyEnv (idType id)
+              str = case lookupIfaceByModName hit pit modname of
+                       Nothing    -> showSDoc (ppr ty)
+                       Just iface -> showSDocForUser unqual (ppr ty)
+                          where unqual = unQualInScope (mi_globals iface)
+          in return (Just str)
+
+       _ -> panic "cmTypeOfName"
+
+-----------------------------------------------------------------------------
+-- cmInfo: return "info" about an expression.  The info might be:
+--
+--     * its type, for an expression,
+--     * the class definition, for a class
+--     * the datatype definition, for a tycon (or synonym)
+--     * the export list, for a module
+--
+-- Can be used to find the type of the last expression compiled, by looking
+-- for "it".
+
+cmInfo :: CmState -> String -> IO (Maybe String)
+cmInfo cmstate str 
+ = do error "cmInfo not implemented yet"
+
+-----------------------------------------------------------------------------
+-- Unload the compilation manager's state: everything it knows about the
+-- current collection of modules in the Home package.
 
-\begin{code}
 cmUnload :: CmState -> IO CmState
 cmUnload state 
  = do -- Throw away the old home dir cache
@@ -148,18 +248,17 @@ cmUnload state
    where
      CmState{ hst=hst, hit=hit } = state
      (new_hst, new_hit) = retainInTopLevelEnvs [] (hst,hit)
-\end{code}
 
-The real business of the compilation manager: given a system state and
-a module name, try and bring the module up to date, probably changing
-the system state at the same time.
+-----------------------------------------------------------------------------
+-- The real business of the compilation manager: given a system state and
+-- a module name, try and bring the module up to date, probably changing
+-- the system state at the same time.
 
-\begin{code}
 cmLoadModule :: CmState 
              -> FilePath
              -> IO (CmState,           -- new state
                    Bool,               -- was successful
-                   [Module])           -- list of modules loaded
+                   [String])           -- list of modules loaded
 
 cmLoadModule cmstate1 rootname
    = do -- version 1's are the original, before downsweep
@@ -171,6 +270,7 @@ cmLoadModule cmstate1 rootname
        -- the previous pass, if any.
         let ui1       = ui     cmstate1
        let mg1       = mg     cmstate1
+       let ic1       = ic     cmstate1
 
         let ghci_mode = gmode cmstate1 -- this never changes
 
@@ -201,18 +301,9 @@ cmLoadModule cmstate1 rootname
         let mg2_with_srcimps = topological_sort True mg2unsorted
 
        -- Sort out which linkables we wish to keep in the unlinked image.
-       -- For each module, we take:
-       --
-       --      - the old in-core linkable, if available
-       --      - an on-disk linkable, if available
-       --
-       -- and we take the youngest of these, provided it is younger than the
-       -- source file.
-       --
-       -- If a module has a valid linkable, then it may be STABLE (see below),
-       -- and it is classified as SOURCE UNCHANGED for the purposes of calling
-       -- compile.
-       valid_linkables <- getValidLinkables ui1 mg2unsorted
+       -- See getValidLinkables below for details.
+       valid_linkables <- getValidLinkables ui1 mg2unsorted_names 
+                               mg2_with_srcimps
 
         -- Figure out a stable set of modules which can be retained
         -- the top level envs, to avoid upsweeping them.  Goes to a
@@ -236,7 +327,7 @@ cmLoadModule cmstate1 rootname
                    valid_linkables
 
         when (verb >= 2) $
-           putStrLn (showSDoc (text "STABLE MODULES:" 
+           putStrLn (showSDoc (text "Stable modules:" 
                                <+> sep (map (text.moduleNameUserString) stable_mods)))
 
        -- unload any modules which aren't going to be re-linked this
@@ -293,19 +384,15 @@ cmLoadModule cmstate1 rootname
            -- Easy; just relink it all.
            do when (verb >= 2) $ 
                 hPutStrLn stderr "Upsweep completely successful."
-              linkresult 
-                 <- link ghci_mode dflags a_root_is_Main ui3 pls2
-              case linkresult of
-                 LinkErrs _ _
-                    -> panic "cmLoadModule: link failed (1)"
-                 LinkOK pls3 
-                    -> do let cmstate3 
-                                 = CmState { hst=hst3, hit=hit3, 
-                                             ui=ui3, mg=modsDone, 
-                                             gmode=ghci_mode,
-                                            pcs=pcs3, pls=pls3 }
-                          return (cmstate3, True, 
-                                  map ms_mod modsDone)
+
+             -- clean up after ourselves
+             cleanTempFilesExcept verb (ppFilesFromSummaries modsDone)
+
+             -- link everything together
+              linkresult <- link ghci_mode dflags a_root_is_Main ui3 pls2
+
+             cmLoadFinish True linkresult 
+                       hst3 hit3 ui3 modsDone ghci_mode pcs3
 
          else 
            -- Tricky.  We need to back out the effects of compiling any
@@ -317,64 +404,135 @@ cmLoadModule cmstate1 rootname
               let modsDone_names
                      = map name_of_summary modsDone
               let mods_to_zap_names 
-                     = findPartiallyCompletedCycles modsDone_names mg2_with_srcimps
-              let (hst4, hit4, ui4) 
+                     = findPartiallyCompletedCycles modsDone_names 
+                         mg2_with_srcimps
+              let (hst4, hit4, ui4)
                      = removeFromTopLevelEnvs mods_to_zap_names (hst3,hit3,ui3)
+
               let mods_to_keep
-                     = filter ((`notElem` mods_to_zap_names).name_of_summary) modsDone
-              let mods_to_keep_names 
-                     = map name_of_summary mods_to_keep
-              -- we could get the relevant linkables by filtering newLis, but
-              -- it seems easier to drag them out of the updated, cleaned-up UI
-              let linkables_to_link 
-                     = map (unJust "linkables_to_link" . findModuleLinkable_maybe ui4)
-                           mods_to_keep_names
-
-              linkresult <- link ghci_mode dflags False linkables_to_link pls2
-              case linkresult of
-                 LinkErrs _ _
-                    -> panic "cmLoadModule: link failed (2)"
-                 LinkOK pls3
-                    -> do let cmstate4 
-                                 = CmState { hst=hst4, hit=hit4, 
-                                             ui=ui4, mg=mods_to_keep,
-                                             gmode=ghci_mode, pcs=pcs3, pls=pls3 }
-                          return (cmstate4, False, 
-                                  map ms_mod mods_to_keep)
+                     = filter ((`notElem` mods_to_zap_names).name_of_summary) 
+                         modsDone
+
+             -- clean up after ourselves
+             cleanTempFilesExcept verb (ppFilesFromSummaries mods_to_keep)
+
+             -- link everything together
+              linkresult <- link ghci_mode dflags False ui4 pls2
+
+             cmLoadFinish False linkresult 
+                   hst4 hit4 ui4 mods_to_keep ghci_mode pcs3
+
+
+-- Finish up after a cmLoad.
+--
+-- Empty the interactive context and set the module context to the topmost
+-- newly loaded module, or the Prelude if none were loaded.
+cmLoadFinish ok linkresult hst hit ui mods ghci_mode pcs
+  = do case linkresult of {
+          LinkErrs _ _ -> panic "cmLoadModule: link failed (2)";
+          LinkOK pls   -> do
+
+       def_mod <- readIORef defaultCurrentModule
+       let current_mod = case mods of 
+                               []    -> def_mod
+                               (x:_) -> ms_mod x
+
+                  new_ic = emptyInteractiveContext current_mod
+
+           new_cmstate = CmState{ hst=hst, hit=hit, 
+                                  ui=ui, mg=mods,
+                                  gmode=ghci_mode, pcs=pcs, 
+                                 pls=pls,
+                                 ic = new_ic }
+           mods_loaded = map (moduleNameUserString.name_of_summary) mods
 
+       return (new_cmstate, ok, mods_loaded)
+    }
+
+ppFilesFromSummaries summaries
+  = [ fn | Just fn <- map (ml_hspp_file . ms_location) summaries ]
 
 -----------------------------------------------------------------------------
 -- getValidLinkables
 
+-- For each module (or SCC of modules), we take:
+--
+--     - the old in-core linkable, if available
+--     - an on-disk linkable, if available
+--
+-- and we take the youngest of these, provided it is younger than the
+-- source file.  We ignore the on-disk linkables unless all of the
+-- dependents of this SCC also have on-disk linkables.
+--
+-- If a module has a valid linkable, then it may be STABLE (see below),
+-- and it is classified as SOURCE UNCHANGED for the purposes of calling
+-- compile.
+--
+-- ToDo: this pass could be merged with the preUpsweep.
+
 getValidLinkables
-       :: [Linkable]                   -- old linkables
-       -> [ModSummary]                 -- all modules in the program
-       -> IO [Linkable]                -- still-valid linkables 
-
-getValidLinkables old_linkables summaries
-  = do lis <- mapM (getValidLinkable old_linkables) summaries
-       return (concat lis)
-
-getValidLinkable old_linkables summary
-  = do let mod_name = moduleName (ms_mod summary)
-       maybe_disk_linkable
-           <- case ml_obj_file (ms_location summary) of
-                 Nothing -> return Nothing
-                 Just obj_fn -> maybe_getFileLinkable mod_name obj_fn
-
-       -- find an old in-core linkable if we have one. (forget about
-       -- on-disk linkables for now, we'll check again whether there's
-       -- one here below, just in case a new one has popped up recently).
-       let old_linkable = findModuleLinkable_maybe old_linkables mod_name
-           maybe_old_linkable =
+       :: [Linkable]           -- old linkables
+       -> [ModuleName]         -- all home modules
+       -> [SCC ModSummary]     -- all modules in the program, dependency order
+       -> IO [Linkable]        -- still-valid linkables 
+
+getValidLinkables old_linkables all_home_mods module_graph
+  = foldM (getValidLinkablesSCC old_linkables all_home_mods) [] module_graph
+
+getValidLinkablesSCC old_linkables all_home_mods new_linkables scc0
+   = let 
+         scc             = flattenSCC scc0
+          scc_names       = map name_of_summary scc
+         home_module m   = m `elem` all_home_mods && m `notElem` scc_names
+          scc_allhomeimps = nub (filter home_module (concatMap ms_allimps scc))
+
+         has_object m = case findModuleLinkable_maybe new_linkables m of
+                           Nothing -> False
+                           Just l  -> isObjectLinkable l
+
+          objects_allowed = all has_object scc_allhomeimps
+     in do
+
+     these_linkables 
+       <- foldM (getValidLinkable old_linkables objects_allowed) [] scc
+
+       -- 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
+
+        -- find an old in-core linkable if we have one. (forget about
+        -- on-disk linkables for now, we'll check again whether there's
+        -- one here below, just in case a new one has popped up recently).
+        let old_linkable = findModuleLinkable_maybe old_linkables mod_name
+            maybe_old_linkable =
                case old_linkable of
                    Just (LM _ _ ls) | all isInterpretable ls -> old_linkable
-                   _ -> Nothing      
+                   _ -> Nothing
 
-       -- The most recent of the old UI linkable or whatever we could
-       -- find on disk is returned as the linkable if compile
-       -- doesn't think we need to recompile.        
-       let linkable_list
+        -- The most recent of the old UI linkable or whatever we could
+        -- find on disk is returned as the linkable if compile
+        -- doesn't think we need to recompile.        
+        let linkable_list
                = case (maybe_old_linkable, maybe_disk_linkable) of
                     (Nothing, Nothing) -> []
                     (Nothing, Just di) -> [di]
@@ -383,17 +541,16 @@ getValidLinkable old_linkables summary
                        | linkableTime ui >= linkableTime di -> [ui]
                        | otherwise                          -> [di]
 
-       -- only linkables newer than the source code are valid
-       let maybe_src_date = ms_hs_date summary
+        -- only linkables newer than the source code are valid
+        let maybe_src_date = ms_hs_date summary
 
-          valid_linkable_list
+           valid_linkable_list
              = case maybe_src_date of
                  Nothing -> panic "valid_linkable_list"
                  Just src_date 
-                     -> filter (\li -> linkableTime li > src_date) linkable_list
-
-       return valid_linkable_list
+                    -> filter (\li -> linkableTime li > src_date) linkable_list
 
+        return (valid_linkable_list ++ new_linkables)
 
 
 maybe_getFileLinkable :: ModuleName -> FilePath -> IO (Maybe Linkable)
@@ -434,9 +591,7 @@ preUpsweep valid_lis old_lis all_home_mods stable (scc0:sccs)
             scc_names
                = map name_of_summary scc
             in_stable_or_scc m
-               = --trace (showSDoc (text "ISOS" <+> ppr m <+> ppr scc_names <+> ppr stable)) (
-                 m `elem` scc_names || m `elem` stable
-                 --)
+               = 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), and the
@@ -571,15 +726,6 @@ upsweep_mod ghci_mode dflags oldUI threaded1 summary1 reachable_from_here
         let mod_name = name_of_summary summary1
        let verb = verbosity dflags
 
-        when (verb == 1) $
-          if (ghci_mode == Batch)
-               then hPutStr stderr (progName ++ ": module " 
-                               ++ moduleNameUserString mod_name
-                       ++ ": ")
-               else hPutStr stderr ("Compiling "
-                       ++ moduleNameUserString mod_name
-                       ++ " ... ")
-
         let (CmThreaded pcs1 hst1 hit1) = threaded1
         let old_iface = lookupUFM hit1 mod_name
 
@@ -744,14 +890,8 @@ downsweep rootNm old_summaries
 
         getSummary :: ModuleName -> IO ModSummary
         getSummary nm
-           -- | trace ("getSummary: "++ showSDoc (ppr nm)) True
            = do found <- findModule nm
                case found of
-                   -- Be sure not to use the mod and location passed in to 
-                   -- summarise for any other purpose -- summarise may change
-                   -- the module names in them if name of module /= name of file,
-                   -- and put the changed versions in the returned summary.
-                   -- These will then conflict with the passed-in versions.
                   Just (mod, location) -> do
                        let old_summary = findModInSummaries old_summaries mod
                        new_summary <- summarise mod location old_summary
@@ -771,7 +911,7 @@ downsweep rootNm old_summaries
                let all_home = map (moduleName.ms_mod) home_summaries
 
                -- imports for modules we don't already have
-                let needed_imps = filter (`notElem` all_home) imps
+                let needed_imps = nub (filter (`notElem` all_home) imps)
 
                -- summarise them
                 needed_summaries <- mapM getSummary needed_imps
@@ -844,12 +984,11 @@ summarise mod location old_summary
                  Nothing     -> return Nothing
                  Just src_fn -> maybe_getModificationTime src_fn
 
-       if mod_name == moduleName mod
-               then return ()
-               else throwDyn (OtherError 
-                       (showSDoc (text "file name does not match module name: "
-                          <+> ppr (moduleName mod) <+> text "vs" 
-                          <+> ppr mod_name)))
+       when (mod_name /= moduleName mod) $
+               throwDyn (OtherError 
+                  (showSDoc (text "file name does not match module name: "
+                             <+> ppr (moduleName mod) <+> text "vs" 
+                             <+> ppr mod_name)))
 
         return (Just (ModSummary mod location{ml_hspp_file=Just hspp_fn} 
                                  srcimps imps