[project @ 2005-03-22 17:13:12 by simonmar]
authorsimonmar <unknown>
Tue, 22 Mar 2005 17:13:55 +0000 (17:13 +0000)
committersimonmar <unknown>
Tue, 22 Mar 2005 17:13:55 +0000 (17:13 +0000)
A start on the GHC API:

Flesh out the GHC module so that it can replace CompManager.  Now, the
clients that used CompManager consume the GHC API instead (namely
Main, DriverMkDepend, and InteractiveUI).  Main is significantly
cleaner as a result.

The interface needs more work: in particular, getInfo returns results
in the form of IfaceDecls but we want to use full HsSyn and
Id/DataCon/Class across the boundary instead.

The interfaces for inspecting loaded modules are not yet implemented.

13 files changed:
ghc/compiler/Makefile
ghc/compiler/compMan/CompManager.lhs [deleted file]
ghc/compiler/ghci/InteractiveUI.hs
ghc/compiler/ghci/Linker.lhs
ghc/compiler/iface/LoadIface.lhs
ghc/compiler/main/DriverMkDepend.hs
ghc/compiler/main/DriverPipeline.hs
ghc/compiler/main/Finder.lhs
ghc/compiler/main/GHC.hs
ghc/compiler/main/HscMain.lhs
ghc/compiler/main/HscTypes.lhs
ghc/compiler/main/Main.hs
ghc/compiler/typecheck/TcRnDriver.lhs

index 49890d1..b6c919c 100644 (file)
@@ -369,9 +369,6 @@ ALL_SRCS += $(CONFIG_HS)
 # HsGeneric.hs is not used just now
 EXCLUDED_SRCS += hsSyn/HsGeneric.hs
 
-# main/GHC.hs is not ready yet
-EXCLUDED_SRCS += main/GHC.hs
-
 ifeq ($(GhcWithNativeCodeGen),YES)
 ALL_DIRS += nativeGen
 else
diff --git a/ghc/compiler/compMan/CompManager.lhs b/ghc/compiler/compMan/CompManager.lhs
deleted file mode 100644 (file)
index 79735bc..0000000
+++ /dev/null
@@ -1,1386 +0,0 @@
-%
-% (c) The University of Glasgow, 2002
-%
-% The Compilation Manager
-%
-\begin{code}
-module CompManager ( 
-    ModSummary,                -- Abstract
-    ModuleGraph,       -- All the modules from the home package
-
-    CmState,           -- Abstract
-
-    cmInit,       -- :: GhcMode -> IO CmState
-
-    cmDepAnal,    -- :: CmState -> [FilePath] -> IO ModuleGraph
-    cmDownsweep,   
-    cmTopSort,    -- :: Bool -> ModuleGraph -> [SCC ModSummary]
-    cyclicModuleErr,   -- :: [ModSummary] -> String    -- Used by DriverMkDepend
-
-    cmLoadModules, -- :: CmState -> ModuleGraph
-                  --    -> IO (CmState, Bool, [String])
-
-    cmUnload,     -- :: CmState -> IO CmState
-
-
-#ifdef GHCI
-    cmModuleIsInterpreted, -- :: CmState -> String -> IO Bool
-
-    cmSetContext,  -- :: CmState -> [String] -> [String] -> IO CmState
-    cmGetContext,  -- :: CmState -> IO ([String],[String])
-
-    cmGetInfo,    -- :: CmState -> String -> IO (CmState, [(TyThing,Fixity)])
-    GetInfoResult,
-    cmBrowseModule, -- :: CmState -> IO [TyThing]
-    cmShowModule,
-
-    CmRunResult(..),
-    cmRunStmt,         -- :: CmState -> String -> IO (CmState, CmRunResult)
-
-    cmTypeOfExpr,      -- :: CmState -> String -> IO (CmState, Maybe String)
-    cmKindOfType,      -- :: CmState -> String -> IO (CmState, Maybe String)
-    cmTypeOfName,      -- :: CmState -> Name -> IO (Maybe String)
-
-    HValue,
-    cmCompileExpr,     -- :: CmState -> String -> IO (CmState, Maybe HValue)
-    cmGetModuleGraph,  -- :: CmState -> ModuleGraph
-    cmSetDFlags,
-    cmGetDFlags,
-
-    cmGetBindings,     -- :: CmState -> [TyThing]
-    cmGetPrintUnqual,  -- :: CmState -> PrintUnqualified
-#endif
-  )
-where
-
-#include "HsVersions.h"
-
-import Packages                ( isHomePackage )
-import DriverPipeline  ( CompResult(..), preprocess, compile, link )
-import HscMain         ( newHscEnv )
-import DriverPhases    ( HscSource(..), hscSourceString, isHaskellSrcFilename )
-import Finder          ( findModule, findLinkable, addHomeModuleToFinder,
-                         flushFinderCache, mkHomeModLocation, FindResult(..), cantFindError )
-import HscTypes                ( ModSummary(..), HomeModInfo(..), ModIface(..),
-                         msHsFilePath, HscEnv(..), isBootSummary,
-                         InteractiveContext(..), emptyInteractiveContext, 
-                         HomePackageTable, emptyHomePackageTable,
-                         IsBootInterface, Linkable(..), isObjectLinkable )
-import Module          ( Module, mkModule, delModuleEnv, delModuleEnvList,
-                         mkModuleEnv, lookupModuleEnv, moduleEnvElts,
-                         extendModuleEnv, filterModuleEnv, moduleUserString,
-                         addBootSuffixLocn, ModLocation(..) )
-import GetImports      ( getImports )
-import Digraph         ( SCC(..), stronglyConnComp, flattenSCC, flattenSCCs )
-import ErrUtils                ( showPass )
-import SysTools                ( cleanTempFilesExcept )
-import BasicTypes      ( SuccessFlag(..), succeeded )
-import StringBuffer    ( hGetStringBuffer )
-import Util
-import Outputable
-import Panic
-import DynFlags                ( DynFlags(..), DynFlag(..), GhcMode(..), dopt )
-import Maybes          ( expectJust, orElse, mapCatMaybes )
-import FiniteMap
-
-#ifdef GHCI
-import Finder          ( findPackageModule )
-import HscMain         ( hscGetInfo, GetInfoResult, hscStmt, hscTcExpr, hscKcType )
-import HscTypes                ( TyThing(..), icPrintUnqual, showModMsg )
-import TcRnDriver      ( mkExportEnv, getModuleContents )
-import IfaceSyn                ( IfaceDecl )
-import RdrName         ( GlobalRdrEnv, plusGlobalRdrEnv )
-import Name            ( Name )
-import NameEnv
-import Id              ( idType )
-import Type            ( tidyType, dropForAlls )
-import VarEnv          ( emptyTidyEnv )
-import Linker          ( HValue, unload, extendLinkEnv )
-import GHC.Exts                ( unsafeCoerce# )
-import Foreign
-import Control.Exception as Exception ( Exception, try )
-import DynFlags        ( DynFlag(..), dopt_unset, dopt )
-#endif
-
-import EXCEPTION       ( throwDyn )
-
--- std
-import Directory        ( getModificationTime, doesFileExist )
-import IO
-import Monad
-import List            ( nub )
-import Maybe
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-               The module dependency graph
-               ModSummary, ModGraph, NodeKey, NodeMap
-%*                                                                     *
-%************************************************************************
-
-The nodes of the module graph are
-       EITHER a regular Haskell source module
-       OR     a hi-boot source module
-
-A ModuleGraph contains all the nodes from the home package (only).  
-There will be a node for each source module, plus a node for each hi-boot
-module.
-
-\begin{code}
-type ModuleGraph = [ModSummary]  -- The module graph, 
-                                -- NOT NECESSARILY IN TOPOLOGICAL ORDER
-
-emptyMG :: ModuleGraph
-emptyMG = []
-
---------------------
-ms_allimps :: ModSummary -> [Module]
-ms_allimps ms = ms_srcimps ms ++ ms_imps ms
-
---------------------
-type NodeKey   = (Module, HscSource)     -- The nodes of the graph are 
-type NodeMap a = FiniteMap NodeKey a     -- keyed by (mod, src_file_type) pairs
-
-msKey :: ModSummary -> NodeKey
-msKey (ModSummary { ms_mod = mod, ms_hsc_src = boot }) = (mod,boot)
-
-emptyNodeMap :: NodeMap a
-emptyNodeMap = emptyFM
-
-mkNodeMap :: [ModSummary] -> NodeMap ModSummary
-mkNodeMap summaries = listToFM [ (msKey s, s) | s <- summaries]
-       
-nodeMapElts :: NodeMap a -> [a]
-nodeMapElts = eltsFM
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-               The compilation manager state
-%*                                                                     *
-%************************************************************************
-
-
-\begin{code}
--- Persistent state for the entire system
-data CmState
-   = CmState {
-       cm_hsc :: HscEnv,               -- Includes the home-package table
-       cm_mg  :: ModuleGraph,          -- The module graph
-       cm_ic  :: InteractiveContext    -- Command-line binding info
-     }
-
-#ifdef GHCI
-cmGetModuleGraph cmstate = cm_mg cmstate
-cmGetBindings    cmstate = nameEnvElts (ic_type_env (cm_ic cmstate))
-cmGetPrintUnqual cmstate = icPrintUnqual (cm_ic cmstate)
-cmHPT           cmstate = hsc_HPT (cm_hsc cmstate)
-#endif
-
-cmInit :: DynFlags -> IO CmState
-cmInit dflags
-   = do { hsc_env <- newHscEnv dflags
-       ; return (CmState { cm_hsc = hsc_env,
-                           cm_mg  = emptyMG, 
-                           cm_ic  = emptyInteractiveContext })}
-
-discardCMInfo :: CmState -> CmState
--- Forget the compilation manager's state, including the home package table
--- but retain the persistent info in HscEnv
-discardCMInfo cm_state
-  = cm_state { cm_mg = emptyMG, cm_ic = emptyInteractiveContext,
-              cm_hsc = (cm_hsc cm_state) { hsc_HPT = emptyHomePackageTable } }
-
--------------------------------------------------------------------
---                     The unlinked image
--- 
--- The compilation manager keeps a list of compiled, but as-yet unlinked
--- binaries (byte code or object code).  Even when it links bytecode
--- it keeps the unlinked version so it can re-link it later without
--- recompiling.
-
-type UnlinkedImage = [Linkable]        -- the unlinked images (should be a set, really)
-
-findModuleLinkable_maybe :: [Linkable] -> Module -> Maybe Linkable
-findModuleLinkable_maybe lis mod
-   = case [LM time nm us | LM time nm us <- lis, nm == mod] of
-        []   -> Nothing
-        [li] -> Just li
-        many -> pprPanic "findModuleLinkable" (ppr mod)
-
-delModuleLinkable :: [Linkable] -> Module -> [Linkable]
-delModuleLinkable ls mod = [ l | l@(LM _ nm _) <- ls, nm /= mod ]
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-       GHCI stuff
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-#ifdef GHCI
------------------------------------------------------------------------------
--- 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]             -- take the top-level scopes of these modules
-       -> [String]             -- and the just the exports from these
-       -> IO CmState
-cmSetContext cmstate toplevs exports = do 
-  let old_ic  = cm_ic cmstate
-      hsc_env = cm_hsc cmstate
-      hpt     = hsc_HPT hsc_env
-
-  let export_mods = map mkModule exports
-  mapM_ (checkModuleExists (hsc_dflags hsc_env) hpt) export_mods
-  export_env  <- mkExportEnv hsc_env export_mods
-  toplev_envs <- mapM (mkTopLevEnv hpt) toplevs
-
-  let all_env = foldr plusGlobalRdrEnv export_env toplev_envs
-  return cmstate{ cm_ic = old_ic { ic_toplev_scope = toplevs,
-                                  ic_exports      = exports,
-                                  ic_rn_gbl_env   = all_env } }
-
-checkModuleExists :: DynFlags -> HomePackageTable -> Module -> IO ()
-checkModuleExists dflags hpt mod = 
-  case lookupModuleEnv hpt mod of
-    Just mod_info -> return ()
-    _not_a_home_module -> do
-         res <- findPackageModule dflags mod True
-         case res of
-           Found _ _ -> return  ()
-           err -> let msg = cantFindError dflags mod err in
-                  throwDyn (CmdLineError (showSDoc msg))
-
-mkTopLevEnv :: HomePackageTable -> String -> IO GlobalRdrEnv
-mkTopLevEnv hpt mod
- = case lookupModuleEnv hpt (mkModule mod) of
-      Nothing      -> throwDyn (ProgramError ("mkTopLevEnv: not a home module " ++ mod))
-      Just details -> case mi_globals (hm_iface details) of
-                       Nothing  -> throwDyn (ProgramError ("mkTopLevEnv: not interpreted " ++ mod))
-                       Just env -> return env
-
-cmGetContext :: CmState -> IO ([String],[String])
-cmGetContext CmState{cm_ic=ic} = 
-  return (ic_toplev_scope ic, ic_exports ic)
-
-cmModuleIsInterpreted :: CmState -> String -> IO Bool
-cmModuleIsInterpreted cmstate str 
- = case lookupModuleEnv (cmHPT cmstate) (mkModule str) of
-      Just details       -> return (isJust (mi_globals (hm_iface details)))
-      _not_a_home_module -> return False
-
------------------------------------------------------------------------------
-
-cmSetDFlags :: CmState -> DynFlags -> CmState
-cmSetDFlags cm_state dflags 
-  = cm_state { cm_hsc = (cm_hsc cm_state) { hsc_dflags = dflags } }
-
-cmGetDFlags :: CmState -> DynFlags
-cmGetDFlags cm_state = hsc_dflags (cm_hsc cm_state)
-
------------------------------------------------------------------------------
--- cmInfoThing: convert a String to a TyThing
-
--- A string may refer to more than one TyThing (eg. a constructor,
--- and type constructor), so we return a list of all the possible TyThings.
-
-cmGetInfo :: CmState -> String -> IO [GetInfoResult]
-cmGetInfo cmstate id = hscGetInfo (cm_hsc cmstate) (cm_ic cmstate) id
-
--- ---------------------------------------------------------------------------
--- cmBrowseModule: get all the TyThings defined in a module
-
-cmBrowseModule :: CmState -> String -> Bool -> IO [IfaceDecl]
-cmBrowseModule cmstate str exports_only
-  = do { mb_decls <- getModuleContents (cm_hsc cmstate) (cm_ic cmstate) 
-                                      (mkModule str) exports_only
-       ; case mb_decls of
-          Nothing -> return []         -- An error of some kind
-          Just ds -> return ds
-   }
-
-
------------------------------------------------------------------------------
-cmShowModule :: CmState -> ModSummary -> String
-cmShowModule cmstate mod_summary
-  = case lookupModuleEnv hpt (ms_mod mod_summary) of
-       Nothing       -> panic "missing linkable"
-       Just mod_info -> showModMsg obj_linkable mod_summary
-                     where
-                        obj_linkable = isObjectLinkable (hm_linkable mod_info)
-  where
-    hpt  = hsc_HPT (cm_hsc cmstate)
-
------------------------------------------------------------------------------
--- cmRunStmt:  Run a statement/expr.
-
-data CmRunResult
-  = CmRunOk [Name]             -- names bound by this evaluation
-  | CmRunFailed 
-  | CmRunException Exception   -- statement raised an exception
-
-cmRunStmt :: CmState -> String -> IO (CmState, CmRunResult)            
-cmRunStmt cmstate@CmState{ cm_hsc=hsc_env, cm_ic=icontext } expr
-   = do 
-       -- Turn off -fwarn-unused-bindings when running a statement, to hide
-       -- warnings about the implicit bindings we introduce.
-       let dflags'  = dopt_unset (hsc_dflags hsc_env) Opt_WarnUnusedBinds
-           hsc_env' = hsc_env{ hsc_dflags = dflags' }
-
-        maybe_stuff <- hscStmt hsc_env' icontext expr
-
-        case maybe_stuff of
-          Nothing -> return (cmstate, CmRunFailed)
-          Just (new_ic, names, hval) -> do
-
-               let thing_to_run = unsafeCoerce# hval :: IO [HValue]
-               either_hvals <- sandboxIO thing_to_run
-
-               case either_hvals of
-                   Left e -> do
-                       -- on error, keep the *old* interactive context,
-                       -- so that 'it' is not bound to something
-                       -- that doesn't exist.
-                       return ( cmstate, CmRunException e )
-
-                   Right hvals -> do
-                       -- Get the newly bound things, and bind them.  
-                       -- Don't need to delete any shadowed bindings;
-                       -- the new ones override the old ones. 
-                       extendLinkEnv (zip names hvals)
-                       
-                       return (cmstate{ cm_ic=new_ic }, 
-                               CmRunOk names)
-
-
--- We run the statement in a "sandbox" to protect the rest of the
--- system from anything the expression might do.  For now, this
--- consists of just wrapping it in an exception handler, but see below
--- for another version.
-
-sandboxIO :: IO a -> IO (Either Exception a)
-sandboxIO thing = Exception.try thing
-
-{-
--- This version of sandboxIO runs the expression in a completely new
--- RTS main thread.  It is disabled for now because ^C exceptions
--- won't be delivered to the new thread, instead they'll be delivered
--- to the (blocked) GHCi main thread.
-
--- SLPJ: when re-enabling this, reflect a wrong-stat error as an exception
-
-sandboxIO :: IO a -> IO (Either Int (Either Exception a))
-sandboxIO thing = do
-  st_thing <- newStablePtr (Exception.try thing)
-  alloca $ \ p_st_result -> do
-    stat <- rts_evalStableIO st_thing p_st_result
-    freeStablePtr st_thing
-    if stat == 1
-       then do st_result <- peek p_st_result
-               result <- deRefStablePtr st_result
-               freeStablePtr st_result
-               return (Right result)
-       else do
-               return (Left (fromIntegral stat))
-
-foreign import "rts_evalStableIO"  {- safe -}
-  rts_evalStableIO :: StablePtr (IO a) -> Ptr (StablePtr a) -> IO CInt
-  -- more informative than the C type!
--}
-
------------------------------------------------------------------------------
--- cmTypeOfExpr: returns a string representing the type of an expression
-
-cmTypeOfExpr :: CmState -> String -> IO (Maybe String)
-cmTypeOfExpr cmstate expr
-   = do maybe_stuff <- hscTcExpr (cm_hsc cmstate) (cm_ic cmstate) expr
-
-       case maybe_stuff of
-          Nothing -> return Nothing
-          Just ty -> return (Just (showSDocForUser unqual doc))
-            where 
-               doc     = text expr <+> dcolon <+> ppr final_ty
-               unqual  = icPrintUnqual (cm_ic cmstate)
-               tidy_ty = tidyType emptyTidyEnv ty
-               dflags  = hsc_dflags (cm_hsc cmstate)
-               -- if -fglasgow-exts is on we show the foralls, otherwise
-               -- we don't.
-               final_ty
-                 | dopt Opt_GlasgowExts dflags = tidy_ty
-                 | otherwise                   = dropForAlls tidy_ty
-
------------------------------------------------------------------------------
--- cmKindOfType: returns a string representing the kind of a type
-
-cmKindOfType :: CmState -> String -> IO (Maybe String)
-cmKindOfType cmstate str
-   = do maybe_stuff <- hscKcType (cm_hsc cmstate) (cm_ic cmstate) str
-       case maybe_stuff of
-          Nothing -> return Nothing
-          Just kind -> return (Just res_str)
-            where 
-               res_str = showSDocForUser unqual (text str <+> dcolon <+> ppr kind)
-               unqual  = icPrintUnqual (cm_ic cmstate)
-
------------------------------------------------------------------------------
--- cmTypeOfName: returns a string representing the type of a name.
-
-cmTypeOfName :: CmState -> Name -> IO (Maybe String)
-cmTypeOfName CmState{ cm_ic=ic } name
- = do 
-    hPutStrLn stderr ("cmTypeOfName: " ++ showSDoc (ppr name))
-    case lookupNameEnv (ic_type_env ic) name of
-       Nothing        -> return Nothing
-       Just (AnId id) -> return (Just str)
-          where
-            unqual = icPrintUnqual ic
-            ty = tidyType emptyTidyEnv (idType id)
-            str = showSDocForUser unqual (ppr ty)
-
-       _ -> panic "cmTypeOfName"
-
------------------------------------------------------------------------------
--- cmCompileExpr: compile an expression and deliver an HValue
-
-cmCompileExpr :: CmState -> String -> IO (Maybe HValue)
-cmCompileExpr cmstate expr
-   = do 
-        maybe_stuff 
-           <- hscStmt (cm_hsc cmstate) (cm_ic cmstate)
-                      ("let __cmCompileExpr = "++expr)
-
-        case maybe_stuff of
-          Nothing -> return Nothing
-          Just (new_ic, names, hval) -> do
-
-                       -- Run it!
-               hvals <- (unsafeCoerce# hval) :: IO [HValue]
-
-               case (names,hvals) of
-                 ([n],[hv]) -> return (Just hv)
-                 _          -> panic "cmCompileExpr"
-
-#endif /* GHCI */
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-       Loading and unloading
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
------------------------------------------------------------------------------
--- Unload the compilation manager's state: everything it knows about the
--- current collection of modules in the Home package.
-
-cmUnload :: CmState -> IO CmState
-cmUnload state@CmState{ cm_hsc = hsc_env }
- = do -- Throw away the old home dir cache
-      flushFinderCache
-
-      -- Unload everything the linker knows about
-      cm_unload hsc_env []
-
-      -- Start with a fresh CmState, but keep the PersistentCompilerState
-      return (discardCMInfo state)
-
-cm_unload hsc_env stable_linkables     -- Unload everthing *except* 'stable_linkables'
-  = case ghcMode (hsc_dflags hsc_env) of
-       BatchCompile -> return ()
-#ifdef GHCI
-       Interactive -> Linker.unload (hsc_dflags hsc_env) stable_linkables
-#else
-       Interactive -> panic "cm_unload: no interpreter"
-#endif
-       other -> panic "cm_unload: strange mode"
-    
-
------------------------------------------------------------------------------
--- Trace dependency graph
-
--- This is a seperate pass so that the caller can back off and keep
--- the current state if the downsweep fails.  Typically the caller
--- might go    cmDepAnal
---             cmUnload
---             cmLoadModules
--- He wants to do the dependency analysis before the unload, so that
--- if the former fails he can use the later
-
-cmDepAnal :: CmState -> [FilePath] -> IO ModuleGraph
-cmDepAnal cmstate rootnames
-  = do showPass dflags "Chasing dependencies"
-       when (verbosity dflags >= 1 && gmode == BatchCompile) $
-           hPutStrLn stderr (showSDoc (hcat [
-            text "Chasing modules from: ",
-            hcat (punctuate comma (map text rootnames))]))
-       cmDownsweep dflags rootnames (cm_mg cmstate) []
-  where
-    hsc_env = cm_hsc cmstate
-    dflags  = hsc_dflags hsc_env
-    gmode   = ghcMode (hsc_dflags hsc_env)
-
------------------------------------------------------------------------------
--- 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.
-
-cmLoadModules :: CmState               -- The HPT may not be as up to date
-              -> ModuleGraph           -- Bang up to date; but may contain hi-boot no
-              -> IO (CmState,          -- new state
-                    SuccessFlag,       -- was successful
-                    [String])          -- list of modules loaded
-
-cmLoadModules cmstate1 mg2unsorted
-   = do -- version 1's are the original, before downsweep
-       let hsc_env   = cm_hsc cmstate1
-        let hpt1      = hsc_HPT hsc_env
-        let ghci_mode = ghcMode (hsc_dflags hsc_env) -- this never changes
-        let dflags    = hsc_dflags hsc_env -- this never changes
-        let verb      = verbosity dflags
-
-       -- The "bad" boot modules are the ones for which we have
-       -- 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 s | s <- mg2unsorted, not (isBootSummary s)]
-           bad_boot_mods = [s        | s <- mg2unsorted, isBootSummary s,
-                                       not (ms_mod s `elem` all_home_mods)]
-       ASSERT( null bad_boot_mods ) return ()
-
-        -- Do the downsweep to reestablish the module graph
-        -- mg2 should be cycle free; but it includes hi-boot ModSummary nodes
-        let mg2 :: [SCC ModSummary]
-           mg2 = cmTopSort False mg2unsorted
-
-        -- 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
-        -- not in strict downwards closure, during calls to compile.
-        let mg2_with_srcimps :: [SCC ModSummary]
-           mg2_with_srcimps = cmTopSort True mg2unsorted
-
-       -- Sort out which linkables we wish to keep in the unlinked image.
-       -- See getValidLinkables below for details.
-       (valid_old_linkables, new_linkables)
-           <- getValidLinkables ghci_mode (hptLinkables hpt1)
-                 all_home_mods mg2_with_srcimps
-
-       -- putStrLn (showSDoc (vcat [ppr valid_old_linkables, ppr new_linkables]))
-
-       -- The new_linkables are .o files we found on the disk, presumably
-       -- as a result of a GHC run "on the side".  So we'd better forget
-       -- everything we know abouut those modules!
-       let old_hpt = delModuleEnvList hpt1 (map linkableModule new_linkables)
-
-       -- When (verb >= 2) $
-        --    putStrLn (showSDoc (text "Valid linkables:" 
-        --                      <+> ppr valid_linkables))
-
-        -- Figure out a stable set of modules which can be retained
-        -- the top level envs, to avoid upsweeping them.  Goes to a
-        -- bit of trouble to avoid upsweeping module cycles.
-        --
-        -- Construct a set S of stable modules like this:
-        -- Travel upwards, over the sccified graph.  For each scc
-        -- of modules ms, add ms to S only if:
-        -- 1.  All home imports of ms are either in ms or S
-        -- 2.  A valid old linkable exists for each module in ms
-
-       -- mg2_with_srcimps has no hi-boot nodes, 
-       -- and hence neither does stable_mods 
-        stable_summaries <- preUpsweep valid_old_linkables
-                                      all_home_mods [] mg2_with_srcimps
-        let stable_mods      = map ms_mod stable_summaries
-           stable_linkables = filter (\m -> linkableModule m `elem` stable_mods) 
-                                     valid_old_linkables
-
-           stable_hpt = filterModuleEnv is_stable_hm hpt1
-           is_stable_hm hm_info = mi_module (hm_iface hm_info) `elem` stable_mods
-
-            upsweep_these
-               = filter (\scc -> any (`notElem` stable_mods) 
-                                     (map ms_mod (flattenSCC scc)))
-                        mg2
-
-        when (verb >= 2) $
-           hPutStrLn stderr (showSDoc (text "Stable modules:" 
-                               <+> sep (map (text.moduleUserString) stable_mods)))
-
-       -- Unload any modules which are going to be re-linked this time around.
-       cm_unload hsc_env stable_linkables
-
-       -- We can now glom together our linkable sets
-       let valid_linkables = valid_old_linkables ++ new_linkables
-
-        -- We could at this point detect cycles which aren't broken by
-        -- a source-import, and complain immediately, but it seems better
-        -- to let upsweep_mods do this, so at least some useful work gets
-        -- done before the upsweep is abandoned.
-        --hPutStrLn stderr "after tsort:\n"
-        --hPutStrLn stderr (showSDoc (vcat (map ppr mg2)))
-
-        -- Because we don't take into account source imports when doing
-        -- the topological sort, there shouldn't be any cycles in mg2.
-        -- If there is, we complain and give up -- the user needs to
-        -- break the cycle using a boot file.
-
-        -- Now do the upsweep, calling compile for each module in
-        -- turn.  Final result is version 3 of everything.
-
-       -- clean up between compilations
-       let cleanup = cleanTempFilesExcept dflags
-                         (ppFilesFromSummaries (flattenSCCs mg2))
-
-        (upsweep_ok, hsc_env3, modsUpswept)
-           <- upsweep_mods (hsc_env { hsc_HPT = stable_hpt })
-                          (old_hpt, valid_linkables)
-                           cleanup upsweep_these
-
-        -- At this point, modsUpswept and newLis should have the same
-        -- length, so there is one new (or old) linkable for each 
-        -- mod which was processed (passed to compile).
-
-       -- Make modsDone be the summaries for each home module now
-       -- available; this should equal the domain of hpt3.
-       -- (NOT STRICTLY TRUE if an interactive session was started
-       --  with some object on disk ???)
-        -- Get in in a roughly top .. bottom order (hence reverse).
-
-        let modsDone = reverse modsUpswept ++ stable_summaries
-
-        -- Try and do linking in some form, depending on whether the
-        -- upsweep was completely or only partially successful.
-
-        if succeeded upsweep_ok
-
-         then 
-           -- Easy; just relink it all.
-           do when (verb >= 2) $ 
-                hPutStrLn stderr "Upsweep completely successful."
-
-             -- Clean up after ourselves
-             cleanTempFilesExcept dflags (ppFilesFromSummaries modsDone)
-
-             -- Issue a warning for the confusing case where the user
-             -- said '-o foo' but we're not going to do any linking.
-             -- We attempt linking if either (a) one of the modules is
-             -- called Main, or (b) the user said -no-hs-main, indicating
-             -- that main() is going to come from somewhere else.
-             --
-             let ofile = outputFile dflags
-             let no_hs_main = dopt Opt_NoHsMain dflags
-             let mb_main_mod = mainModIs dflags
-             let 
-               main_mod = mb_main_mod `orElse` "Main"
-               a_root_is_Main 
-                           = any ((==main_mod).moduleUserString.ms_mod) 
-                         mg2unsorted
-               do_linking = a_root_is_Main || no_hs_main
-
-             when (ghci_mode == BatchCompile && isJust ofile && not do_linking
-                    && verb > 0) $
-                hPutStrLn stderr ("Warning: output was redirected with -o, " ++
-                                  "but no output will be generated\n" ++
-                                  "because there is no " ++ main_mod ++ " module.")
-
-             -- link everything together
-              linkresult <- link ghci_mode dflags do_linking (hsc_HPT hsc_env3)
-
-             let cmstate3 = cmstate1 { cm_mg = modsDone, cm_hsc = hsc_env3 }
-             cmLoadFinish Succeeded linkresult cmstate3
-
-         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.
-           do when (verb >= 2) $
-               hPutStrLn stderr "Upsweep partially successful."
-
-              let modsDone_names
-                     = map ms_mod modsDone
-              let mods_to_zap_names 
-                     = findPartiallyCompletedCycles modsDone_names 
-                         mg2_with_srcimps
-              let mods_to_keep
-                     = filter ((`notElem` mods_to_zap_names).ms_mod) 
-                         modsDone
-
-              let hpt4 = retainInTopLevelEnvs (map ms_mod mods_to_keep) 
-                                             (hsc_HPT hsc_env3)
-
-             -- Clean up after ourselves
-             cleanTempFilesExcept dflags (ppFilesFromSummaries mods_to_keep)
-
-             -- Link everything together
-              linkresult <- link ghci_mode dflags False hpt4
-
-             let cmstate3 = cmstate1 { cm_mg = mods_to_keep,
-                                       cm_hsc = hsc_env3 { hsc_HPT = hpt4 } }
-             cmLoadFinish Failed linkresult cmstate3
-
--- Finish up after a cmLoad.
-
--- If the link failed, unload everything and return.
-cmLoadFinish ok Failed cmstate
-  = do cm_unload (cm_hsc cmstate) []
-       return (discardCMInfo cmstate, Failed, [])
-
--- Empty the interactive context and set the module context to the topmost
--- newly loaded module, or the Prelude if none were loaded.
-cmLoadFinish ok Succeeded cmstate
-  = do let new_cmstate = cmstate { cm_ic = emptyInteractiveContext }
-           mods_loaded = map (moduleUserString.ms_mod) 
-                            (cm_mg cmstate)
-
-       return (new_cmstate, ok, mods_loaded)
-
--- used to fish out the preprocess output files for the purposes of
--- cleaning up.  The preprocessed file *might* be the same as the
--- source file, but that doesn't do any harm.
-ppFilesFromSummaries summaries = [ fn | Just fn <- map ms_hspp_file summaries ]
-
------------------------------------------------------------------------------
--- getValidLinkables
-
--- For each module (or SCC of modules), we take:
---
---     - an on-disk linkable, if this is the first time around and one
---       is available.
---
---     - the old linkable, otherwise (and if one is available).
---
--- and we throw away the linkable if it is older than the source file.
--- In interactive mode, we also ignore the on-disk linkables unless
--- all of the dependents of this SCC also have on-disk linkables (we
--- can't have dynamically loaded objects that depend on interpreted
--- modules in GHCi).
---
--- 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
-       :: GhcMode
-       -> [Linkable]           -- old linkables
-       -> [Module]             -- all home modules
-       -> [SCC ModSummary]     -- all modules in the program, dependency order
-       -> IO ( [Linkable],     -- still-valid linkables 
-               [Linkable]      -- new linkables we just found on the disk
-                               -- presumably generated by separate run of ghc
-             )
-
-getValidLinkables mode old_linkables all_home_mods module_graph
-  = do {       -- Process the SCCs in bottom-to-top order
-               -- (foldM works left-to-right)
-         ls <- foldM (getValidLinkablesSCC mode old_linkables all_home_mods) 
-                     [] module_graph
-       ; return (partition_it ls [] []) }
- where
-  partition_it []         valid new = (valid,new)
-  partition_it ((l,b):ls) valid new 
-       | b         = partition_it ls valid (l:new)
-       | otherwise = partition_it ls (l:valid) new
-
-
-getValidLinkablesSCC
-       :: GhcMode
-       -> [Linkable]           -- old linkables
-       -> [Module]             -- all home modules
-       -> [(Linkable,Bool)]
-       -> SCC ModSummary
-       -> IO [(Linkable,Bool)]
-
-getValidLinkablesSCC mode old_linkables all_home_mods new_linkables scc0
-   = let 
-         scc             = flattenSCC scc0
-          scc_names       = map ms_mod scc
-         home_module m   = m `elem` all_home_mods && m `notElem` scc_names
-          scc_allhomeimps = nub (filter home_module (concatMap ms_imps scc))
-               -- NB. ms_imps, not ms_allimps above.  We don't want to
-               -- force a module's SOURCE imports to be already compiled for
-               -- its object linkable to be valid.
-
-               -- The new_linkables is only the *valid* linkables below here
-         has_object m = case findModuleLinkable_maybe (map fst new_linkables) m of
-                           Nothing -> False
-                           Just l  -> isObjectLinkable l
-
-          objects_allowed = mode == BatchCompile || all has_object scc_allhomeimps
-     in do
-
-     new_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.
-     new_linkables' <- 
-        if objects_allowed
-            && not (all isObjectLinkable (map fst new_linkables'))
-         then foldM (getValidLinkable old_linkables False) [] scc
-         else return new_linkables'
-
-     return (new_linkables ++ new_linkables')
-
-
-getValidLinkable :: [Linkable] -> Bool -> [(Linkable,Bool)] -> ModSummary 
-       -> IO [(Linkable,Bool)]
-       -- True <=> linkable is new; i.e. freshly discovered on the disk
-       --                                presumably generated 'on the side'
-       --                                by a separate GHC run
-getValidLinkable old_linkables objects_allowed new_linkables summary 
-       -- 'objects_allowed' says whether we permit this module to
-       -- have a .o-file linkable.  We only permit it if all the
-       -- modules it depends on also have .o files; a .o file can't
-       -- link to a bytecode module
-   = do let mod_name = ms_mod summary
-
-       maybe_disk_linkable
-          <- if (not objects_allowed)
-               then return Nothing
-
-               else findLinkable mod_name (ms_location summary)
-
-       let old_linkable = findModuleLinkable_maybe old_linkables mod_name
-
-           new_linkables' = 
-            case (old_linkable, maybe_disk_linkable) of
-               (Nothing, Nothing)                      -> []
-
-               -- new object linkable just appeared
-               (Nothing, Just l)                       -> up_to_date l True
-
-               (Just l,  Nothing)
-                 | isObjectLinkable l                  -> []
-                   -- object linkable disappeared!  In case we need to
-                   -- relink the module, disregard the old linkable and
-                   -- just interpret the module from now on.
-                 | otherwise                           -> up_to_date l False
-                   -- old byte code linkable
-
-               (Just l, Just l') 
-                 | not (isObjectLinkable l)            -> up_to_date l  False
-                   -- if the previous linkable was interpreted, then we
-                   -- ignore a newly compiled version, because the version
-                   -- numbers in the interface file will be out-of-sync with
-                   -- our internal ones.
-                 | linkableTime l' >  linkableTime l   -> up_to_date l' True
-                 | linkableTime l' == linkableTime l   -> up_to_date l  False
-                 | otherwise                           -> []
-                   -- on-disk linkable has been replaced by an older one!
-                   -- again, disregard the previous one.
-
-           up_to_date l b
-               | linkableTime l < ms_hs_date summary = []
-               | otherwise = [(l,b)]
-               -- 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, 
-               -- especially if the source was automatically generated
-               -- and compiled.  Using >= is slightly unsafe, but it matches
-               -- make's behaviour.
-
-       return (new_linkables' ++ new_linkables)
-
-
-hptLinkables :: HomePackageTable -> [Linkable]
--- Get all the linkables from the home package table, one for each module
--- Once the HPT is up to date, these are the ones we should link
-hptLinkables hpt = map hm_linkable (moduleEnvElts hpt)
-
-
------------------------------------------------------------------------------
--- 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 HPT (interactive mode only)
-
-preUpsweep :: [Linkable]       -- new valid linkables
-           -> [Module]         -- names of all mods encountered in downsweep
-           -> [ModSummary]     -- accumulating stable modules
-           -> [SCC ModSummary]  -- scc-ified mod graph, including src imps
-           -> IO [ModSummary]  -- stable modules
-
-preUpsweep valid_lis all_home_mods stable []  = return stable
-preUpsweep valid_lis all_home_mods stable (scc0:sccs)
-   = do let scc = flattenSCC scc0
-            scc_allhomeimps :: [Module]
-            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_mods     = map ms_mod scc
-            stable_names = scc_mods ++ map ms_mod stable
-            in_stable_or_scc m = m `elem` stable_names
-
-           -- now we check for valid linkables: each module in the SCC must 
-           -- have a valid linkable (see getValidLinkables above).
-           has_valid_linkable scc_mod
-             = isJust (findModuleLinkable_maybe valid_lis scc_mod)
-
-           scc_is_stable = all_imports_in_scc_or_stable
-                         && all has_valid_linkable scc_mods
-
-        if scc_is_stable
-         then preUpsweep valid_lis all_home_mods (scc ++ stable) sccs
-         else preUpsweep valid_lis all_home_mods stable         sccs
-
-
--- Return (names of) all those in modsDone who are part of a cycle
--- as defined by theGraph.
-findPartiallyCompletedCycles :: [Module] -> [SCC ModSummary] -> [Module]
-findPartiallyCompletedCycles modsDone theGraph
-   = chew theGraph
-     where
-        chew [] = []
-        chew ((AcyclicSCC v):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, 
-                                   done `elem` names_in_this_cycle])
-                 chewed_rest = chew rest
-             in 
-             if   notNull mods_in_this_cycle
-                  && length mods_in_this_cycle < length names_in_this_cycle
-             then mods_in_this_cycle ++ chewed_rest
-             else chewed_rest
-
-
--- Compile multiple modules, stopping as soon as an error appears.
--- There better had not be any cyclic groups here -- we check for them.
-upsweep_mods :: HscEnv                         -- Includes initially-empty HPT
-             -> (HomePackageTable, [Linkable]) -- HPT and valid linkables from last time round
-            -> IO ()                           -- How to clean up unwanted tmp files
-             -> [SCC ModSummary]               -- Mods to do (the worklist)
-             -> IO (SuccessFlag,
-                    HscEnv,            -- With an updated HPT
-                    [ModSummary])      -- Mods which succeeded
-
-upsweep_mods hsc_env oldUI cleanup
-     []
-   = return (Succeeded, hsc_env, [])
-
-upsweep_mods hsc_env oldUI cleanup
-     (CyclicSCC ms:_)
-   = do hPutStrLn stderr (showSDoc (cyclicModuleErr ms))
-        return (Failed, hsc_env, [])
-
-upsweep_mods hsc_env oldUI@(old_hpt, old_linkables) cleanup
-     (AcyclicSCC mod:mods)
-   = do -- putStrLn ("UPSWEEP_MOD: hpt = " ++ 
-       --           show (map (moduleUserString.moduleName.mi_module.hm_iface) 
-       --                     (moduleEnvElts (hsc_HPT hsc_env)))
-
-        mb_mod_info <- upsweep_mod hsc_env oldUI mod 
-
-       cleanup         -- Remove unwanted tmp files between compilations
-
-        case mb_mod_info of
-           Nothing -> return (Failed, hsc_env, [])
-           Just mod_info -> do 
-               { let this_mod = ms_mod mod
-
-                       -- Add new info to hsc_env
-                     hpt1     = extendModuleEnv (hsc_HPT hsc_env) this_mod mod_info
-                     hsc_env1 = hsc_env { hsc_HPT = hpt1 }
-
-                       -- Space-saving: delete the old HPT entry and linkable for mod
-                       -- BUT if mod is a hs-boot node, don't delete it
-                       -- For the linkable this is dead right: the linkable relates only
-                       -- to the main Haskell source file. 
-                       -- For the interface, the HPT entry is probaby for the main Haskell
-                       -- source file.  Deleting it would force 
-                     oldUI1 | isBootSummary mod = oldUI
-                            | otherwise
-                            = (delModuleEnv old_hpt this_mod, 
-                                 delModuleLinkable old_linkables this_mod)
-
-               ; (restOK, hsc_env2, modOKs) <- upsweep_mods hsc_env1 oldUI1 cleanup mods
-               ; return (restOK, hsc_env2, mod:modOKs) }
-
-
--- Compile a single module.  Always produce a Linkable for it if 
--- successful.  If no compilation happened, return the old Linkable.
-upsweep_mod :: HscEnv
-            -> (HomePackageTable, UnlinkedImage)
-            -> ModSummary
-            -> IO (Maybe HomeModInfo)  -- Nothing => Failed
-
-upsweep_mod hsc_env (old_hpt, old_linkables) summary
-   = do 
-        let this_mod = ms_mod summary
-
-       -- The old interface is ok if it's in the old HPT 
-       --      a) we're compiling a source file, and the old HPT entry is for a source file
-       --      b) we're compiling a hs-boot file
-       -- Case (b) allows an hs-boot file to get the interface of its 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 
-               = case lookupModuleEnv old_hpt this_mod of
-                    Nothing                              -> Nothing
-                    Just hm_info | isBootSummary summary -> Just iface
-                                 | not (mi_boot iface)   -> Just iface
-                                 | otherwise             -> Nothing
-                                  where 
-                                    iface = hm_iface hm_info
-
-            maybe_old_linkable = findModuleLinkable_maybe old_linkables this_mod
-            source_unchanged   = isJust maybe_old_linkable
-
-            old_linkable = expectJust "upsweep_mod:old_linkable" maybe_old_linkable
-
-           have_object 
-              | Just l <- maybe_old_linkable, isObjectLinkable l = True
-              | otherwise = False
-
-        compresult <- compile hsc_env summary source_unchanged have_object mb_old_iface
-
-        case compresult of
-
-           -- Compilation "succeeded", and may or may not have returned a new
-           -- linkable (depending on whether compilation was actually performed
-          -- or not).
-           CompOK new_details new_iface maybe_new_linkable
-              -> do let 
-                       new_linkable = maybe_new_linkable `orElse` old_linkable
-                       new_info = HomeModInfo { hm_iface = new_iface,
-                                                hm_details = new_details,
-                                                hm_linkable = new_linkable }
-                    return (Just new_info)
-
-           -- Compilation failed.  Compile may still have updated the PCS, tho.
-           CompErrs -> return Nothing
-
--- Filter modules in the HPT
-retainInTopLevelEnvs :: [Module] -> HomePackageTable -> HomePackageTable
-retainInTopLevelEnvs keep_these hpt
-   = mkModuleEnv [ (mod, fromJust mb_mod_info)
-                | mod <- keep_these
-                , let mb_mod_info = lookupModuleEnv hpt mod
-                , isJust mb_mod_info ]
-
------------------------------------------------------------------------------
-cmTopSort :: Bool              -- Drop hi-boot nodes? (see below)
-         -> [ModSummary]
-         -> [SCC ModSummary]
--- Calculate SCCs of the module graph, possibly dropping the hi-boot nodes
---
--- Drop hi-boot nodes (first boolean arg)? 
---
---   False:    treat the hi-boot summaries as nodes of the graph,
---             so the graph must be acyclic
---
---   True:     eliminate the hi-boot nodes, and instead pretend
---             the a source-import of Foo is an import of Foo
---             The resulting graph has no hi-boot nodes, but can by cyclic
-
-cmTopSort drop_hs_boot_nodes summaries
-   = stronglyConnComp nodes
-   where
-       -- Drop hs-boot nodes by using HsSrcFile as the key
-       hs_boot_key | drop_hs_boot_nodes = HsSrcFile
-                   | otherwise          = HsBootFile   
-
-       -- We use integers as the keys for the SCC algorithm
-       nodes :: [(ModSummary, Int, [Int])]     
-       nodes = [(s, fromJust (lookup_key (ms_hsc_src s) (ms_mod s)), 
-                    out_edge_keys hs_boot_key (ms_srcimps s) ++
-                    out_edge_keys HsSrcFile   (ms_imps s)    )
-               | s <- summaries
-               , not (isBootSummary s && drop_hs_boot_nodes) ]
-               -- Drop the hi-boot ones if told to do so
-
-       key_map :: NodeMap Int
-       key_map = listToFM ([(ms_mod s, ms_hsc_src s) | s <- summaries]
-                          `zip` [1..])
-
-       lookup_key :: HscSource -> Module -> Maybe Int
-       lookup_key hs_src mod = lookupFM key_map (mod, hs_src)
-
-       out_edge_keys :: HscSource -> [Module] -> [Int]
-        out_edge_keys hi_boot ms = mapCatMaybes (lookup_key hi_boot) ms
-               -- If we want keep_hi_boot_nodes, then we do lookup_key with
-               -- the IsBootInterface parameter True; else False
-
-
------------------------------------------------------------------------------
--- Downsweep (dependency analysis)
-
--- Chase downwards from the specified root set, returning summaries
--- for all home modules encountered.  Only follow source-import
--- links.
-
--- We pass in the previous collection of summaries, which is used as a
--- cache to avoid recalculating a module summary if the source is
--- 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 
--- are all there, including the imports of non-home-package modules.
-
-cmDownsweep :: DynFlags
-           -> [FilePath]       -- Roots
-           -> [ModSummary]     -- Old summaries
-           -> [Module]         -- Ignore dependencies on these; treat them as
-                               -- if they were package modules
-           -> IO [ModSummary]
-cmDownsweep dflags roots old_summaries excl_mods
-   = do rootSummaries <- mapM getRootSummary roots
-       checkDuplicates rootSummaries
-        loop (concatMap msDeps rootSummaries) 
-            (mkNodeMap rootSummaries)
-     where
-       old_summary_map :: NodeMap ModSummary
-       old_summary_map = mkNodeMap old_summaries
-
-       getRootSummary :: FilePath -> IO ModSummary
-       getRootSummary file
-          | isHaskellSrcFilename file
-          = do exists <- doesFileExist file
-               if exists then summariseFile dflags file else do
-               throwDyn (CmdLineError ("can't find file `" ++ file ++ "'"))    
-          | otherwise
-          = do exists <- doesFileExist hs_file
-               if exists then summariseFile dflags hs_file else do
-               exists <- doesFileExist lhs_file
-               if exists then summariseFile dflags lhs_file else do
-               let mod_name = mkModule file
-               maybe_summary <- summarise dflags emptyNodeMap Nothing False 
-                                          mod_name excl_mods
-               case maybe_summary of
-                  Nothing -> packageModErr mod_name
-                  Just s  -> return s
-           where 
-                hs_file = file ++ ".hs"
-                lhs_file = file ++ ".lhs"
-
-       -- In a root module, the filename is allowed to diverge from the module
-       -- 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 :: [ModSummary] -> IO ()
-       checkDuplicates summaries = mapM_ check summaries
-         where check summ = 
-                 case dups of
-                       []     -> return ()
-                       [_one] -> return ()
-                       many   -> multiRootsErr modl many
-                  where modl = ms_mod summ
-                        dups = 
-                          [ fromJust (ml_hs_file (ms_location summ'))
-                          | summ' <- summaries, ms_mod summ' == modl ]
-
-       loop :: [(FilePath,Module,IsBootInterface)]     -- Work list: process these modules
-            -> NodeMap ModSummary      -- Visited set
-            -> IO [ModSummary]         -- The result includes the worklist, except 
-                                       -- for those mentioned in the visited set
-       loop [] done      = return (nodeMapElts done)
-       loop ((cur_path, wanted_mod, is_boot) : ss) done 
-         | key `elemFM` done = loop ss done
-         | otherwise         = do { mb_s <- summarise dflags old_summary_map 
-                                                (Just cur_path) is_boot 
-                                                wanted_mod excl_mods
-                                  ; case mb_s of
-                                       Nothing -> loop ss done
-                                       Just s  -> loop (msDeps s ++ ss) 
-                                                       (addToFM done key s) }
-         where
-           key = (wanted_mod, if is_boot then HsBootFile else HsSrcFile)
-
-msDeps :: ModSummary -> [(FilePath,            -- Importing module
-                         Module,               -- Imported module
-                         IsBootInterface)]      -- {-# SOURCE #-} import or not
--- (msDeps s) returns the dependencies of the ModSummary s.
--- A wrinkle is that for a {-# SOURCE #-} import we return
---     *both* the hs-boot file
---     *and* the source file
--- as "dependencies".  That ensures that the list of all relevant
--- 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 s =  concat [ [(f, m, True), (f,m,False)] | m <- ms_srcimps s] 
-        ++ [(f,m,False) | m <- ms_imps    s] 
-       where
-         f = msHsFilePath s    -- Keep the importing module for error reporting
-
-
------------------------------------------------------------------------------
--- Summarising modules
-
--- We have two types of summarisation:
---
---    * Summarise a file.  This is used for the root module(s) passed to
---     cmLoadModules.  The file is read, and used to determine the root
---     module name.  The module name may differ from the filename.
---
---    * Summarise a module.  We are given a module name, and must provide
---     a summary.  The finder is used to locate the file in which the module
---     resides.
-
-summariseFile :: DynFlags -> FilePath -> IO ModSummary
--- Used for Haskell source only, I think
--- We know the file name, and we know it exists,
--- but we don't necessarily know the module name (might differ)
-summariseFile dflags file
-   = do (dflags', hspp_fn) <- preprocess dflags file
-               -- The dflags' contains the OPTIONS pragmas
-
-       -- Read the file into a buffer.  We're going to cache
-       -- this buffer in the ModLocation (ml_hspp_buf) so that it
-       -- doesn't have to be slurped again when hscMain parses the
-       -- file later.
-       buf <- hGetStringBuffer hspp_fn
-        (srcimps,the_imps,mod) <- getImports dflags' buf hspp_fn
-
-       -- Make a ModLocation for this file
-       location <- mkHomeModLocation dflags mod file
-
-       -- Tell the Finder cache where it is, so that subsequent calls
-       -- to findModule will find it, even if it's not on any search path
-       addHomeModuleToFinder mod location
-
-        src_timestamp <- getModificationTime file
-        return (ModSummary { ms_mod = mod, ms_hsc_src = HsSrcFile,
-                            ms_location = location,
-                             ms_hspp_file = Just hspp_fn,
-                            ms_hspp_buf  = Just buf,
-                             ms_srcimps = srcimps, ms_imps = the_imps,
-                            ms_hs_date = src_timestamp })
-
--- Summarise a module, and pick up source and timestamp.
-summarise :: DynFlags 
-         -> NodeMap ModSummary -- Map of old summaries
-         -> Maybe FilePath     -- Importing module (for error messages)
-         -> IsBootInterface    -- True <=> a {-# SOURCE #-} import
-         -> Module             -- Imported module to be summarised
-         -> [Module]           -- Modules to exclude
-         -> IO (Maybe ModSummary)      -- Its new summary
-
-summarise dflags old_summary_map cur_mod is_boot wanted_mod excl_mods
-  | wanted_mod `elem` excl_mods
-  = return Nothing
-
-  | Just old_summary <- lookupFM old_summary_map (wanted_mod, hsc_src)
-  = 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 = fromJust (ml_hs_file location)
-
-       ;  src_timestamp <- getModificationTime src_fn
-
-               -- return the cached summary if the source didn't change
-       ; if ms_hs_date old_summary == src_timestamp 
-         then return (Just old_summary)
-         else new_summary location
-       }
-
-  | otherwise
-  = do { found <- findModule dflags wanted_mod True {-explicit-}
-       ; case found of
-            Found location pkg 
-               | not (isHomePackage pkg)      -> return Nothing        -- Drop external-pkg
-               | isJust (ml_hs_file location) -> new_summary location  -- Home package
-            err        -> noModError dflags cur_mod wanted_mod err     -- Not found
-       }
-  where
-    hsc_src = if is_boot then HsBootFile else HsSrcFile
-
-    new_summary location
-      = do {   -- 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
-             src_fn = fromJust (ml_hs_file location')
-
-               -- Check that it exists
-               -- It might have been deleted since the Finder last found it
-       ; exists <- doesFileExist src_fn
-       ; if exists then return () else noHsFileErr cur_mod src_fn
-
-       -- Preprocess the source file and get its imports
-       -- The dflags' contains the OPTIONS pragmas
-       ; (dflags', hspp_fn) <- preprocess dflags src_fn
-       ; buf <- hGetStringBuffer hspp_fn
-        ; (srcimps, the_imps, mod_name) <- getImports dflags' buf hspp_fn
-
-       ; when (mod_name /= wanted_mod) $
-               throwDyn (ProgramError 
-                  (showSDoc (text src_fn
-                             <>  text ": file name does not match module name"
-                             <+> quotes (ppr mod_name))))
-
-               -- Find its timestamp, and return the summary
-        ; src_timestamp <- getModificationTime src_fn
-       ; return (Just ( ModSummary { ms_mod       = wanted_mod, 
-                                     ms_hsc_src   = hsc_src,
-                                     ms_location  = location',
-                                     ms_hspp_file = Just hspp_fn,
-                                     ms_hspp_buf  = Just buf,
-                                     ms_srcimps   = srcimps,
-                                     ms_imps      = the_imps,
-                                     ms_hs_date   = src_timestamp }))
-       }
-
-
------------------------------------------------------------------------------
---                     Error messages
------------------------------------------------------------------------------
-
-noModError :: DynFlags -> Maybe FilePath -> Module -> FindResult -> IO ab
--- ToDo: we don't have a proper line number for this error
-noModError dflags cur_mod wanted_mod err
-  = throwDyn $ ProgramError $ showSDoc $
-    vcat [cantFindError dflags wanted_mod err,
-         nest 2 (parens (pp_where cur_mod))]
-                               
-noHsFileErr cur_mod path
-  = throwDyn $ CmdLineError $ showSDoc $
-    vcat [text "Can't find" <+> text path,
-         nest 2 (parens (pp_where cur_mod))]
-pp_where Nothing  = text "one of the roots of the dependency analysis"
-pp_where (Just p) = text "imported from" <+> text p
-
-packageModErr mod
-  = throwDyn (CmdLineError (showSDoc (text "module" <+>
-                                  quotes (ppr mod) <+>
-                                  text "is a package module")))
-
-multiRootsErr mod files
-  = throwDyn (ProgramError (showSDoc (
-       text "module" <+> quotes (ppr mod) <+> 
-       text "is defined in multiple files:" <+>
-       sep (map text files))))
-
-cyclicModuleErr :: [ModSummary] -> SDoc
-cyclicModuleErr ms
-  = hang (ptext SLIT("Module imports form a cycle for modules:"))
-       2 (vcat (map show_one ms))
-  where
-    show_one ms = sep [ show_mod (ms_hsc_src ms) (ms_mod ms),
-                       nest 2 $ ptext SLIT("imports:") <+> 
-                                  (pp_imps HsBootFile (ms_srcimps ms)
-                                  $$ pp_imps HsSrcFile  (ms_imps ms))]
-    show_mod hsc_src mod = ppr mod <> text (hscSourceString hsc_src)
-    pp_imps src mods = fsep (map (show_mod src) mods)
-\end{code}
-
index 0939218..51fcd8e 100644 (file)
@@ -1,37 +1,42 @@
 {-# OPTIONS -#include "Linker.h" #-}
 -----------------------------------------------------------------------------
--- $Id: InteractiveUI.hs,v 1.195 2005/03/18 17:16:03 simonpj Exp $
 --
 -- GHC Interactive User Interface
 --
--- (c) The GHC Team 2004
+-- (c) The GHC Team 2005
 --
 -----------------------------------------------------------------------------
 module InteractiveUI ( 
-       interactiveUI,  -- :: CmState -> [FilePath] -> IO ()
+       interactiveUI,
        ghciWelcomeMsg
    ) where
 
 #include "HsVersions.h"
 
-import CompManager
+-- The GHC interface
+import qualified GHC
+import GHC             ( Session, verbosity, dopt, DynFlag(..),
+                         mkModule, pprModule, Type, Module, SuccessFlag(..),
+                         TyThing(..), Name )
+import Outputable
+
+-- following all needed for :info... ToDo: remove
 import IfaceSyn                ( IfaceDecl(..), IfaceClassOp(..), IfaceConDecls(..),
                          IfaceConDecl(..), IfaceType,
                          pprIfaceDeclHead, pprParendIfaceType,
                          pprIfaceForAllPart, pprIfaceType )
 import FunDeps         ( pprFundeps )
-import Util            ( removeSpaces, handle )
-import Linker          ( showLinkerState, linkPackages )
-import Util
-import Name            ( Name, NamedThing(..) )
+import SrcLoc          ( SrcLoc, isGoodSrcLoc )
 import OccName         ( OccName, parenSymOcc, occNameUserString )
-import BasicTypes      ( StrictnessMark(..), defaultFixity, SuccessFlag(..) )
-import Outputable
-import DynFlags
+import BasicTypes      ( StrictnessMark(..), defaultFixity )
+
+-- Other random utilities
 import Panic           hiding ( showException )
 import Config
-import SrcLoc          ( SrcLoc, isGoodSrcLoc )
 import StaticFlags     ( opt_IgnoreDotGhci )
+import Linker          ( showLinkerState )
+import Util            ( removeSpaces, handle, global, toArgs,
+                         looksLikeModuleName, prefixMatch )
 
 #ifndef mingw32_HOST_OS
 import Util            ( handle )
@@ -151,10 +156,8 @@ helpText =
  "                         (eg. -v2, -fglasgow-exts, etc.)\n"
 
 
-interactiveUI :: DynFlags -> [FilePath] -> Maybe String -> IO ()
-interactiveUI dflags srcs maybe_expr = do
-
-   cmstate <- cmInit dflags;
+interactiveUI :: Session -> [FilePath] -> Maybe String -> IO ()
+interactiveUI session srcs maybe_expr = do
 
    -- HACK! If we happen to get into an infinite loop (eg the user
    -- types 'let x=x in x' at the prompt), then the thread will block
@@ -172,24 +175,23 @@ interactiveUI dflags srcs maybe_expr = do
    hSetBuffering stdout NoBuffering
 
        -- Initialise buffering for the *interpreted* I/O system
-   initInterpBuffering cmstate
+   initInterpBuffering session
 
        -- We don't want the cmd line to buffer any input that might be
        -- intended for the program, so unbuffer stdin.
    hSetBuffering stdin NoBuffering
 
        -- initial context is just the Prelude
-   cmstate <- cmSetContext cmstate [] ["Prelude"]
+   GHC.setContext session [] [prelude_mod]
 
 #ifdef USE_READLINE
    Readline.initialize
 #endif
 
-   startGHCi (runGHCi srcs dflags maybe_expr)
+   startGHCi (runGHCi srcs maybe_expr)
        GHCiState{ progname = "<interactive>",
                   args = [],
-                  targets = srcs,
-                  cmstate = cmstate,
+                  session = session,
                   options = [] }
 
 #ifdef USE_READLINE
@@ -198,8 +200,8 @@ interactiveUI dflags srcs maybe_expr = do
 
    return ()
 
-runGHCi :: [FilePath] -> DynFlags -> Maybe String -> GHCi ()
-runGHCi paths dflags maybe_expr = do
+runGHCi :: [FilePath] -> Maybe String -> GHCi ()
+runGHCi paths maybe_expr = do
   let read_dot_files = not opt_IgnoreDotGhci
 
   when (read_dot_files) $ do
@@ -239,6 +241,7 @@ runGHCi paths dflags maybe_expr = do
   -- if verbosity is greater than 0, or we are connected to a
   -- terminal, display the prompt in the interactive loop.
   is_tty <- io (hIsTerminalDevice stdin)
+  dflags <- getDynFlags
   let show_prompt = verbosity dflags > 0 || is_tty
 
   case maybe_expr of
@@ -303,8 +306,8 @@ checkPerms name =
 
 fileLoop :: Handle -> Bool -> GHCi ()
 fileLoop hdl prompt = do
-   cmstate <- getCmState
-   (mod,imports) <- io (cmGetContext cmstate)
+   session <- getSession
+   (mod,imports) <- io (GHC.getContext session)
    when prompt (io (putStr (mkPrompt mod imports)))
    l <- io (IO.try (hGetLine hdl))
    case l of
@@ -331,13 +334,15 @@ stringLoop (s:ss) = do
                  if quit then return () else stringLoop ss
 
 mkPrompt toplevs exports
-   = concat (intersperse " " (map ('*':) toplevs ++ exports)) ++ "> "
+  = showSDoc (hsep (map (\m -> char '*' <> pprModule m) toplevs)
+            <+> hsep (map pprModule exports)
+            <> text "> ")
 
 #ifdef USE_READLINE
 readlineLoop :: GHCi ()
 readlineLoop = do
-   cmstate <- getCmState
-   (mod,imports) <- io (cmGetContext cmstate)
+   session <- getSession
+   (mod,imports) <- io (GHC.getContext session)
    io yield
    l <- io (readline (mkPrompt mod imports)
                `finally` setNonBlockingFD 0)
@@ -402,21 +407,19 @@ runStmt stmt
  | null (filter (not.isSpace) stmt) = return []
  | otherwise
  = do st <- getGHCiState
-      cmstate <- getCmState
-      (new_cmstate, result) <- 
-       io $ withProgName (progname st) $ withArgs (args st) $
-            cmRunStmt cmstate stmt
-      setGHCiState st{cmstate = new_cmstate}
+      session <- getSession
+      result <- io $ withProgName (progname st) $ withArgs (args st) $
+                    GHC.runStmt session stmt
       case result of
-       CmRunFailed      -> return []
-       CmRunException e -> throw e  -- this is caught by runCommand(Eval)
-       CmRunOk names    -> return names
+       GHC.RunFailed      -> return []
+       GHC.RunException e -> throw e  -- this is caught by runCommand(Eval)
+       GHC.RunOk names    -> return names
 
 -- possibly print the type and revert CAFs after evaluating an expression
 finishEvalExpr names
  = do b <- isOptionSet ShowType
-      cmstate <- getCmState
-      when b (mapM_ (showTypeOfName cmstate) names)
+      session <- getSession
+      when b (mapM_ (showTypeOfName session) names)
 
       flushInterpBuffers
       io installSignalHandlers
@@ -424,12 +427,18 @@ finishEvalExpr names
       io (when b revertCAFs)
       return True
 
-showTypeOfName :: CmState -> Name -> GHCi ()
-showTypeOfName cmstate n
-   = do maybe_str <- io (cmTypeOfName cmstate n)
-       case maybe_str of
-         Nothing  -> return ()
-         Just str -> io (putStrLn (showSDoc (ppr n) ++ " :: " ++ str))
+showTypeOfName :: Session -> Name -> GHCi ()
+showTypeOfName session n
+   = do maybe_tything <- io (GHC.lookupName session n)
+       case maybe_tything of
+         Nothing    -> return ()
+         Just thing -> showTyThing thing
+
+showForUser :: SDoc -> GHCi String
+showForUser doc = do
+  session <- getSession
+  unqual <- io (GHC.getPrintUnqual session)
+  return $! showSDocForUser unqual doc
 
 specialCommand :: String -> GHCi Bool
 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
@@ -459,15 +468,15 @@ no_buf_cmd = "System.IO.hSetBuffering System.IO.stdout System.IO.NoBuffering" ++
             " Prelude.>> System.IO.hSetBuffering System.IO.stderr System.IO.NoBuffering"
 flush_cmd  = "System.IO.hFlush System.IO.stdout Prelude.>> System.IO.hFlush IO.stderr"
 
-initInterpBuffering :: CmState -> IO ()
-initInterpBuffering cmstate
- = do maybe_hval <- cmCompileExpr cmstate no_buf_cmd
+initInterpBuffering :: Session -> IO ()
+initInterpBuffering session
+ = do maybe_hval <- GHC.compileExpr session no_buf_cmd
        
       case maybe_hval of
        Just hval -> writeIORef turn_off_buffering (unsafeCoerce# hval :: IO ())
        other     -> panic "interactiveUI:setBuffering"
        
-      maybe_hval <- cmCompileExpr cmstate flush_cmd
+      maybe_hval <- GHC.compileExpr session flush_cmd
       case maybe_hval of
        Just hval -> writeIORef flush_interp (unsafeCoerce# hval :: IO ())
        _         -> panic "interactiveUI:flush"
@@ -496,17 +505,18 @@ help _ = io (putStr helpText)
 info :: String -> GHCi ()
 info "" = throwDyn (CmdLineError "syntax: ':i <thing-you-want-info-about>'")
 info s  = do { let names = words s
-            ; init_cms <- getCmState
+            ; session <- getSession
             ; dflags <- getDynFlags
             ; let exts = dopt Opt_GlasgowExts dflags
-            ; mapM_ (infoThing exts init_cms) names }
+            ; mapM_ (infoThing exts session) names }
   where
-    infoThing exts cms name
-       = do { stuff <- io (cmGetInfo cms name)
-            ; io (putStrLn (showSDocForUser (cmGetPrintUnqual cms) $
+    infoThing exts session name
+       = do { stuff <- io (GHC.getInfo session name)
+            ; unqual <- io (GHC.getPrintUnqual session)
+            ; io (putStrLn (showSDocForUser unqual $
                   vcat (intersperse (text "") (map (showThing exts) stuff)))) }
 
-showThing :: Bool -> GetInfoResult -> SDoc
+showThing :: Bool -> GHC.GetInfoResult -> SDoc
 showThing exts (wanted_str, thing, fixity, src_loc, insts) 
     = vcat [ showWithLoc src_loc (showDecl exts want_name thing),
             show_fixity fixity,
@@ -540,7 +550,7 @@ showDecl exts want_name (IfaceForeign {ifName = tc})
   = ppr tc <+> ptext SLIT("is a foreign type")
 
 showDecl exts want_name (IfaceId {ifName = var, ifType = ty})
-  = ppr var <+> dcolon <+> showType exts ty 
+  = ppr var <+> dcolon <+> showIfaceType exts ty 
 
 showDecl exts want_name (IfaceSyn {ifName = tycon, ifTyVars = tyvars, ifSynRhs = mono_ty})
   = hang (ptext SLIT("type") <+> pprIfaceDeclHead [] tycon tyvars)
@@ -603,13 +613,13 @@ showDecl exts want_name (IfaceClass {ifCtxt = context, ifName = clas, ifTyVars =
              | otherwise = ptext SLIT("where")
     show_op (IfaceClassOp op dm ty) 
        | want_name clas || want_name op 
-       = Just (ppr_bndr op <+> dcolon <+> showType exts ty)
+       = Just (ppr_bndr op <+> dcolon <+> showIfaceType exts ty)
        | otherwise
        = Nothing
 
-showType :: Bool -> IfaceType -> SDoc
-showType True  ty = pprIfaceType ty -- -fglasgow-exts: print with the foralls
-showType False ty = ppr ty         -- otherwise, print without the foralls
+showIfaceType :: Bool -> IfaceType -> SDoc
+showIfaceType True  ty = pprIfaceType ty -- -fglasgow-exts: print with the foralls
+showIfaceType False ty = ppr ty            -- otherwise, print without the foralls
 
 ppr_trim :: (a -> Maybe SDoc) -> [a] -> [SDoc]
 ppr_trim show xs
@@ -630,25 +640,24 @@ ppr_bndr occ = parenSymOcc occ (ppr occ)
 
 addModule :: [FilePath] -> GHCi ()
 addModule files = do
-  state <- getGHCiState
   io (revertCAFs)                      -- always revert CAFs on load/add.
   files <- mapM expandPath files
-  let new_targets = files ++ targets state 
-  graph <- io (cmDepAnal (cmstate state) new_targets)
-  (cmstate1, ok, mods) <- io (cmLoadModules (cmstate state) graph)
-  setGHCiState state{ cmstate = cmstate1, targets = new_targets }
-  setContextAfterLoad mods
-  dflags <- getDynFlags
-  modulesLoadedMsg ok mods dflags
+  targets <- mapM (io . GHC.guessTarget) files
+  session <- getSession
+  io (mapM_ (GHC.addTarget session) targets)
+  ok <- io (GHC.load session Nothing)
+  afterLoad ok session
 
 changeDirectory :: String -> GHCi ()
 changeDirectory dir = do
-  state    <- getGHCiState
-  when (targets state /= []) $
+  session <- getSession
+  graph <- io (GHC.getModuleGraph session)
+  when (not (null graph)) $
        io $ putStr "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed.\n"
-  cmstate1 <- io (cmUnload (cmstate state))
-  setGHCiState state{ cmstate = cmstate1, targets = [] }
+  io (GHC.setTargets session [])
+  io (GHC.load session Nothing)
   setContextAfterLoad []
+  io (GHC.workingDirectoryChanged session)
   dir <- expandPath dir
   io (setCurrentDirectory dir)
 
@@ -669,14 +678,14 @@ defineMacro s = do
   let new_expr = '(' : definition ++ ") :: String -> IO String"
 
   -- compile the expression
-  cms <- getCmState
-  maybe_hv <- io (cmCompileExpr cms new_expr)
+  cms <- getSession
+  maybe_hv <- io (GHC.compileExpr cms new_expr)
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
                    ((macro_name, keepGoing (runMacro hv)) : cmds))
 
-runMacro :: HValue{-String -> IO String-} -> String -> GHCi ()
+runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi ()
 runMacro fun s = do
   str <- io ((unsafeCoerce# fun :: String -> IO String) s)
   stringLoop (lines str)
@@ -700,60 +709,58 @@ loadModule fs = timeIt (loadModule' fs)
 
 loadModule' :: [FilePath] -> GHCi ()
 loadModule' files = do
-  state <- getGHCiState
+  session <- getSession
+
+  -- unload first
+  io (GHC.setTargets session [])
+  io (GHC.load session Nothing)
 
   -- expand tildes
   files <- mapM expandPath files
+  targets <- io (mapM GHC.guessTarget files)
 
-  -- do the dependency anal first, so that if it fails we don't throw
-  -- away the current set of modules.
-  graph <- io (cmDepAnal (cmstate state) files)
+  -- NOTE: we used to do the dependency anal first, so that if it
+  -- fails we didn't throw away the current set of modules.  This would
+  -- require some re-working of the GHC interface, so we'll leave it
+  -- as a ToDo for now.
 
-  -- Dependency anal ok, now unload everything
-  cmstate1 <- io (cmUnload (cmstate state))
-  setGHCiState state{ cmstate = cmstate1, targets = [] }
-
-  io (revertCAFs)  -- always revert CAFs on load.
-  (cmstate2, ok, mods) <- io (cmLoadModules cmstate1 graph)
-  setGHCiState state{ cmstate = cmstate2, targets = files }
-
-  setContextAfterLoad mods
-  dflags <- getDynFlags
-  modulesLoadedMsg ok mods dflags
+  io (GHC.setTargets session targets)
+  ok <- io (GHC.load session Nothing)
+  afterLoad ok session
 
 
 reloadModule :: String -> GHCi ()
 reloadModule "" = do
-  state <- getGHCiState
-  case targets state of
-   [] -> io (putStr "no current target\n")
-   paths -> do
-       -- do the dependency anal first, so that if it fails we don't throw
-       -- away the current set of modules.
-       graph <- io (cmDepAnal (cmstate state) paths)
-
-       io (revertCAFs)         -- always revert CAFs on reload.
-       (cmstate1, ok, mods) 
-               <- io (cmLoadModules (cmstate state) graph)
-        setGHCiState state{ cmstate=cmstate1 }
-       setContextAfterLoad mods
-       dflags <- getDynFlags
-       modulesLoadedMsg ok mods dflags
-
+  io (revertCAFs)              -- always revert CAFs on reload.
+  session <- getSession
+  ok <- io (GHC.load session Nothing)
+  afterLoad ok session
 reloadModule _ = noArgs ":reload"
 
-setContextAfterLoad [] = setContext prel
+afterLoad ok session = do
+  io (revertCAFs)  -- always revert CAFs on load.
+  graph <- io (GHC.getModuleGraph session)
+  let mods = map GHC.ms_mod graph
+  setContextAfterLoad mods
+  modulesLoadedMsg ok mods
+
+setContextAfterLoad [] = do
+  session <- getSession
+  io (GHC.setContext session [] [prelude_mod])
 setContextAfterLoad (m:_) = do
-  cmstate <- getCmState
-  b <- io (cmModuleIsInterpreted cmstate m)
-  if b then setContext ('*':m) else setContext m
+  session <- getSession
+  b <- io (GHC.moduleIsInterpreted session m)
+  if b then io (GHC.setContext session [m] []) 
+       else io (GHC.setContext session []  [m])
 
-modulesLoadedMsg ok mods dflags =
+modulesLoadedMsg :: SuccessFlag -> [Module] -> GHCi ()
+modulesLoadedMsg ok mods = do
+  dflags <- getDynFlags
   when (verbosity dflags > 0) $ do
    let mod_commas 
        | null mods = text "none."
        | otherwise = hsep (
-           punctuate comma (map text mods)) <> text "."
+           punctuate comma (map pprModule mods)) <> text "."
    case ok of
     Failed ->
        io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
@@ -763,19 +770,22 @@ modulesLoadedMsg ok mods dflags =
 
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
-  = do cms <- getCmState
-       maybe_tystr <- io (cmTypeOfExpr cms str)
-       case maybe_tystr of
-         Nothing    -> return ()
-         Just tystr -> io (putStrLn tystr)
+  = do cms <- getSession
+       maybe_ty <- io (GHC.exprType cms str)
+       case maybe_ty of
+         Nothing -> return ()
+         Just ty -> do ty' <- cleanType ty
+                       tystr <- showForUser (ppr ty')
+                       io (putStrLn (str ++ " :: " ++ tystr))
 
 kindOfType :: String -> GHCi ()
 kindOfType str 
-  = do cms <- getCmState
-       maybe_tystr <- io (cmKindOfType cms str)
-       case maybe_tystr of
+  = do cms <- getSession
+       maybe_ty <- io (GHC.typeKind cms str)
+       case maybe_ty of
          Nothing    -> return ()
-         Just tystr -> io (putStrLn tystr)
+         Just ty    -> do tystr <- showForUser (ppr ty)
+                          io (putStrLn (str ++ " :: " ++ tystr))
 
 quit :: String -> GHCi Bool
 quit _ = return True
@@ -794,22 +804,22 @@ browseCmd m =
     _ -> throwDyn (CmdLineError "syntax:  :browse <module>")
 
 browseModule m exports_only = do
-  cms <- getCmState
+  s <- getSession
 
-  is_interpreted <- io (cmModuleIsInterpreted cms m)
+  let modl = mkModule m
+  is_interpreted <- io (GHC.moduleIsInterpreted s modl)
   when (not is_interpreted && not exports_only) $
        throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
 
   -- Temporarily set the context to the module we're interested in,
   -- just so we can get an appropriate PrintUnqualified
-  (as,bs) <- io (cmGetContext cms)
-  cms1 <- io (if exports_only then cmSetContext cms [] [prel,m]
-                             else cmSetContext cms [m] [])
-  cms2 <- io (cmSetContext cms1 as bs)
+  (as,bs) <- io (GHC.getContext s)
+  io (if exports_only then GHC.setContext s [] [prelude_mod,modl]
+                     else GHC.setContext s [modl] [])
+  io (GHC.setContext s as bs)
 
-  things <- io (cmBrowseModule cms2 m exports_only)
-
-  let unqual = cmGetPrintUnqual cms1 -- NOTE: cms1 with the new context
+  things <- io (GHC.browseModule s modl exports_only)
+  unqual <- io (GHC.getPrintUnqual s)
 
   dflags <- getDynFlags
   let exts = dopt Opt_GlasgowExts dflags
@@ -833,47 +843,46 @@ setContext str
     sensible m       = looksLikeModuleName m
 
 newContext mods = do
-  cms <- getCmState
-  (as,bs) <- separate cms mods [] []
-  let bs' = if null as && prel `notElem` bs then prel:bs else bs
-  cms' <- io (cmSetContext cms as bs')
-  setCmState cms'
-
-separate cmstate []           as bs = return (as,bs)
-separate cmstate (('*':m):ms) as bs = do
-   b <- io (cmModuleIsInterpreted cmstate m)
-   if b then separate cmstate ms (m:as) bs
+  session <- getSession
+  (as,bs) <- separate session mods [] []
+  let bs' = if null as && prelude_mod `notElem` bs then prelude_mod:bs else bs
+  io (GHC.setContext session as bs')
+
+separate :: Session -> [String] -> [Module] -> [Module]
+  -> GHCi ([Module],[Module])
+separate session []           as bs = return (as,bs)
+separate session (('*':m):ms) as bs = do
+   let modl = mkModule m
+   b <- io (GHC.moduleIsInterpreted session modl)
+   if b then separate session ms (modl:as) bs
        else throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
-separate cmstate (m:ms)       as bs = separate cmstate ms as (m:bs)
+separate session (m:ms)       as bs = separate session ms as (mkModule m:bs)
 
-prel = "Prelude"
+prelude_mod = mkModule "Prelude"
 
 
 addToContext mods = do
-  cms <- getCmState
-  (as,bs) <- io (cmGetContext cms)
+  cms <- getSession
+  (as,bs) <- io (GHC.getContext cms)
 
   (as',bs') <- separate cms mods [] []
 
   let as_to_add = as' \\ (as ++ bs)
       bs_to_add = bs' \\ (as ++ bs)
 
-  cms' <- io (cmSetContext cms
-                       (as ++ as_to_add) (bs ++ bs_to_add))
-  setCmState cms'
+  io (GHC.setContext cms (as ++ as_to_add) (bs ++ bs_to_add))
 
 
 removeFromContext mods = do
-  cms <- getCmState
-  (as,bs) <- io (cmGetContext cms)
+  cms <- getSession
+  (as,bs) <- io (GHC.getContext cms)
 
   (as_to_remove,bs_to_remove) <- separate cms mods [] []
 
   let as' = as \\ (as_to_remove ++ bs_to_remove)
       bs' = bs \\ (as_to_remove ++ bs_to_remove)
 
-  cms' <- io (cmSetContext cms as' bs')
-  setCmState cms'
+  io (GHC.setContext cms as' bs')
 
 ----------------------------------------------------------------------------
 -- Code for `:set'
@@ -918,7 +927,7 @@ setOptions wds =
 
       -- then, dynamic flags
       dflags <- getDynFlags
-      (dflags',leftovers) <- io $ parseDynamicFlags dflags minus_opts
+      (dflags',leftovers) <- io $ GHC.parseDynamicFlags dflags minus_opts
       setDynFlags dflags'
 
         -- update things if the users wants more packages
@@ -979,13 +988,15 @@ optToStr ShowTiming = "s"
 optToStr ShowType   = "t"
 optToStr RevertCAFs = "r"
 
+{- ToDo
 newPackages new_pkgs = do      -- The new packages are already in v_Packages
-  state    <- getGHCiState
-  cmstate1 <- io (cmUnload (cmstate state))
-  setGHCiState state{ cmstate = cmstate1, targets = [] }
+  session <- getSession
+  io (GHC.setTargets session [])
+  io (GHC.load session Nothing)
   dflags   <- getDynFlags
   io (linkPackages dflags new_pkgs)
   setContextAfterLoad []
+-}
 
 -- ---------------------------------------------------------------------------
 -- code for `:show'
@@ -997,21 +1008,33 @@ showCmd str =
        ["linker"]   -> io showLinkerState
        _ -> throwDyn (CmdLineError "syntax:  :show [modules|bindings]")
 
-showModules
-  = do { cms <- getCmState
-       ; let show_one ms = io (putStrLn (cmShowModule cms ms))
-       ; mapM_ show_one (cmGetModuleGraph cms) }
+showModules = do
+  session <- getSession
+  let show_one ms = do m <- io (GHC.showModule session ms)
+                      io (putStrLn m)
+  graph <- io (GHC.getModuleGraph session)
+  mapM_ show_one graph
 
 showBindings = do
-  cms <- getCmState
-  let
-       unqual = cmGetPrintUnqual cms
---     showBinding b = putStrLn (showSDocForUser unqual (ppr (ifaceTyThing b)))
-       showBinding b = putStrLn (showSDocForUser unqual (ppr (getName b)))
-
-  io (mapM_ showBinding (cmGetBindings cms))
+  s <- getSession
+  unqual <- io (GHC.getPrintUnqual s)
+  bindings <- io (GHC.getBindings s)
+  mapM_ showTyThing bindings
   return ()
 
+showTyThing (AnId id) = do 
+  ty' <- cleanType (GHC.idType id)
+  str <- showForUser (ppr id <> text " :: " <> ppr ty')
+  io (putStrLn str)
+showTyThing _  = return ()
+
+-- if -fglasgow-exts is on we show the foralls, otherwise we don't.
+cleanType :: Type -> GHCi Type
+cleanType ty = do
+  dflags <- getDynFlags
+  if dopt Opt_GlasgowExts dflags 
+       then return ty
+       else return $! GHC.dropForAlls ty
 
 -----------------------------------------------------------------------------
 -- GHCi monad
@@ -1020,8 +1043,7 @@ data GHCiState = GHCiState
      { 
        progname       :: String,
        args           :: [String],
-       targets        :: [FilePath],
-       cmstate        :: CmState,
+       session        :: GHC.Session,
        options        :: [GHCiOption]
      }
 
@@ -1048,12 +1070,14 @@ getGHCiState   = GHCi $ \r -> readIORef r
 setGHCiState s = GHCi $ \r -> writeIORef r s
 
 -- for convenience...
-getCmState = getGHCiState >>= return . cmstate
-setCmState cms = do s <- getGHCiState; setGHCiState s{cmstate=cms}
-
-getDynFlags = getCmState >>= return . cmGetDFlags
-
-setDynFlags dflags = do s <- getCmState; setCmState (cmSetDFlags s dflags)
+getSession = getGHCiState >>= return . session
+
+getDynFlags = do
+  s <- getSession
+  io (GHC.getSessionDynFlags s)
+setDynFlags dflags = do 
+  s <- getSession 
+  io (GHC.setSessionDynFlags s dflags)
 
 isOptionSet :: GHCiOption -> GHCi Bool
 isOptionSet opt
index b582e7e..6db6b45 100644 (file)
@@ -315,7 +315,7 @@ linkExpr hsc_env root_ul_bco
 
        -- Find what packages and linkables are required
    ; eps <- readIORef (hsc_EPS hsc_env)
-   ; (lnks, pkgs) <- getLinkDeps dflags hpt (eps_PIT eps) needed_mods
+   ; (lnks, pkgs) <- getLinkDeps hsc_env hpt (eps_PIT eps) needed_mods
 
        -- Link the packages and modules required
    ; linkPackages dflags pkgs
@@ -350,12 +350,12 @@ linkExpr hsc_env root_ul_bco
  
 dieWith msg = throwDyn (ProgramError (showSDoc msg))
 
-getLinkDeps :: DynFlags -> HomePackageTable -> PackageIfaceTable
+getLinkDeps :: HscEnv -> HomePackageTable -> PackageIfaceTable
            -> [Module]                         -- If you need these
            -> IO ([Linkable], [PackageId])     -- ... then link these first
 -- Fails with an IO exception if it can't find enough files
 
-getLinkDeps dflags hpt pit mods
+getLinkDeps hsc_env hpt pit mods
 -- Find all the packages and linkables that a set of modules depends on
  = do {        pls <- readIORef v_PersistentLinkerState ;
        let {
@@ -404,7 +404,7 @@ getLinkDeps dflags hpt pit mods
        | otherwise     
        =       -- It's not in the HPT because we are in one shot mode, 
                -- so use the Finder to get a ModLocation...
-         do { mb_stuff <- findModule dflags mod_name False ;
+         do { mb_stuff <- findModule hsc_env mod_name False ;
               case mb_stuff of {
                  Found loc _ -> found loc mod_name ;
                  _ -> no_obj mod_name
index 25d0508..ab11421 100644 (file)
@@ -27,7 +27,7 @@ import IfaceSyn               ( IfaceDecl(..), IfaceConDecl(..), IfaceClassOp(..),
 import IfaceEnv                ( newGlobalBinder, lookupIfaceExt, lookupIfaceTc, lookupAvail )
 import HscTypes                ( ModIface(..), TyThing, emptyModIface, EpsStats(..),
                          addEpsInStats, ExternalPackageState(..),
-                         PackageTypeEnv, emptyTypeEnv,  
+                         PackageTypeEnv, emptyTypeEnv,  HscEnv(..),
                          lookupIfaceByModule, emptyPackageIfaceTable,
                          IsBootInterface, mkIfaceFixCache, Gated,
                          implicitTyThings, addRulesToPool, addInstsToPool
@@ -576,7 +576,8 @@ findAndReadIface explicit doc_str mod_name hi_boot_file
          else do
 
        -- Look for the file
-       ; mb_found <- ioToIOEnv (findHiFile dflags explicit mod_name hi_boot_file)
+       ; hsc_env <- getTopEnv
+       ; mb_found <- ioToIOEnv (findHiFile hsc_env explicit mod_name hi_boot_file)
        ; case mb_found of {
              Failed err -> do
                { traceIf (ptext SLIT("...not found"))
@@ -598,19 +599,19 @@ findAndReadIface explicit doc_str mod_name hi_boot_file
                        -- Don't forget to fill in the package name...
        }}}
 
-findHiFile :: DynFlags -> Bool -> Module -> IsBootInterface
+findHiFile :: HscEnv -> Bool -> Module -> IsBootInterface
           -> IO (MaybeErr FindResult (FilePath, PackageIdH))
-findHiFile dflags explicit mod_name hi_boot_file
+findHiFile hsc_env explicit mod_name hi_boot_file
  = do { 
        -- In interactive or --make mode, we are *not allowed* to demand-load
        -- a home package .hi file.  So don't even look for them.
        -- This helps in the case where you are sitting in eg. ghc/lib/std
        -- and start up GHCi - it won't complain that all the modules it tries
        -- to load are found in the home location.
-       let { home_allowed = isOneShot (ghcMode dflags) } ;
+       let { home_allowed = isOneShot (ghcMode (hsc_dflags hsc_env)) } ;
        maybe_found <-  if home_allowed 
-                       then findModule        dflags mod_name explicit
-                       else findPackageModule dflags mod_name explicit;
+                       then findModule        hsc_env mod_name explicit
+                       else findPackageModule hsc_env mod_name explicit;
 
        case maybe_found of
          Found loc pkg -> return (Succeeded (path, pkg))
index fe8ad3c..410f5b1 100644 (file)
@@ -12,11 +12,11 @@ module DriverMkDepend (
 
 #include "HsVersions.h"
 
-import CompManager     ( cmDownsweep, cmTopSort, cyclicModuleErr )
+import qualified GHC
+import GHC             ( Session, ModSummary(..) )
 import DynFlags                ( DynFlags( verbosity, opt_dep ), getOpts )
 import Util            ( escapeSpaces, splitFilename )
-import HscTypes                ( IsBootInterface, ModSummary(..), msObjFilePath,
-                          msHsFilePath )
+import HscTypes                ( HscEnv, IsBootInterface, msObjFilePath, msHsFilePath )
 import Packages                ( PackageIdH(..) )
 import SysTools                ( newTempName )
 import qualified SysTools
@@ -47,18 +47,22 @@ import Panic                ( catchJust, ioErrors )
 --
 -----------------------------------------------------------------
 
-doMkDependHS :: DynFlags -> [FilePath] -> IO ()
-doMkDependHS dflags srcs
+doMkDependHS :: Session -> [FilePath] -> IO ()
+doMkDependHS session srcs
   = do {       -- Initialisation
-         files <- beginMkDependHS dflags
+         dflags <- GHC.getSessionDynFlags session
+       ; files <- beginMkDependHS dflags
 
                -- Do the downsweep to find all the modules
+       ; targets <- mapM GHC.guessTarget srcs
+       ; GHC.setTargets session targets
        ; excl_mods <- readIORef v_Dep_exclude_mods
-       ; mod_summaries <- cmDownsweep dflags srcs [] excl_mods
+       ; GHC.depanal session excl_mods
+       ; mod_summaries <- GHC.getModuleGraph session
 
                -- Sort into dependency order
                -- There should be no cycles
-       ; let sorted = cmTopSort False mod_summaries
+       ; let sorted = GHC.topSortModuleGraph False mod_summaries
 
                -- Print out the dependencies if wanted
        ; if verbosity dflags >= 2 then
@@ -67,7 +71,7 @@ doMkDependHS dflags srcs
                
                -- Prcess them one by one, dumping results into makefile
                -- and complaining about cycles
-       ; mapM (processDeps dflags (mkd_tmp_hdl files)) sorted
+       ; mapM (processDeps session (mkd_tmp_hdl files)) sorted
 
                -- Tidy up
        ; endMkDependHS dflags files }
@@ -145,7 +149,7 @@ beginMkDependHS dflags = do
 --
 -----------------------------------------------------------------
 
-processDeps :: DynFlags
+processDeps :: Session
            -> Handle           -- Write dependencies to here
            -> SCC ModSummary
            -> IO ()
@@ -164,19 +168,20 @@ processDeps :: DynFlags
 --
 -- For {-# SOURCE #-} imports the "hi" will be "hi-boot".
 
-processDeps dflags hdl (CyclicSCC nodes)
+processDeps session hdl (CyclicSCC nodes)
   =    -- There shouldn't be any cycles; report them   
-    throwDyn (ProgramError (showSDoc $ cyclicModuleErr nodes))
+    throwDyn (ProgramError (showSDoc $ GHC.cyclicModuleErr nodes))
 
-processDeps dflags hdl (AcyclicSCC node)
+processDeps session hdl (AcyclicSCC node)
   = do { extra_suffixes   <- readIORef v_Dep_suffixes
+       ; hsc_env <- GHC.sessionHscEnv session
        ; include_pkg_deps <- readIORef v_Dep_include_pkg_deps
        ; let src_file  = msHsFilePath node
              obj_file  = msObjFilePath node
              obj_files = insertSuffixes obj_file extra_suffixes
 
              do_imp is_boot imp_mod
-               = do { mb_hi <- findDependency dflags src_file imp_mod 
+               = do { mb_hi <- findDependency hsc_env src_file imp_mod 
                                               is_boot include_pkg_deps
                     ; case mb_hi of {
                           Nothing      -> return () ;
@@ -200,16 +205,16 @@ processDeps dflags hdl (AcyclicSCC node)
        }
 
 
-findDependency :: DynFlags
+findDependency :: HscEnv
                -> FilePath             -- Importing module: used only for error msg
                -> Module               -- Imported module
                -> IsBootInterface      -- Source import
                -> Bool                 -- Record dependency on package modules
                -> IO (Maybe FilePath)  -- Interface file file
-findDependency dflags src imp is_boot include_pkg_deps
+findDependency hsc_env src imp is_boot include_pkg_deps
   = do {       -- Find the module; this will be fast because
                -- we've done it once during downsweep
-         r <- findModule dflags imp True {-explicit-}
+         r <- findModule hsc_env imp True {-explicit-}
        ; case r of 
            Found loc pkg
                -- Not in this package: we don't need a dependency
@@ -220,9 +225,7 @@ findDependency dflags src imp is_boot include_pkg_deps
                | otherwise
                -> return (Just (addBootSuffix_maybe is_boot (ml_hi_file loc)))
 
-           _ -> throwDyn (ProgramError 
-                (src ++ ": " ++ "can't locate import `" ++ (moduleUserString imp) ++ "'"
-                 ++ if is_boot then " (SOURCE import)" else ""))
+           _ -> panic "findDependency"
        }
 
 -----------------------------
index 4c60264..f9fdafa 100644 (file)
@@ -2,13 +2,14 @@
 --
 -- GHC Driver
 --
--- (c) The University of Glasgow 2002
+-- (c) The University of Glasgow 2005
 --
 -----------------------------------------------------------------------------
 
 module DriverPipeline (
-       -- Run a series of compilation steps in a pipeline
-   runPipeline,
+       -- Run a series of compilation steps in a pipeline, for a
+       -- collection of source files.
+   oneShot,
 
        -- Interfaces for the batch-mode driver
    staticLink,
@@ -70,13 +71,7 @@ import Maybe
 preprocess :: DynFlags -> FilePath -> IO (DynFlags, FilePath)
 preprocess dflags filename =
   ASSERT2(isHaskellSrcFilename filename, text filename) 
-  runPipeline anyHsc dflags
-       False{-temporary output file-}
-       Nothing{-no specific output file-}
-       filename
-       Nothing{-no ModLocation-}
-
-
+  runPipeline anyHsc dflags filename Temporary Nothing{-no ModLocation-}
 
 -- ---------------------------------------------------------------------------
 -- Compile
@@ -88,12 +83,6 @@ preprocess dflags filename =
 -- reading the OPTIONS pragma from the source file, and passing the
 -- output of hsc through the C compiler.
 
--- The driver sits between 'compile' and 'hscMain', translating calls
--- to the former into calls to the latter, and results from the latter
--- into results from the former.  It does things like preprocessing
--- the .hs file if necessary, and compiling up the .stub_c files to
--- generate Linkables.
-
 -- NB.  No old interface can also mean that the source has changed.
 
 compile :: HscEnv
@@ -149,9 +138,8 @@ compile hsc_env mod_summary
    -- ... and what the next phase should be
    let next_phase = hscNextPhase dflags src_flavour hsc_lang
    -- ... and what file to generate the output into
-   let get_output_fn = genOutputFilenameFunc dflags next_phase 
-                               False Nothing basename
-   output_fn     <- get_output_fn next_phase (Just location)
+   output_fn <- getOutputFilename dflags next_phase 
+                       Temporary basename next_phase (Just location)
 
    let dflags' = dflags { hscTarget = hsc_lang,
                                hscOutName = output_fn,
@@ -209,8 +197,8 @@ compile hsc_env mod_summary
                _other -> do
                   let object_filename = ml_obj_file location
 
-                  runPipeline StopLn dflags
-                              True Nothing output_fn (Just location)
+                  runPipeline StopLn dflags output_fn Persistent
+                              (Just location)
                        -- the object filename comes from the ModLocation
 
                   o_time <- getModificationTime object_filename
@@ -230,10 +218,7 @@ compileStub dflags stub_c_exists
        -- compile the _stub.c file w/ gcc
        let stub_c = hscStubCOutName dflags
        (_, stub_o) <- runPipeline StopLn dflags
-                           True{-persistent output-} 
-                           Nothing{-no specific output file-}
-                           stub_c
-                           Nothing{-no ModLocation-}
+                           stub_c Persistent Nothing{-no ModLocation-}
        return (Just stub_o)
 
 
@@ -304,24 +289,93 @@ link BatchCompile dflags batch_attempt_linking hpt
    where
       verb = verbosity dflags
       
+
+-- -----------------------------------------------------------------------------
+-- Compile files in one-shot mode.
+
+oneShot :: DynFlags -> Phase -> [String] -> IO ()
+oneShot dflags stop_phase srcs = do
+  o_files <- mapM (compileFile dflags stop_phase) srcs
+  doLink dflags stop_phase o_files
+
+compileFile :: DynFlags -> Phase -> FilePath -> IO FilePath
+compileFile dflags stop_phase src = do
+   exists <- doesFileExist src
+   when (not exists) $ 
+       throwDyn (CmdLineError ("does not exist: " ++ src))
+   
+   let
+       split     = dopt Opt_SplitObjs dflags
+       mb_o_file = outputFile dflags
+       ghc_link  = ghcLink dflags      -- Set by -c or -no-link
+
+       -- When linking, the -o argument refers to the linker's output. 
+       -- otherwise, we use it as the name for the pipeline's output.
+        output
+        | StopLn <- stop_phase, not (isNoLink ghc_link) = Persistent
+               -- -o foo applies to linker
+        | Just o_file <- mb_o_file = SpecificFile o_file
+               -- -o foo applies to the file we are compiling now
+        | otherwise = Persistent
+
+        stop_phase' = case stop_phase of 
+                       As | split -> SplitAs
+                       other      -> stop_phase
+
+   (_, out_file) <- runPipeline stop_phase' dflags
+                         src output Nothing{-no ModLocation-}
+   return out_file
+
+
+doLink :: DynFlags -> Phase -> [FilePath] -> IO ()
+doLink dflags stop_phase o_files
+  | not (isStopLn stop_phase)
+  = return ()          -- We stopped before the linking phase
+
+  | otherwise
+  = case ghcLink dflags of
+       NoLink     -> return ()
+       StaticLink -> staticLink dflags o_files link_pkgs
+       MkDLL      -> doMkDLL dflags o_files link_pkgs
+  where
+   -- Always link in the haskell98 package for static linking.  Other
+   -- packages have to be specified via the -package flag.
+    link_pkgs
+         | ExtPackage h98_id <- haskell98PackageId (pkgState dflags) = [h98_id]
+         | otherwise = []
+
+
 -- ---------------------------------------------------------------------------
 -- Run a compilation pipeline, consisting of multiple phases.
 
+-- This is the interface to the compilation pipeline, which runs
+-- a series of compilation steps on a single source file, specifying
+-- at which stage to stop.
+
 -- The DynFlags can be modified by phases in the pipeline (eg. by
--- OPTIONS pragmas), and the changes affect later phases in the
--- pipeline, but we throw away the resulting DynFlags at the end.
+-- GHC_OPTIONS pragmas), and the changes affect later phases in the
+-- pipeline.
+
+data PipelineOutput 
+  = Temporary
+       -- output should be to a temporary file: we're going to
+       -- run more compilation steps on this output later
+  | Persistent
+       -- we want a persistent file, i.e. a file in the current directory
+       -- derived from the input filename, but with the appropriate extension.
+       -- eg. in "ghc -c Foo.hs" the output goes into ./Foo.o.
+  | SpecificFile FilePath
+       -- the output must go into the specified file.
 
 runPipeline
   :: Phase             -- When to stop
   -> DynFlags          -- Dynamic flags
-  -> Bool              -- Final output is persistent?
-  -> Maybe FilePath    -- Where to put the output, optionally
   -> FilePath          -- Input filename
-  -> Maybe ModLocation  -- A ModLocation for this module, if we have one
+  -> PipelineOutput    -- Output filename
+  -> Maybe ModLocation  -- A ModLocation, if this is a Haskell module
   -> IO (DynFlags, FilePath)   -- (final flags, output filename)
 
-runPipeline stop_phase dflags keep_output 
-  maybe_output_filename input_fn maybe_loc
+runPipeline stop_phase dflags input_fn output maybe_loc
   = do
   let (basename, suffix) = splitFilename input_fn
       start_phase = startPhase suffix
@@ -338,27 +392,29 @@ runPipeline stop_phase dflags keep_output
                    ("cannot compile this file to desired target: "
                       ++ input_fn))
 
-  -- generate a function which will be used to calculate output file names
-  -- as we go along.
-  let get_output_fn = genOutputFilenameFunc dflags stop_phase keep_output 
-                                        maybe_output_filename basename
+  -- this is a function which will be used to calculate output file names
+  -- as we go along (we partially apply it to some of its inputs here)
+  let get_output_fn = getOutputFilename dflags stop_phase output basename
 
   -- Execute the pipeline...
-  (dflags', output_fn, maybe_loc) <- pipeLoop dflags start_phase stop_phase input_fn 
-                                             basename suffix get_output_fn maybe_loc
+  (dflags', output_fn, maybe_loc) <- 
+       pipeLoop dflags start_phase stop_phase input_fn 
+                basename suffix get_output_fn maybe_loc
 
   -- Sometimes, a compilation phase doesn't actually generate any output
   -- (eg. the CPP phase when -fcpp is not turned on).  If we end on this
   -- stage, but we wanted to keep the output, then we have to explicitly
   -- copy the file.
-  if keep_output 
-       then do final_fn <- get_output_fn stop_phase maybe_loc
-               when (final_fn /= output_fn) $
-                 copy dflags ("Copying `" ++ output_fn ++ "' to `" ++ final_fn
+  case output of
+    Temporary -> 
+       return (dflags', output_fn)
+    _other ->
+       do final_fn <- get_output_fn stop_phase maybe_loc
+          when (final_fn /= output_fn) $
+                 copy dflags ("Copying `" ++ output_fn ++ "' to `" ++ final_fn
                        ++ "'") output_fn final_fn
-               return (dflags', final_fn)
-       else
-               return (dflags', output_fn)
+          return (dflags', final_fn)
+               
 
 
 pipeLoop :: DynFlags -> Phase -> Phase 
@@ -389,10 +445,10 @@ pipeLoop dflags phase stop_phase
        ; pipeLoop dflags' next_phase stop_phase output_fn
                   orig_basename orig_suff orig_get_output_fn maybe_loc }
 
-genOutputFilenameFunc :: DynFlags -> Phase -> Bool -> Maybe FilePath -> String
-  -> (Phase{-next phase-} -> Maybe ModLocation -> IO FilePath)
-genOutputFilenameFunc dflags stop_phase keep_final_output 
-                       maybe_output_filename basename
+getOutputFilename
+  :: DynFlags -> Phase -> PipelineOutput -> String
+  -> Phase{-next phase-} -> Maybe ModLocation -> IO FilePath
+getOutputFilename dflags stop_phase output basename
  = func
  where
        hcsuf      = hcSuf dflags
@@ -407,11 +463,10 @@ genOutputFilenameFunc dflags stop_phase keep_final_output
         myPhaseInputExt other  = phaseInputExt other
 
        func next_phase maybe_location
-               | is_last_phase, Just f <- maybe_output_filename = return f
-               | is_last_phase && keep_final_output = persistent_fn
-               | keep_this_output                   = persistent_fn
-               | otherwise                          = newTempName dflags suffix
-
+          | is_last_phase, Persistent <- output     = persistent_fn
+          | is_last_phase, SpecificFile f <- output = return f
+          | keep_this_output                        = persistent_fn
+          | otherwise                               = newTempName dflags suffix
           where
                is_last_phase = next_phase `eqPhase` stop_phase
 
@@ -582,9 +637,6 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
                      = location3 { ml_obj_file = ofile }
                      | otherwise = location3
 
-  -- Tell the finder cache about this module
-       addHomeModuleToFinder mod_name location4
-
   -- Make the ModSummary to hand to hscMain
        src_timestamp <- getModificationTime (basename ++ '.':suff)
        let
@@ -638,6 +690,9 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
 
        hsc_env <- newHscEnv dflags'
 
+  -- Tell the finder cache about this module
+       addHomeModuleToFinder hsc_env mod_name location4
+
   -- run the compiler!
        result <- hscMain hsc_env printErrorsAndWarnings
                          mod_summary source_unchanged 
index 97904a1..c8896f8 100644 (file)
@@ -11,7 +11,7 @@ module Finder (
     findPackageModule,         -- :: ModuleName -> Bool -> IO FindResult
     mkHomeModLocation,         -- :: ModuleName -> FilePath -> IO ModLocation
     mkHomeModLocation2,                -- :: ModuleName -> FilePath -> String -> IO ModLocation
-    addHomeModuleToFinder,     -- :: Module -> ModLocation -> IO ()
+    addHomeModuleToFinder,     -- :: HscEnv -> Module -> ModLocation -> IO ()
 
     findLinkable,      -- :: ModuleName -> ModLocation -> IO (Maybe Linkable)
 
@@ -22,7 +22,7 @@ module Finder (
 
 import Module
 import UniqFM          ( filterUFM )
-import HscTypes                ( Linkable(..), Unlinked(..) )
+import HscTypes
 import Packages
 import FastString
 import Util
@@ -55,24 +55,20 @@ type BaseName = String      -- Basename of file
 -- -----------------------------------------------------------------------------
 -- The finder's cache
 
-GLOBAL_VAR(finder_cache, emptyModuleEnv, ModuleEnv FinderCacheEntry)
-
-type FinderCacheEntry = (ModLocation, Maybe (PackageConfig,Bool))
-
 -- remove all the home modules from the cache; package modules are
 -- assumed to not move around during a session.
-flushFinderCache :: IO ()
-flushFinderCache = do
+flushFinderCache :: IORef FinderCache -> IO ()
+flushFinderCache finder_cache = do
   fm <- readIORef finder_cache
-  writeIORef finder_cache (filterUFM (\(loc,m) -> isNothing m) fm)
+  writeIORef finder_cache $! filterUFM (\(loc,m) -> isNothing m) fm
 
-addToFinderCache :: Module -> FinderCacheEntry -> IO ()
-addToFinderCache mod_name entry = do
+addToFinderCache :: IORef FinderCache -> Module -> FinderCacheEntry -> IO ()
+addToFinderCache finder_cache mod_name entry = do
   fm <- readIORef finder_cache
-  writeIORef finder_cache (extendModuleEnv fm mod_name entry)
+  writeIORef finder_cache $! extendModuleEnv fm mod_name entry
 
-lookupFinderCache :: Module -> IO (Maybe FinderCacheEntry)
-lookupFinderCache mod_name = do
+lookupFinderCache :: IORef FinderCache -> Module -> IO (Maybe FinderCacheEntry)
+lookupFinderCache finder_cache mod_name = do
   fm <- readIORef finder_cache
   return $! lookupModuleEnv fm mod_name
 
@@ -108,19 +104,20 @@ type LocalFindResult = MaybeErr [FilePath] FinderCacheEntry
 
 cached :: Bool
        -> (DynFlags -> Module -> IO LocalFindResult)
-       -> DynFlags -> Module -> Bool -> IO FindResult
-cached home_allowed wrapped_fn dflags name explicit 
+       -> HscEnv -> Module -> Bool -> IO FindResult
+cached home_allowed wrapped_fn hsc_env name explicit 
   = do {       -- First try the cache
-         mb_entry <- lookupFinderCache name
+         let cache = hsc_FC hsc_env
+       ; mb_entry <- lookupFinderCache cache name
        ; case mb_entry of {
            Just old_entry -> return (found old_entry) ;
            Nothing    -> do
 
        {       -- Now try the wrapped function
-         mb_entry <- wrapped_fn dflags name
+         mb_entry <- wrapped_fn (hsc_dflags hsc_env) name
        ; case mb_entry of
            Failed paths        -> return (NotFound paths)
-           Succeeded new_entry -> do { addToFinderCache name new_entry
+           Succeeded new_entry -> do { addToFinderCache cache name new_entry
                                      ; return (found new_entry) }
        }}} 
   where
@@ -137,18 +134,19 @@ cached home_allowed wrapped_fn dflags name explicit
        where
          pkg_name = packageConfigId pkg
 
-addHomeModuleToFinder :: Module -> ModLocation -> IO ()
-addHomeModuleToFinder mod loc = addToFinderCache mod (loc, Nothing)
+addHomeModuleToFinder :: HscEnv -> Module -> ModLocation -> IO ()
+addHomeModuleToFinder hsc_env mod loc 
+  = addToFinderCache (hsc_FC hsc_env) mod (loc, Nothing)
 
 
 -- -----------------------------------------------------------------------------
 --     The two external entry points
 
 
-findModule :: DynFlags -> Module -> Bool -> IO FindResult
+findModule :: HscEnv -> Module -> Bool -> IO FindResult
 findModule = cached True findModule' 
   
-findPackageModule :: DynFlags -> Module -> Bool -> IO FindResult
+findPackageModule :: HscEnv -> Module -> Bool -> IO FindResult
 findPackageModule = cached False findPackageModule'
 
 -- -----------------------------------------------------------------------------
index 452d26e..8cf3c24 100644 (file)
+-- -----------------------------------------------------------------------------
 --
--- (c) The University of Glasgow, 2004
+-- (c) The University of Glasgow, 2005
 --
 -- The GHC API
 --
+-- -----------------------------------------------------------------------------
 
 module GHC (
        -- * Initialisation
-       GhcSession,
-       GhcMode(..),
+       Session,
        defaultErrorHandler,
        defaultCleanupHandler,
        init,
        newSession,
 
        -- * Flags and settings
-       DynFlags(..),
-       DynFlag(..),
+       DynFlags(..), DynFlag(..), GhcMode(..), HscTarget(..), dopt,
+       parseDynamicFlags,
        getSessionDynFlags,
        setSessionDynFlags,
        setMsgHandler,
+
+       -- * Targets
+       Target(..),
+       setTargets,
+       getTargets,
+       addTarget,
+       guessTarget,
+       
+       -- * Loading/compiling the program
+       depanal,
+       load, SuccessFlag(..),          -- also does depanal
+       workingDirectoryChanged,
+
+       -- * Inspecting the module structure of the program
+       ModuleGraph, ModSummary(..),
+       getModuleGraph,
+       topSortModuleGraph,
+
+       -- * Interactive evaluation
+       getBindings, getPrintUnqual,
+#ifdef GHCI
+       setContext, getContext, 
+       moduleIsInterpreted,
+       getInfo, GetInfoResult,
+       exprType,
+       typeKind,
+       lookupName,
+       RunResult(..),
+       runStmt,
+       browseModule,
+       showModule,
+       compileExpr, HValue,
+#endif
+
+       -- * Abstract syntax elements
+       Module, mkModule, pprModule,
+       Type, dropForAlls,
+       Kind,
+       Name, Id, TyCon, Class, DataCon,
+       TyThing(..), 
+       idType,
+
+       -- used by DriverMkDepend:
+       sessionHscEnv,
+       cyclicModuleErr,
   ) where
 
-import HscTypes                ( GhcMode(..) )
+{-
+ ToDo:
+
+  * return error messages rather than printing them.
+  * inline bits of HscMain here to simplify layering: hscGetInfo,
+    hscTcExpr, hscStmt.
+  * implement second argument to load.
+  * we need to expose DynFlags, so should parseDynamicFlags really be
+    part of this interface?
+  * what StaticFlags should we expose, if any?
+-}
+
+#include "HsVersions.h"
+
+#ifdef GHCI
+import qualified Linker
+import Linker          ( HValue, extendLinkEnv )
+import NameEnv         ( lookupNameEnv )
+import TcRnDriver      ( mkExportEnv, getModuleContents )
+import RdrName         ( GlobalRdrEnv, plusGlobalRdrEnv )
+import HscMain         ( hscGetInfo, GetInfoResult, 
+                         hscStmt, hscTcExpr, hscKcType )
+import Type            ( tidyType )
+import VarEnv          ( emptyTidyEnv )
+import GHC.Exts                ( unsafeCoerce# )
+import IfaceSyn                ( IfaceDecl )
+#endif
+
+import Type            ( Kind, Type, dropForAlls )
+import Id              ( Id, idType )
+import TyCon           ( TyCon )
+import Class           ( Class )
+import DataCon         ( DataCon )
+import Name            ( Name )
+import NameEnv         ( nameEnvElts )
+import DriverPipeline  ( preprocess, compile, CompResult(..), link )
+import DriverPhases    ( isHaskellSrcFilename )
+import GetImports      ( getImports )
+import Packages                ( isHomePackage )
+import Finder
+import HscMain         ( newHscEnv )
+import HscTypes
+import DynFlags
+import StaticFlags
+import SysTools                ( initSysTools, cleanTempFiles )
+import Module
+import FiniteMap
+import Panic
+import Digraph         ( SCC(..), stronglyConnComp, flattenSCC, flattenSCCs )
+import ErrUtils                ( showPass )
 import qualified ErrUtils
+import Util
+import StringBuffer    ( hGetStringBuffer )
+import Outputable
+import SysTools                ( cleanTempFilesExcept )
+import BasicTypes      ( SuccessFlag(..), succeeded )
+import Maybes          ( orElse, expectJust, mapCatMaybes )
+
+import Directory        ( getModificationTime, doesFileExist )
+import Maybe           ( isJust, fromJust )
+import List            ( partition, nub )
+import Monad           ( unless, when, foldM )
+import System          ( exitWith, ExitCode(..) )
+import EXCEPTION as Exception hiding (handle)
+import DATA_IOREF
+import IO
+import Prelude hiding (init)
 
 -- -----------------------------------------------------------------------------
--- Initialisation
-
--- | abstract type representing a session with GHC.  A session
--- includes the currently loaded modules, and any bindings made using
--- interactive evaluation.
-data Session = 
-  Session {
-       sess_hscenv :: IORef HscEnv  -- will include the InteractiveContext
-  }
+-- Exception handlers
 
 -- | Install some default exception handlers and run the inner computation.
 -- Unless you want to handle exceptions yourself, you should wrap this around
@@ -68,14 +171,11 @@ defaultErrorHandler inner =
 -- deposited by a GHC run.  This is seperate from
 -- 'defaultErrorHandler', because you might want to override the error
 -- handling, but still get the ordinary cleanup behaviour.
-defaultCleanupHandler :: IO a -> IO a
-defaultCleanupHandler inner = 
+defaultCleanupHandler :: DynFlags -> IO a -> IO a
+defaultCleanupHandler dflags inner = 
    -- make sure we clean up after ourselves
-   later (do  forget_it <- readIORef v_Keep_tmp_files
-             unless forget_it $ do
-             verb <- dynFlag verbosity
-             cleanTempFiles verb
-     ) $
+   later (unless (dopt Opt_KeepTmpFiles dflags) $ 
+           cleanTempFiles dflags) 
        -- exceptions will be blocked while we clean the temporary files,
        -- so there shouldn't be any difficulty if we receive further
        -- signals.
@@ -83,82 +183,26 @@ defaultCleanupHandler inner =
 
 
 -- | Initialises GHC.  This must be done /once/ only.  Takes the
--- command-line arguments.  All command-line arguments beginning with
--- '-' are interpreted as flags.  All others are returned.
---
+-- command-line arguments.  All command-line arguments which aren't
+-- understood by GHC will be returned.
+
 init :: [String] -> IO [String]
 init args = do
    -- catch ^C
    installSignalHandlers
 
-   argv <- getArgs
-   let (minusB_args, argv') = partition (prefixMatch "-B") argv
-   top_dir <- initSysTools minusB_args
-
-       -- Process all the other arguments, and get the source files
-   non_static <- processArgs static_flags argv' []
-   mode <- readIORef v_CmdLineMode
-
-       -- Read all package.conf files (system, user, -package-conf)
-   readPackageConfigs
-
-       -- load explicit packages (those named with -package on the cmdline)
-   loadExplicitPackages
-
-       -- -O and --interactive are not a good combination
-       -- ditto with any kind of way selection
-   orig_ways <- readIORef v_Ways
-   when (notNull orig_ways && isInteractive mode) $
-      do throwDyn (UsageError 
-                   "--interactive can't be used with -prof, -ticky, -unreg or -smp.")
-
-       -- Find the build tag, and re-process the build-specific options.
-       -- Also add in flags for unregisterised compilation, if 
-       -- GhcUnregisterised=YES.
-   way_opts <- findBuildTag
-   let unreg_opts | cGhcUnregisterised == "YES" = unregFlags
-                 | otherwise = []
-   pkg_extra_opts <- getPackageExtraGhcOpts
-   extra_non_static <- processArgs static_flags 
-                          (unreg_opts ++ way_opts ++ pkg_extra_opts) []
-
-       -- Give the static flags to hsc
-   static_opts <- buildStaticHscOpts
-   writeIORef v_Static_hsc_opts static_opts
-
-   -- build the default DynFlags (these may be adjusted on a per
-   -- module basis by OPTIONS pragmas and settings in the interpreter).
-
-   stg_todo  <- buildStgToDo
-
-   -- set the "global" HscLang.  The HscLang can be further adjusted on a module
-   -- by module basis, using only the -fvia-C and -fasm flags.  If the global
-   -- HscLang is not HscC or HscAsm, -fvia-C and -fasm have no effect.
-   dyn_flags <- getDynFlags
-   let lang = case mode of 
-                DoInteractive  -> HscInterpreted
-                DoEval _       -> HscInterpreted
-                _other         -> hscLang dyn_flags
-
-   setDynFlags (dyn_flags{ stgToDo  = stg_todo,
-                          hscLang  = lang,
-                          -- leave out hscOutName for now
-                          hscOutName = panic "Main.main:hscOutName not set",
-                          verbosity = case mode of
-                                        DoEval _ -> 0
-                                        _other   -> 1
-                       })
-
-       -- The rest of the arguments are "dynamic"
-       -- Leftover ones are presumably files
-   fileish_args <- processArgs dynamic_flags (extra_non_static ++ non_static) []
-
-       -- save the "initial DynFlags" away
-   saveDynFlags
-
-       -- and return the leftover args
-   return fileish_args
+   -- Grab the -B option if there is one
+   let (minusB_args, argv1) = partition (prefixMatch "-B") args
+   dflags0 <- initSysTools minusB_args defaultDynFlags
+   writeIORef v_initDynFlags dflags0
 
+   -- Parse the static flags
+   argv2 <- parseStaticFlags argv1
+   return argv2
+
+GLOBAL_VAR(v_initDynFlags, error "initDynFlags", DynFlags)
+       -- stores the DynFlags between the call to init and subsequent
+       -- calls to newSession.
 
 -- | Starts a new session.  A session consists of a set of loaded
 -- modules, a set of options (DynFlags), and an interactive context.
@@ -166,26 +210,33 @@ init args = do
 -- code".
 newSession :: GhcMode -> IO Session
 newSession mode = do
-  dflags <- getDynFlags
-  env <- newHscEnv mode dflags
+  dflags0 <- readIORef v_initDynFlags
+  dflags <- initDynFlags dflags0
+  env <- newHscEnv dflags{ ghcMode=mode }
   ref <- newIORef env
-  panic "do we need to set v_CmdLineMode? finder uses it."
-  return (Session {sess_hscenv = ref})
+  return (Session ref)
+
+-- tmp: this breaks the abstraction, but required because DriverMkDepend
+-- needs to call the Finder.  ToDo: untangle this.
+sessionHscEnv :: Session -> IO HscEnv
+sessionHscEnv (Session ref) = readIORef ref
+
+withSession :: Session -> (HscEnv -> IO a) -> IO a
+withSession (Session ref) f = do h <- readIORef ref; f h
+
+modifySession :: Session -> (HscEnv -> HscEnv) -> IO ()
+modifySession (Session ref) f = do h <- readIORef ref; writeIORef ref $! f h
 
 -- -----------------------------------------------------------------------------
 -- Flags & settings
 
 -- | Grabs the DynFlags from the Session
 getSessionDynFlags :: Session -> IO DynFlags
-getSessionDynFlags sess = do
-  env <- readIORef (sess_hscenv sess)
-  return (hsc_dflags env)
+getSessionDynFlags s = withSession s (return . hsc_dflags)
 
 -- | Updates the DynFlags in a Session
-updateSessionDynFlags :: Session -> DynFlags -> IO ()
-updateSessionDynFlags sess dflags = do
-  env <- readIORef (sess_hscenv sess)
-  writeIORef (sess_hscenv sess) env{hsc_dflags=dflags}
+setSessionDynFlags :: Session -> DynFlags -> IO ()
+setSessionDynFlags s dflags = modifySession s (\h -> h{ hsc_dflags = dflags })
 
 -- | Messages during compilation (eg. warnings and progress messages)
 -- are reported using this callback.  By default, these messages are
@@ -194,18 +245,7 @@ setMsgHandler :: (String -> IO ()) -> IO ()
 setMsgHandler = ErrUtils.setMsgHandler
 
 -- -----------------------------------------------------------------------------
--- Loading a program
-
--- | A compilation target.
-data Target = Target TargetId (Maybe StringBuffer)
-       -- A target may be supplied with the actual text of the
-       -- module.  If so, use this instead of the file contents (this
-       -- is for use in an IDE where the file hasn't been saved by
-       -- the user yet).
-
-data TargetId
-  = TargetModule String                -- A module name: search for the file
-  | TargetFile   FilePath      -- A filename: parse it to find the module name.
+-- Targets
 
 -- ToDo: think about relative vs. absolute file paths. And what
 -- happens when the current directory changes.
@@ -213,46 +253,1028 @@ data TargetId
 -- | Sets the targets for this session.  Each target may be a module name
 -- or a filename.  The targets correspond to the set of root modules for
 -- the program/library.  Unloading the current program is achieved by
--- setting the current set of targets to be empty.
+-- setting the current set of targets to be empty, followed by load.
 setTargets :: Session -> [Target] -> IO ()
+setTargets s targets = modifySession s (\h -> h{ hsc_targets = targets })
 
 -- | returns the current set of targets
---getTargets :: Session -> IO [Target]
+getTargets :: Session -> IO [Target]
+getTargets s = withSession s (return . hsc_targets)
 
 -- Add another target, or update an existing target with new content.
-addTarget :: Session -> Target -> IO Module
+addTarget :: Session -> Target -> IO ()
+addTarget s target
+  = modifySession s (\h -> h{ hsc_targets = target : hsc_targets h })
 
 -- Remove a target
-removeTarget :: Session -> Module -> IO ()
+-- removeTarget :: Session -> Module -> IO ()
 
--- Try to load the program.  If a Module is supplied, then just
--- attempt to load up to this target.  If no Module is supplied,
--- then try to load all targets.
-load :: Session -> Maybe Module -> IO LoadResult
+-- Attempts to guess what Target a string refers to.  This function implements
+-- the --make/GHCi command-line syntax for filenames: 
+--
+--     - if the string looks like a Haskell source filename, then interpret
+--       it as such
+--     - if adding a .hs or .lhs suffix yields the name of an existing file,
+--       then use that
+--     - otherwise interpret the string as a module name
+--
+guessTarget :: String -> IO Target
+guessTarget file
+   | isHaskellSrcFilename file
+   = return (Target (TargetFile file) Nothing)
+   | otherwise
+   = do exists <- doesFileExist hs_file
+       if exists then return (Target (TargetFile hs_file) Nothing) else do
+       exists <- doesFileExist lhs_file
+       if exists then return (Target (TargetFile lhs_file) Nothing) else do
+       return (Target (TargetModule (mkModule file)) Nothing)
+     where 
+        hs_file = file ++ ".hs"
+        lhs_file = file ++ ".lhs"
+
+-- -----------------------------------------------------------------------------
+-- Loading the program
 
 -- | The result of load.
 data LoadResult
   = LoadOk     Errors  -- ^ all specified targets were loaded successfully.
   | LoadFailed  Errors -- ^ not all modules were loaded.
 
-type Errors = [ErrMsg]
+type Errors = [String]
 
+{-
 data ErrMsg = ErrMsg { 
        errMsgSeverity  :: Severity,  -- warning, error, etc.
        errMsgSpans     :: [SrcSpan],
        errMsgShortDoc  :: Doc,
        errMsgExtraInfo :: Doc
        }
+-}
+
+-- Perform a dependency analysis starting from the current targets
+-- and update the session with the new module graph.
+depanal :: Session -> [Module] -> IO ()
+depanal (Session ref) excluded_mods = do
+  hsc_env <- readIORef ref
+  let
+        dflags  = hsc_dflags hsc_env
+        gmode   = ghcMode (hsc_dflags hsc_env)
+        targets = hsc_targets hsc_env
+        old_graph = hsc_mod_graph hsc_env
+       
+  showPass dflags "Chasing dependencies"
+  when (verbosity dflags >= 1 && gmode == BatchCompile) $
+              hPutStrLn stderr (showSDoc (hcat [
+                    text "Chasing modules from: ",
+                       hcat (punctuate comma (map pprTarget targets))]))
+
+  graph <- downsweep hsc_env old_graph excluded_mods
+  writeIORef ref hsc_env{ hsc_mod_graph=graph }
+
+
+-- | Try to load the program.  If a Module is supplied, then just
+-- attempt to load up to this target.  If no Module is supplied,
+-- then try to load all targets.
+load :: Session -> Maybe Module -> IO SuccessFlag
+load s@(Session ref) maybe_mod{-ToDo-} 
+   = do 
+       -- dependency analysis first
+       depanal s []
+
+       hsc_env <- readIORef ref
+
+        let hpt1      = hsc_HPT hsc_env
+        let dflags    = hsc_dflags hsc_env
+       let mod_graph = hsc_mod_graph hsc_env
+
+        let ghci_mode = ghcMode (hsc_dflags hsc_env) -- this never changes
+        let verb      = verbosity dflags
+
+       -- The "bad" boot modules are the ones for which we have
+       -- 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 s | s <- mod_graph, not (isBootSummary s)]
+           bad_boot_mods = [s        | s <- mod_graph, isBootSummary s,
+                                       not (ms_mod s `elem` all_home_mods)]
+       ASSERT( null bad_boot_mods ) return ()
+
+        -- Topologically sort the module graph
+        -- mg2 should be cycle free; but it includes hi-boot ModSummary nodes
+        let mg2 :: [SCC ModSummary]
+           mg2 = topSortModuleGraph False mod_graph
+
+        -- 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
+        -- not in strict downwards closure, during calls to compile.
+        let mg2_with_srcimps :: [SCC ModSummary]
+           mg2_with_srcimps = topSortModuleGraph True mod_graph
+
+       -- Sort out which linkables we wish to keep in the unlinked image.
+       -- See getValidLinkables below for details.
+       (valid_old_linkables, new_linkables)
+           <- getValidLinkables ghci_mode (hptLinkables hpt1)
+                 all_home_mods mg2_with_srcimps
+
+       -- putStrLn (showSDoc (vcat [ppr valid_old_linkables, ppr new_linkables]))
+
+       -- The new_linkables are .o files we found on the disk, presumably
+       -- as a result of a GHC run "on the side".  So we'd better forget
+       -- everything we know abouut those modules!
+       let old_hpt = delModuleEnvList hpt1 (map linkableModule new_linkables)
+
+       -- When (verb >= 2) $
+        --    putStrLn (showSDoc (text "Valid linkables:" 
+        --                      <+> ppr valid_linkables))
+
+        -- Figure out a stable set of modules which can be retained
+        -- the top level envs, to avoid upsweeping them.  Goes to a
+        -- bit of trouble to avoid upsweeping module cycles.
+        --
+        -- Construct a set S of stable modules like this:
+        -- Travel upwards, over the sccified graph.  For each scc
+        -- of modules ms, add ms to S only if:
+        -- 1.  All home imports of ms are either in ms or S
+        -- 2.  A valid old linkable exists for each module in ms
+
+       -- mg2_with_srcimps has no hi-boot nodes, 
+       -- and hence neither does stable_mods 
+        stable_summaries <- preUpsweep valid_old_linkables
+                                      all_home_mods [] mg2_with_srcimps
+        let stable_mods      = map ms_mod stable_summaries
+           stable_linkables = filter (\m -> linkableModule m `elem` stable_mods) 
+                                     valid_old_linkables
+
+           stable_hpt = filterModuleEnv is_stable_hm hpt1
+           is_stable_hm hm_info = mi_module (hm_iface hm_info) `elem` stable_mods
+
+            upsweep_these
+               = filter (\scc -> any (`notElem` stable_mods) 
+                                     (map ms_mod (flattenSCC scc)))
+                        mg2
+
+        when (verb >= 2) $
+           hPutStrLn stderr (showSDoc (text "Stable modules:" 
+                               <+> sep (map (text.moduleUserString) stable_mods)))
+
+       -- Unload any modules which are going to be re-linked this time around.
+       unload hsc_env stable_linkables
+
+       -- We can now glom together our linkable sets
+       let valid_linkables = valid_old_linkables ++ new_linkables
+
+        -- We could at this point detect cycles which aren't broken by
+        -- a source-import, and complain immediately, but it seems better
+        -- to let upsweep_mods do this, so at least some useful work gets
+        -- done before the upsweep is abandoned.
+        --hPutStrLn stderr "after tsort:\n"
+        --hPutStrLn stderr (showSDoc (vcat (map ppr mg2)))
+
+        -- Now do the upsweep, calling compile for each module in
+        -- turn.  Final result is version 3 of everything.
+
+       -- clean up between compilations
+       let cleanup = cleanTempFilesExcept dflags
+                         (ppFilesFromSummaries (flattenSCCs mg2))
+
+        (upsweep_ok, hsc_env3, modsUpswept)
+           <- upsweep_mods (hsc_env { hsc_HPT = stable_hpt })
+                          (old_hpt, valid_linkables)
+                           cleanup upsweep_these
+
+        -- At this point, modsUpswept and newLis should have the same
+        -- length, so there is one new (or old) linkable for each 
+        -- mod which was processed (passed to compile).
+
+       -- Make modsDone be the summaries for each home module now
+       -- available; this should equal the domain of hpt3.
+       -- (NOT STRICTLY TRUE if an interactive session was started
+       --  with some object on disk ???)
+        -- Get in in a roughly top .. bottom order (hence reverse).
+
+        let modsDone = reverse modsUpswept ++ stable_summaries
+
+        -- Try and do linking in some form, depending on whether the
+        -- upsweep was completely or only partially successful.
+
+        if succeeded upsweep_ok
+
+         then 
+           -- Easy; just relink it all.
+           do when (verb >= 2) $ 
+                hPutStrLn stderr "Upsweep completely successful."
+
+             -- Clean up after ourselves
+             cleanTempFilesExcept dflags (ppFilesFromSummaries modsDone)
+
+             -- Issue a warning for the confusing case where the user
+             -- said '-o foo' but we're not going to do any linking.
+             -- We attempt linking if either (a) one of the modules is
+             -- called Main, or (b) the user said -no-hs-main, indicating
+             -- that main() is going to come from somewhere else.
+             --
+             let ofile = outputFile dflags
+             let no_hs_main = dopt Opt_NoHsMain dflags
+             let mb_main_mod = mainModIs dflags
+             let 
+               main_mod = mb_main_mod `orElse` "Main"
+               a_root_is_Main 
+                           = any ((==main_mod).moduleUserString.ms_mod) 
+                         mod_graph
+               do_linking = a_root_is_Main || no_hs_main
+
+             when (ghci_mode == BatchCompile && isJust ofile && not do_linking
+                    && verb > 0) $
+                hPutStrLn stderr ("Warning: output was redirected with -o, " ++
+                                  "but no output will be generated\n" ++
+                                  "because there is no " ++ main_mod ++ " module.")
+
+             -- link everything together
+              linkresult <- link ghci_mode dflags do_linking (hsc_HPT hsc_env3)
+
+             let hsc_env4 = hsc_env3{ hsc_mod_graph = modsDone }
+             loadFinish Succeeded linkresult ref hsc_env4
+
+         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.
+           do when (verb >= 2) $
+               hPutStrLn stderr "Upsweep partially successful."
+
+              let modsDone_names
+                     = map ms_mod modsDone
+              let mods_to_zap_names 
+                     = findPartiallyCompletedCycles modsDone_names 
+                         mg2_with_srcimps
+              let mods_to_keep
+                     = filter ((`notElem` mods_to_zap_names).ms_mod) 
+                         modsDone
+
+              let hpt4 = retainInTopLevelEnvs (map ms_mod mods_to_keep) 
+                                             (hsc_HPT hsc_env3)
+
+             -- Clean up after ourselves
+             cleanTempFilesExcept dflags (ppFilesFromSummaries mods_to_keep)
+
+             -- Link everything together
+              linkresult <- link ghci_mode dflags False hpt4
+
+             let hsc_env4 = hsc_env3{ hsc_mod_graph = mods_to_keep,
+                                      hsc_HPT = hpt4 }
+             loadFinish Failed linkresult ref hsc_env4
+
+-- Finish up after a load.
+
+-- If the link failed, unload everything and return.
+loadFinish all_ok Failed ref hsc_env
+  = do unload hsc_env []
+       writeIORef ref $! discardProg hsc_env
+       return Failed
+
+-- Empty the interactive context and set the module context to the topmost
+-- newly loaded module, or the Prelude if none were loaded.
+loadFinish all_ok Succeeded ref hsc_env
+  = do writeIORef ref $! hsc_env{ hsc_IC = emptyInteractiveContext }
+       return all_ok
+
+-- Forget the current program, but retain the persistent info in HscEnv
+discardProg :: HscEnv -> HscEnv
+discardProg hsc_env
+  = hsc_env { hsc_mod_graph = emptyMG, 
+             hsc_IC = emptyInteractiveContext,
+             hsc_HPT = emptyHomePackageTable }
+
+-- used to fish out the preprocess output files for the purposes of
+-- cleaning up.  The preprocessed file *might* be the same as the
+-- source file, but that doesn't do any harm.
+ppFilesFromSummaries summaries = [ fn | Just fn <- map ms_hspp_file summaries ]
+
+-----------------------------------------------------------------------------
+-- Unloading
+
+unload :: HscEnv -> [Linkable] -> IO ()
+unload hsc_env stable_linkables        -- Unload everthing *except* 'stable_linkables'
+  = case ghcMode (hsc_dflags hsc_env) of
+       BatchCompile -> return ()
+#ifdef GHCI
+       Interactive -> Linker.unload (hsc_dflags hsc_env) stable_linkables
+#else
+       Interactive -> panic "unload: no interpreter"
+#endif
+       other -> panic "unload: strange mode"
+    
+-----------------------------------------------------------------------------
+-- getValidLinkables
+
+-- For each module (or SCC of modules), we take:
+--
+--     - an on-disk linkable, if this is the first time around and one
+--       is available.
+--
+--     - the old linkable, otherwise (and if one is available).
+--
+-- and we throw away the linkable if it is older than the source file.
+-- In interactive mode, we also ignore the on-disk linkables unless
+-- all of the dependents of this SCC also have on-disk linkables (we
+-- can't have dynamically loaded objects that depend on interpreted
+-- modules in GHCi).
+--
+-- 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.
+-- 
+-- ****************
+-- CAREFUL!  This pass operates on the cyclic version of
+-- the module graph (topSortModuleGraph True), whereas the upsweep operates on
+-- the non-cyclic (topSortModuleGraph False) version of the graph.
+-- ****************
+
+getValidLinkables
+       :: GhcMode
+       -> [Linkable]           -- old linkables
+       -> [Module]             -- all home modules
+       -> [SCC ModSummary]     -- all modules in the program, dependency order
+       -> IO ( [Linkable],     -- still-valid linkables 
+               [Linkable]      -- new linkables we just found on the disk
+                               -- presumably generated by separate run of ghc
+             )
+
+getValidLinkables mode old_linkables all_home_mods module_graph
+  = do {       -- Process the SCCs in bottom-to-top order
+               -- (foldM works left-to-right)
+         ls <- foldM (getValidLinkablesSCC mode old_linkables all_home_mods) 
+                     [] module_graph
+       ; return (partition_it ls [] []) }
+ where
+  partition_it []         valid new = (valid,new)
+  partition_it ((l,b):ls) valid new 
+       | b         = partition_it ls valid (l:new)
+       | otherwise = partition_it ls (l:valid) new
+
+
+getValidLinkablesSCC
+       :: GhcMode
+       -> [Linkable]           -- old linkables
+       -> [Module]             -- all home modules
+       -> [(Linkable,Bool)]
+       -> SCC ModSummary
+       -> IO [(Linkable,Bool)]
+
+getValidLinkablesSCC mode old_linkables all_home_mods new_linkables scc0
+   = let 
+         scc             = flattenSCC scc0
+          scc_names       = map ms_mod scc
+         home_module m   = m `elem` all_home_mods && m `notElem` scc_names
+          scc_allhomeimps = nub (filter home_module (concatMap ms_imps scc))
+               -- NB. ms_imps, not ms_allimps above.  We don't want to
+               -- force a module's SOURCE imports to be already compiled for
+               -- its object linkable to be valid.
+
+               -- The new_linkables is only the *valid* linkables below here
+         has_object m = case findModuleLinkable_maybe (map fst new_linkables) m of
+                           Nothing -> False
+                           Just l  -> isObjectLinkable l
+
+          objects_allowed = mode == BatchCompile || all has_object scc_allhomeimps
+     in do
+
+     new_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.
+     new_linkables' <- 
+        if objects_allowed
+            && not (all isObjectLinkable (map fst new_linkables'))
+         then foldM (getValidLinkable old_linkables False) [] scc
+         else return new_linkables'
+
+     return (new_linkables ++ new_linkables')
+
+
+getValidLinkable :: [Linkable] -> Bool -> [(Linkable,Bool)] -> ModSummary 
+       -> IO [(Linkable,Bool)]
+       -- True <=> linkable is new; i.e. freshly discovered on the disk
+       --                                presumably generated 'on the side'
+       --                                by a separate GHC run
+getValidLinkable old_linkables objects_allowed new_linkables summary 
+       -- 'objects_allowed' says whether we permit this module to
+       -- have a .o-file linkable.  We only permit it if all the
+       -- modules it depends on also have .o files; a .o file can't
+       -- link to a bytecode module
+   = do let mod_name = ms_mod summary
+
+       maybe_disk_linkable
+          <- if (not objects_allowed)
+               then return Nothing
+
+               else findLinkable mod_name (ms_location summary)
+
+       let old_linkable = findModuleLinkable_maybe old_linkables mod_name
+
+           new_linkables' = 
+            case (old_linkable, maybe_disk_linkable) of
+               (Nothing, Nothing)                      -> []
+
+               -- new object linkable just appeared
+               (Nothing, Just l)                       -> up_to_date l True
+
+               (Just l,  Nothing)
+                 | isObjectLinkable l                  -> []
+                   -- object linkable disappeared!  In case we need to
+                   -- relink the module, disregard the old linkable and
+                   -- just interpret the module from now on.
+                 | otherwise                           -> up_to_date l False
+                   -- old byte code linkable
+
+               (Just l, Just l') 
+                 | not (isObjectLinkable l)            -> up_to_date l  False
+                   -- if the previous linkable was interpreted, then we
+                   -- ignore a newly compiled version, because the version
+                   -- numbers in the interface file will be out-of-sync with
+                   -- our internal ones.
+                 | linkableTime l' >  linkableTime l   -> up_to_date l' True
+                 | linkableTime l' == linkableTime l   -> up_to_date l  False
+                 | otherwise                           -> []
+                   -- on-disk linkable has been replaced by an older one!
+                   -- again, disregard the previous one.
+
+           up_to_date l b
+               | linkableTime l < ms_hs_date summary = []
+               | otherwise = [(l,b)]
+               -- 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, 
+               -- especially if the source was automatically generated
+               -- and compiled.  Using >= is slightly unsafe, but it matches
+               -- make's behaviour.
+
+       return (new_linkables' ++ new_linkables)
+
+
+hptLinkables :: HomePackageTable -> [Linkable]
+-- Get all the linkables from the home package table, one for each module
+-- Once the HPT is up to date, these are the ones we should link
+hptLinkables hpt = map hm_linkable (moduleEnvElts hpt)
+
+
+-----------------------------------------------------------------------------
+-- 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 HPT (interactive mode only)
+
+preUpsweep :: [Linkable]       -- new valid linkables
+           -> [Module]         -- names of all mods encountered in downsweep
+           -> [ModSummary]     -- accumulating stable modules
+           -> [SCC ModSummary]  -- scc-ified mod graph, including src imps
+           -> IO [ModSummary]  -- stable modules
+
+preUpsweep valid_lis all_home_mods stable []  = return stable
+preUpsweep valid_lis all_home_mods stable (scc0:sccs)
+   = do let scc = flattenSCC scc0
+            scc_allhomeimps :: [Module]
+            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_mods     = map ms_mod scc
+            stable_names = scc_mods ++ map ms_mod stable
+            in_stable_or_scc m = m `elem` stable_names
+
+           -- now we check for valid linkables: each module in the SCC must 
+           -- have a valid linkable (see getValidLinkables above).
+           has_valid_linkable scc_mod
+             = isJust (findModuleLinkable_maybe valid_lis scc_mod)
+
+           scc_is_stable = all_imports_in_scc_or_stable
+                         && all has_valid_linkable scc_mods
+
+        if scc_is_stable
+         then preUpsweep valid_lis all_home_mods (scc ++ stable) sccs
+         else preUpsweep valid_lis all_home_mods stable         sccs
+
+ms_allimps :: ModSummary -> [Module]
+ms_allimps ms = ms_srcimps ms ++ ms_imps ms
+
+-- Return (names of) all those in modsDone who are part of a cycle
+-- as defined by theGraph.
+findPartiallyCompletedCycles :: [Module] -> [SCC ModSummary] -> [Module]
+findPartiallyCompletedCycles modsDone theGraph
+   = chew theGraph
+     where
+        chew [] = []
+        chew ((AcyclicSCC v):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, 
+                                   done `elem` names_in_this_cycle])
+                 chewed_rest = chew rest
+             in 
+             if   notNull mods_in_this_cycle
+                  && length mods_in_this_cycle < length names_in_this_cycle
+             then mods_in_this_cycle ++ chewed_rest
+             else chewed_rest
+
+
+-- Compile multiple modules, stopping as soon as an error appears.
+-- There better had not be any cyclic groups here -- we check for them.
+upsweep_mods :: HscEnv                         -- Includes initially-empty HPT
+             -> (HomePackageTable, [Linkable]) -- HPT and valid linkables from last time round
+            -> IO ()                           -- How to clean up unwanted tmp files
+             -> [SCC ModSummary]               -- Mods to do (the worklist)
+             -> IO (SuccessFlag,
+                    HscEnv,            -- With an updated HPT
+                    [ModSummary])      -- Mods which succeeded
+
+upsweep_mods hsc_env oldUI cleanup
+     []
+   = return (Succeeded, hsc_env, [])
+
+upsweep_mods hsc_env oldUI cleanup
+     (CyclicSCC ms:_)
+   = do hPutStrLn stderr (showSDoc (cyclicModuleErr ms))
+        return (Failed, hsc_env, [])
+
+upsweep_mods hsc_env oldUI@(old_hpt, old_linkables) cleanup
+     (AcyclicSCC mod:mods)
+   = do -- putStrLn ("UPSWEEP_MOD: hpt = " ++ 
+       --           show (map (moduleUserString.moduleName.mi_module.hm_iface) 
+       --                     (moduleEnvElts (hsc_HPT hsc_env)))
+
+        mb_mod_info <- upsweep_mod hsc_env oldUI mod 
+
+       cleanup         -- Remove unwanted tmp files between compilations
+
+        case mb_mod_info of
+           Nothing -> return (Failed, hsc_env, [])
+           Just mod_info -> do 
+               { let this_mod = ms_mod mod
+
+                       -- Add new info to hsc_env
+                     hpt1     = extendModuleEnv (hsc_HPT hsc_env) this_mod mod_info
+                     hsc_env1 = hsc_env { hsc_HPT = hpt1 }
+                       -- Space-saving: delete the old HPT entry and
+                       -- linkable for mod BUT if mod is a hs-boot
+                       -- node, don't delete it For the linkable this
+                       -- is dead right: the linkable relates only to
+                       -- the main Haskell source file.  For the
+                       -- interface, the HPT entry is probaby for the
+                       -- main Haskell source file.  Deleting it
+                       -- would force .. (what?? --SDM)
+                     oldUI1 | isBootSummary mod = oldUI
+                            | otherwise
+                            = (delModuleEnv old_hpt this_mod, 
+                                 delModuleLinkable old_linkables this_mod)
+
+               ; (restOK, hsc_env2, modOKs) <- upsweep_mods hsc_env1 oldUI1 cleanup mods
+               ; return (restOK, hsc_env2, mod:modOKs) }
+
+
+-- Compile a single module.  Always produce a Linkable for it if 
+-- successful.  If no compilation happened, return the old Linkable.
+upsweep_mod :: HscEnv
+            -> (HomePackageTable, UnlinkedImage)
+            -> ModSummary
+            -> IO (Maybe HomeModInfo)  -- Nothing => Failed
+
+upsweep_mod hsc_env (old_hpt, old_linkables) summary
+   = do 
+        let this_mod = ms_mod summary
+
+       -- The old interface is ok if it's in the old HPT 
+       --      a) we're compiling a source file, and the old HPT
+       --      entry is for a source file
+       --      b) we're compiling a hs-boot file
+       -- Case (b) allows an hs-boot file to get the interface of its
+       -- 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 
+               = case lookupModuleEnv old_hpt this_mod of
+                    Nothing                              -> Nothing
+                    Just hm_info | isBootSummary summary -> Just iface
+                                 | not (mi_boot iface)   -> Just iface
+                                 | otherwise             -> Nothing
+                                  where 
+                                    iface = hm_iface hm_info
+
+            maybe_old_linkable = findModuleLinkable_maybe old_linkables this_mod
+            source_unchanged   = isJust maybe_old_linkable
+
+            old_linkable = expectJust "upsweep_mod:old_linkable" maybe_old_linkable
+
+           have_object 
+              | Just l <- maybe_old_linkable, isObjectLinkable l = True
+              | otherwise = False
+
+        compresult <- compile hsc_env summary source_unchanged have_object mb_old_iface
+
+        case compresult of
+
+           -- Compilation "succeeded", and may or may not have returned a new
+           -- linkable (depending on whether compilation was actually performed
+          -- or not).
+           CompOK new_details new_iface maybe_new_linkable
+              -> do let 
+                       new_linkable = maybe_new_linkable `orElse` old_linkable
+                       new_info = HomeModInfo { hm_iface = new_iface,
+                                                hm_details = new_details,
+                                                hm_linkable = new_linkable }
+                    return (Just new_info)
+
+           -- Compilation failed.  Compile may still have updated the PCS, tho.
+           CompErrs -> return Nothing
+
+-- Filter modules in the HPT
+retainInTopLevelEnvs :: [Module] -> HomePackageTable -> HomePackageTable
+retainInTopLevelEnvs keep_these hpt
+   = mkModuleEnv [ (mod, fromJust mb_mod_info)
+                | mod <- keep_these
+                , let mb_mod_info = lookupModuleEnv hpt mod
+                , isJust mb_mod_info ]
+
+-- ---------------------------------------------------------------------------
+-- Topological sort of the module graph
+
+topSortModuleGraph
+         :: Bool               -- Drop hi-boot nodes? (see below)
+         -> [ModSummary]
+         -> [SCC ModSummary]
+-- Calculate SCCs of the module graph, possibly dropping the hi-boot nodes
+--
+-- Drop hi-boot nodes (first boolean arg)? 
+--
+--   False:    treat the hi-boot summaries as nodes of the graph,
+--             so the graph must be acyclic
+--
+--   True:     eliminate the hi-boot nodes, and instead pretend
+--             the a source-import of Foo is an import of Foo
+--             The resulting graph has no hi-boot nodes, but can by cyclic
+
+topSortModuleGraph drop_hs_boot_nodes summaries
+   = stronglyConnComp nodes
+   where
+       -- Drop hs-boot nodes by using HsSrcFile as the key
+       hs_boot_key | drop_hs_boot_nodes = HsSrcFile
+                   | otherwise          = HsBootFile   
+
+       -- We use integers as the keys for the SCC algorithm
+       nodes :: [(ModSummary, Int, [Int])]     
+       nodes = [(s, fromJust (lookup_key (ms_hsc_src s) (ms_mod s)), 
+                    out_edge_keys hs_boot_key (ms_srcimps s) ++
+                    out_edge_keys HsSrcFile   (ms_imps s)    )
+               | s <- summaries
+               , not (isBootSummary s && drop_hs_boot_nodes) ]
+               -- Drop the hi-boot ones if told to do so
+
+       key_map :: NodeMap Int
+       key_map = listToFM ([(ms_mod s, ms_hsc_src s) | s <- summaries]
+                          `zip` [1..])
+
+       lookup_key :: HscSource -> Module -> Maybe Int
+       lookup_key hs_src mod = lookupFM key_map (mod, hs_src)
+
+       out_edge_keys :: HscSource -> [Module] -> [Int]
+        out_edge_keys hi_boot ms = mapCatMaybes (lookup_key hi_boot) ms
+               -- If we want keep_hi_boot_nodes, then we do lookup_key with
+               -- the IsBootInterface parameter True; else False
+
+
+type NodeKey   = (Module, HscSource)     -- The nodes of the graph are 
+type NodeMap a = FiniteMap NodeKey a     -- keyed by (mod, src_file_type) pairs
+
+msKey :: ModSummary -> NodeKey
+msKey (ModSummary { ms_mod = mod, ms_hsc_src = boot }) = (mod,boot)
+
+emptyNodeMap :: NodeMap a
+emptyNodeMap = emptyFM
+
+mkNodeMap :: [ModSummary] -> NodeMap ModSummary
+mkNodeMap summaries = listToFM [ (msKey s, s) | s <- summaries]
+       
+nodeMapElts :: NodeMap a -> [a]
+nodeMapElts = eltsFM
+
+-- -----------------------------------------------------------------
+-- The unlinked image
+-- 
+-- The compilation manager keeps a list of compiled, but as-yet unlinked
+-- binaries (byte code or object code).  Even when it links bytecode
+-- it keeps the unlinked version so it can re-link it later without
+-- recompiling.
+
+type UnlinkedImage = [Linkable]        -- the unlinked images (should be a set, really)
+
+findModuleLinkable_maybe :: [Linkable] -> Module -> Maybe Linkable
+findModuleLinkable_maybe lis mod
+   = case [LM time nm us | LM time nm us <- lis, nm == mod] of
+        []   -> Nothing
+        [li] -> Just li
+        many -> pprPanic "findModuleLinkable" (ppr mod)
+
+delModuleLinkable :: [Linkable] -> Module -> [Linkable]
+delModuleLinkable ls mod = [ l | l@(LM _ nm _) <- ls, nm /= mod ]
+
+-----------------------------------------------------------------------------
+-- Downsweep (dependency analysis)
+
+-- Chase downwards from the specified root set, returning summaries
+-- for all home modules encountered.  Only follow source-import
+-- links.
+
+-- We pass in the previous collection of summaries, which is used as a
+-- cache to avoid recalculating a module summary if the source is
+-- 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 
+-- are all there, including the imports of non-home-package modules.
+
+downsweep :: HscEnv
+         -> [ModSummary]       -- Old summaries
+         -> [Module]           -- Ignore dependencies on these; treat them as
+                               -- if they were package modules
+         -> IO [ModSummary]
+downsweep hsc_env old_summaries excl_mods
+   = do rootSummaries <- mapM getRootSummary roots
+       checkDuplicates rootSummaries
+        loop (concatMap msDeps rootSummaries) 
+            (mkNodeMap rootSummaries)
+     where
+       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 (TargetFile file) maybe_buf)
+          = do exists <- doesFileExist file
+               if exists then summariseFile hsc_env file else do
+               throwDyn (CmdLineError ("can't find file: " ++ file))   
+       getRootSummary (Target (TargetModule modl) maybe_buf)
+          = do maybe_summary <- summarise hsc_env emptyNodeMap Nothing False 
+                                          modl excl_mods
+               case maybe_summary of
+                  Nothing -> packageModErr modl
+                  Just s  -> return s
+
+       -- In a root module, the filename is allowed to diverge from the module
+       -- 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 :: [ModSummary] -> IO ()
+       checkDuplicates summaries = mapM_ check summaries
+         where check summ = 
+                 case dups of
+                       []     -> return ()
+                       [_one] -> return ()
+                       many   -> multiRootsErr modl many
+                  where modl = ms_mod summ
+                        dups = 
+                          [ fromJust (ml_hs_file (ms_location summ'))
+                          | summ' <- summaries, ms_mod summ' == modl ]
+
+       loop :: [(FilePath,Module,IsBootInterface)]
+                       -- Work list: process these modules
+            -> NodeMap ModSummary
+                       -- Visited set
+            -> IO [ModSummary]
+                       -- The result includes the worklist, except
+                       -- for those mentioned in the visited set
+       loop [] done      = return (nodeMapElts done)
+       loop ((cur_path, wanted_mod, is_boot) : ss) done 
+         | key `elemFM` done = loop ss done
+         | otherwise         = do { mb_s <- summarise hsc_env old_summary_map 
+                                                (Just cur_path) is_boot 
+                                                wanted_mod excl_mods
+                                  ; case mb_s of
+                                       Nothing -> loop ss done
+                                       Just s  -> loop (msDeps s ++ ss) 
+                                                       (addToFM done key s) }
+         where
+           key = (wanted_mod, if is_boot then HsBootFile else HsSrcFile)
+
+msDeps :: ModSummary -> [(FilePath,            -- Importing module
+                         Module,               -- Imported module
+                         IsBootInterface)]      -- {-# SOURCE #-} import or not
+-- (msDeps s) returns the dependencies of the ModSummary s.
+-- A wrinkle is that for a {-# SOURCE #-} import we return
+--     *both* the hs-boot file
+--     *and* the source file
+-- as "dependencies".  That ensures that the list of all relevant
+-- 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 s =  concat [ [(f, m, True), (f,m,False)] | m <- ms_srcimps s] 
+        ++ [(f,m,False) | m <- ms_imps    s] 
+       where
+         f = msHsFilePath s    -- Keep the importing module for error reporting
+
+
+-----------------------------------------------------------------------------
+-- Summarising modules
+
+-- We have two types of summarisation:
+--
+--    * Summarise a file.  This is used for the root module(s) passed to
+--     cmLoadModules.  The file is read, and used to determine the root
+--     module name.  The module name may differ from the filename.
+--
+--    * Summarise a module.  We are given a module name, and must provide
+--     a summary.  The finder is used to locate the file in which the module
+--     resides.
+
+summariseFile :: HscEnv -> FilePath -> IO ModSummary
+-- Used for Haskell source only, I think
+-- We know the file name, and we know it exists,
+-- but we don't necessarily know the module name (might differ)
+summariseFile hsc_env file
+   = do let dflags = hsc_dflags hsc_env
+
+       (dflags', hspp_fn) <- preprocess dflags file
+               -- The dflags' contains the OPTIONS pragmas
+
+       -- Read the file into a buffer.  We're going to cache
+       -- this buffer in the ModLocation (ml_hspp_buf) so that it
+       -- doesn't have to be slurped again when hscMain parses the
+       -- file later.
+       buf <- hGetStringBuffer hspp_fn
+        (srcimps,the_imps,mod) <- getImports dflags' buf hspp_fn
+
+       -- Make a ModLocation for this file
+       location <- mkHomeModLocation dflags mod file
+
+       -- Tell the Finder cache where it is, so that subsequent calls
+       -- to findModule will find it, even if it's not on any search path
+       addHomeModuleToFinder hsc_env mod location
+
+        src_timestamp <- getModificationTime file
+        return (ModSummary { ms_mod = mod, ms_hsc_src = HsSrcFile,
+                            ms_location = location,
+                             ms_hspp_file = Just hspp_fn,
+                            ms_hspp_buf  = Just buf,
+                             ms_srcimps = srcimps, ms_imps = the_imps,
+                            ms_hs_date = src_timestamp })
+
+-- Summarise a module, and pick up source and timestamp.
+summarise :: HscEnv
+         -> NodeMap ModSummary -- Map of old summaries
+         -> Maybe FilePath     -- Importing module (for error messages)
+         -> IsBootInterface    -- True <=> a {-# SOURCE #-} import
+         -> Module             -- Imported module to be summarised
+         -> [Module]           -- Modules to exclude
+         -> IO (Maybe ModSummary)      -- Its new summary
+
+summarise hsc_env old_summary_map cur_mod is_boot wanted_mod excl_mods
+  | wanted_mod `elem` excl_mods
+  = return Nothing
+
+  | Just old_summary <- lookupFM old_summary_map (wanted_mod, hsc_src)
+  = 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 = fromJust (ml_hs_file location)
+
+       ;  src_timestamp <- getModificationTime src_fn
+
+               -- return the cached summary if the source didn't change
+       ; if ms_hs_date old_summary == src_timestamp 
+         then return (Just old_summary)
+         else new_summary location
+       }
+
+  | otherwise
+  = do { found <- findModule hsc_env wanted_mod True {-explicit-}
+       ; case found of
+            Found location pkg 
+               | not (isHomePackage pkg)      -> return Nothing
+                       -- Drop external-pkg
+               | isJust (ml_hs_file location) -> new_summary location
+                       -- Home package
+            err -> noModError dflags cur_mod wanted_mod err
+                       -- Not found
+       }
+  where
+    dflags = hsc_dflags hsc_env
+
+    hsc_src = if is_boot then HsBootFile else HsSrcFile
+
+    new_summary location
+      = do {   -- 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
+             src_fn = fromJust (ml_hs_file location')
+
+               -- Check that it exists
+               -- It might have been deleted since the Finder last found it
+       ; exists <- doesFileExist src_fn
+       ; if exists then return () else noHsFileErr cur_mod src_fn
+
+       -- Preprocess the source file and get its imports
+       -- The dflags' contains the OPTIONS pragmas
+       ; (dflags', hspp_fn) <- preprocess dflags src_fn
+       ; buf <- hGetStringBuffer hspp_fn
+        ; (srcimps, the_imps, mod_name) <- getImports dflags' buf hspp_fn
+
+       ; when (mod_name /= wanted_mod) $
+               throwDyn (ProgramError 
+                  (showSDoc (text src_fn
+                             <>  text ": file name does not match module name"
+                             <+> quotes (ppr mod_name))))
+
+               -- Find its timestamp, and return the summary
+        ; src_timestamp <- getModificationTime src_fn
+       ; return (Just ( ModSummary { ms_mod       = wanted_mod, 
+                                     ms_hsc_src   = hsc_src,
+                                     ms_location  = location',
+                                     ms_hspp_file = Just hspp_fn,
+                                     ms_hspp_buf  = Just buf,
+                                     ms_srcimps   = srcimps,
+                                     ms_imps      = the_imps,
+                                     ms_hs_date   = src_timestamp }))
+       }
+
+
+-----------------------------------------------------------------------------
+--                     Error messages
+-----------------------------------------------------------------------------
+
+noModError :: DynFlags -> Maybe FilePath -> Module -> FindResult -> IO ab
+-- ToDo: we don't have a proper line number for this error
+noModError dflags cur_mod wanted_mod err
+  = throwDyn $ ProgramError $ showSDoc $
+    vcat [cantFindError dflags wanted_mod err,
+         nest 2 (parens (pp_where cur_mod))]
+                               
+noHsFileErr cur_mod path
+  = throwDyn $ CmdLineError $ showSDoc $
+    vcat [text "Can't find" <+> text path,
+         nest 2 (parens (pp_where cur_mod))]
+pp_where Nothing  = text "one of the roots of the dependency analysis"
+pp_where (Just p) = text "imported from" <+> text p
+
+packageModErr mod
+  = throwDyn (CmdLineError (showSDoc (text "module" <+>
+                                  quotes (ppr mod) <+>
+                                  text "is a package module")))
+
+multiRootsErr mod files
+  = throwDyn (ProgramError (showSDoc (
+       text "module" <+> quotes (ppr mod) <+> 
+       text "is defined in multiple files:" <+>
+       sep (map text files))))
+
+cyclicModuleErr :: [ModSummary] -> SDoc
+cyclicModuleErr ms
+  = hang (ptext SLIT("Module imports form a cycle for modules:"))
+       2 (vcat (map show_one ms))
+  where
+    show_one ms = sep [ show_mod (ms_hsc_src ms) (ms_mod ms),
+                       nest 2 $ ptext SLIT("imports:") <+> 
+                                  (pp_imps HsBootFile (ms_srcimps ms)
+                                  $$ pp_imps HsSrcFile  (ms_imps ms))]
+    show_mod hsc_src mod = ppr mod <> text (hscSourceString hsc_src)
+    pp_imps src mods = fsep (map (show_mod src) mods)
+
+
+-- | Inform GHC that the working directory has changed.  GHC will flush
+-- its cache of module locations, since it may no longer be valid.
+-- Note: if you change the working directory, you should also unload
+-- the current program (set targets to empty, followed by load).
+workingDirectoryChanged :: Session -> IO ()
+workingDirectoryChanged s = withSession s $ \hsc_env ->
+  flushFinderCache (hsc_FC hsc_env)
 
 -- -----------------------------------------------------------------------------
 -- inspecting the session
 
--- | Get the set of modules in the current session
-getLoadedModules :: Session -> IO [Module]
+-- | Get the module dependency graph.  After a 'load', this will contain
+-- only the modules that were successfully loaded.
+getModuleGraph :: Session -> IO ModuleGraph -- ToDo: DiGraph ModSummary
+getModuleGraph s = withSession s (return . hsc_mod_graph)
+
+getBindings :: Session -> IO [TyThing]
+getBindings s = withSession s (return . nameEnvElts . ic_type_env . hsc_IC)
 
--- | Get the module dependency graph
-getModuleGraph :: Session -> IO (DiGraph ModSummary)
+getPrintUnqual :: Session -> IO PrintUnqualified
+getPrintUnqual s = withSession s (return . icPrintUnqual . hsc_IC)
 
+#if 0
 getModuleInfo :: Session -> Module -> IO ModuleInfo
 
 data ObjectCode
@@ -316,10 +1338,13 @@ data Kind = ...
 -- Calls the lexer repeatedly.
 -- ToDo: add comment tokens to token stream
 getTokenStream :: Session -> Module -> IO [Located Token]
+#endif
 
 -- -----------------------------------------------------------------------------
 -- Interactive evaluation
 
+#ifdef GHCI
+
 -- | Set the interactive evaluation context.
 --
 -- Setting the context doesn't throw away any bindings; the bindings
@@ -329,32 +1354,213 @@ setContext :: Session
           -> [Module]  -- entire top level scope of these modules
           -> [Module]  -- exports only of these modules
           -> IO ()
-
--- | Get the interactive evaluation context.
+setContext (Session ref) toplevs exports = do 
+  hsc_env <- readIORef ref
+  let old_ic  = hsc_IC     hsc_env
+      hpt     = hsc_HPT    hsc_env
+      dflags  = hsc_dflags hsc_env
+
+  mapM_ (checkModuleExists hsc_env hpt) exports
+  export_env  <- mkExportEnv hsc_env exports
+  toplev_envs <- mapM (mkTopLevEnv hpt) toplevs
+  let all_env = foldr plusGlobalRdrEnv export_env toplev_envs
+  writeIORef ref hsc_env{ hsc_IC = old_ic { ic_toplev_scope = toplevs,
+                                           ic_exports      = exports,
+                                           ic_rn_gbl_env   = all_env } }
+
+checkModuleExists :: HscEnv -> HomePackageTable -> Module -> IO ()
+checkModuleExists hsc_env hpt mod = 
+  case lookupModuleEnv hpt mod of
+    Just mod_info -> return ()
+    _not_a_home_module -> do
+         res <- findPackageModule hsc_env mod True
+         case res of
+           Found _ _ -> return  ()
+           err -> let msg = cantFindError (hsc_dflags hsc_env) mod err in
+                  throwDyn (CmdLineError (showSDoc msg))
+
+mkTopLevEnv :: HomePackageTable -> Module -> IO GlobalRdrEnv
+mkTopLevEnv hpt modl
+ = case lookupModuleEnv hpt modl of
+      Nothing ->       
+        throwDyn (ProgramError ("mkTopLevEnv: not a home module " 
+                       ++ showSDoc (pprModule modl)))
+      Just details ->
+        case mi_globals (hm_iface details) of
+               Nothing  -> 
+                  throwDyn (ProgramError ("mkTopLevEnv: not interpreted " 
+                                               ++ showSDoc (pprModule modl)))
+               Just env -> return env
+
+-- | Get the interactive evaluation context, consisting of a pair of the
+-- set of modules from which we take the full top-level scope, and the set
+-- of modules from which we take just the exports respectively.
 getContext :: Session -> IO ([Module],[Module])
+getContext s = withSession s (\HscEnv{ hsc_IC=ic } ->
+                               return (ic_toplev_scope ic, ic_exports ic))
+
+-- | Returns 'True' if the specified module is interpreted, and hence has
+-- its full top-level scope available.
+moduleIsInterpreted :: Session -> Module -> IO Bool
+moduleIsInterpreted s modl = withSession s $ \h ->
+ case lookupModuleEnv (hsc_HPT h) modl of
+      Just details       -> return (isJust (mi_globals (hm_iface details)))
+      _not_a_home_module -> return False
 
 -- | Looks up an identifier in the current interactive context (for :info)
-lookupThing :: Session -> String -> IO [TyThing]
+getInfo :: Session -> String -> IO [GetInfoResult]
+getInfo s id = withSession s $ \hsc_env -> hscGetInfo hsc_env id
 
--- | Looks up a Name in the current interactive context (for inspecting
--- the result names from 'runStmt').
-lookupName :: Session -> Name -> IO TyThing
+-- -----------------------------------------------------------------------------
+-- Getting the type of an expression
 
 -- | Get the type of an expression
-exprType :: Session -> String -> IO (Either Errors Type)
+exprType :: Session -> String -> IO (Maybe Type)
+exprType s expr = withSession s $ \hsc_env -> do
+   maybe_stuff <- hscTcExpr hsc_env expr
+   case maybe_stuff of
+       Nothing -> return Nothing
+       Just ty -> return (Just tidy_ty)
+            where 
+               tidy_ty = tidyType emptyTidyEnv ty
+               dflags  = hsc_dflags hsc_env
+
+-- -----------------------------------------------------------------------------
+-- Getting the kind of a type
 
 -- | Get the kind of a  type
-typeKind  :: Session -> String -> IO (Either Errors Kind)
+typeKind  :: Session -> String -> IO (Maybe Kind)
+typeKind s str = withSession s $ \hsc_env -> do
+   maybe_stuff <- hscKcType hsc_env str
+   case maybe_stuff of
+       Nothing -> return Nothing
+       Just kind -> return (Just kind)
+
+-----------------------------------------------------------------------------
+-- lookupName: returns the TyThing for a Name in the interactive context.
+-- ToDo: should look it up in the full environment
+
+lookupName :: Session -> Name -> IO (Maybe TyThing)
+lookupName s name = withSession s $ \hsc_env -> do
+  return $! lookupNameEnv (ic_type_env (hsc_IC hsc_env)) name
+
+-----------------------------------------------------------------------------
+-- cmCompileExpr: compile an expression and deliver an HValue
+
+compileExpr :: Session -> String -> IO (Maybe HValue)
+compileExpr s expr = withSession s $ \hsc_env -> do
+  maybe_stuff <- hscStmt hsc_env ("let __cmCompileExpr = "++expr)
+  case maybe_stuff of
+       Nothing -> return Nothing
+       Just (new_ic, names, hval) -> do
+                       -- Run it!
+               hvals <- (unsafeCoerce# hval) :: IO [HValue]
+
+               case (names,hvals) of
+                 ([n],[hv]) -> return (Just hv)
+                 _          -> panic "compileExpr"
+
+-- -----------------------------------------------------------------------------
+-- running a statement interactively
 
 data RunResult
   = RunOk [Name]               -- ^ names bound by this evaluation
-  | RunFailed Errors           -- ^ statement failed compilation
+  | RunFailed                  -- ^ statement failed compilation
   | RunException Exception     -- ^ statement raised an exception
 
 -- | Run a statement in the current interactive context.  Statemenet
 -- may bind multple values.
 runStmt :: Session -> String -> IO RunResult
-
--- | Return a list of the transient bindings in the current interactive
--- context (i.e. those bindings made via runStmt).
-getInteractiveBindings :: Session -> IO [TyThing]
+runStmt (Session ref) expr
+   = do 
+       hsc_env <- readIORef ref
+
+       -- Turn off -fwarn-unused-bindings when running a statement, to hide
+       -- warnings about the implicit bindings we introduce.
+       let dflags'  = dopt_unset (hsc_dflags hsc_env) Opt_WarnUnusedBinds
+           hsc_env' = hsc_env{ hsc_dflags = dflags' }
+
+        maybe_stuff <- hscStmt hsc_env' expr
+
+        case maybe_stuff of
+          Nothing -> return RunFailed
+          Just (new_hsc_env, names, hval) -> do
+
+               let thing_to_run = unsafeCoerce# hval :: IO [HValue]
+               either_hvals <- sandboxIO thing_to_run
+
+               case either_hvals of
+                   Left e -> do
+                       -- on error, keep the *old* interactive context,
+                       -- so that 'it' is not bound to something
+                       -- that doesn't exist.
+                       return (RunException e)
+
+                   Right hvals -> do
+                       -- Get the newly bound things, and bind them.  
+                       -- Don't need to delete any shadowed bindings;
+                       -- the new ones override the old ones. 
+                       extendLinkEnv (zip names hvals)
+                       
+                       writeIORef ref new_hsc_env
+                       return (RunOk names)
+
+
+-- We run the statement in a "sandbox" to protect the rest of the
+-- system from anything the expression might do.  For now, this
+-- consists of just wrapping it in an exception handler, but see below
+-- for another version.
+
+sandboxIO :: IO a -> IO (Either Exception a)
+sandboxIO thing = Exception.try thing
+
+{-
+-- This version of sandboxIO runs the expression in a completely new
+-- RTS main thread.  It is disabled for now because ^C exceptions
+-- won't be delivered to the new thread, instead they'll be delivered
+-- to the (blocked) GHCi main thread.
+
+-- SLPJ: when re-enabling this, reflect a wrong-stat error as an exception
+
+sandboxIO :: IO a -> IO (Either Int (Either Exception a))
+sandboxIO thing = do
+  st_thing <- newStablePtr (Exception.try thing)
+  alloca $ \ p_st_result -> do
+    stat <- rts_evalStableIO st_thing p_st_result
+    freeStablePtr st_thing
+    if stat == 1
+       then do st_result <- peek p_st_result
+               result <- deRefStablePtr st_result
+               freeStablePtr st_result
+               return (Right result)
+       else do
+               return (Left (fromIntegral stat))
+
+foreign import "rts_evalStableIO"  {- safe -}
+  rts_evalStableIO :: StablePtr (IO a) -> Ptr (StablePtr a) -> IO CInt
+  -- more informative than the C type!
+-}
+
+-- ---------------------------------------------------------------------------
+-- cmBrowseModule: get all the TyThings defined in a module
+
+browseModule :: Session -> Module -> Bool -> IO [IfaceDecl]
+browseModule s modl exports_only = withSession s $ \hsc_env -> do
+  mb_decls <- getModuleContents hsc_env modl exports_only
+  case mb_decls of
+       Nothing -> return []            -- An error of some kind
+       Just ds -> return ds
+
+
+-----------------------------------------------------------------------------
+-- show a module and it's source/object filenames
+
+showModule :: Session -> ModSummary -> IO String
+showModule s mod_summary = withSession s $ \hsc_env -> do
+  case lookupModuleEnv (hsc_HPT hsc_env) (ms_mod mod_summary) of
+       Nothing       -> panic "missing linkable"
+       Just mod_info -> return (showModMsg obj_linkable mod_summary)
+                     where
+                        obj_linkable = isObjectLinkable (hm_linkable mod_info)
+
+#endif /* GHCI */
index 8570044..e1ee261 100644 (file)
@@ -42,6 +42,7 @@ import BasicTypes     ( Fixity )
 import SrcLoc          ( SrcLoc, noSrcLoc )
 #endif
 
+import Module          ( emptyModuleEnv )
 import RdrName         ( RdrName )
 import HsSyn           ( HsModule )
 import SrcLoc          ( Located(..) )
@@ -104,10 +105,15 @@ newHscEnv dflags
   = do         { eps_var <- newIORef initExternalPackageState
        ; us      <- mkSplitUniqSupply 'r'
        ; nc_var  <- newIORef (initNameCache us knownKeyNames)
+       ; fc_var  <- newIORef emptyModuleEnv
        ; return (HscEnv { hsc_dflags = dflags,
+                          hsc_targets = [],
+                          hsc_mod_graph = [],
+                          hsc_IC     = emptyInteractiveContext,
                           hsc_HPT    = emptyHomePackageTable,
                           hsc_EPS    = eps_var,
-                          hsc_NC     = nc_var } ) }
+                          hsc_NC     = nc_var,
+                          hsc_FC     = fc_var } ) }
                        
 
 knownKeyNames :: [Name]        -- Put here to avoid loops involving DsMeta,
@@ -590,11 +596,10 @@ A naked expression returns a singleton Name [it].
 #ifdef GHCI
 hscStmt                -- Compile a stmt all the way to an HValue, but don't run it
   :: HscEnv
-  -> InteractiveContext                -- Context for compiling
   -> String                    -- The statement
-  -> IO (Maybe (InteractiveContext, [Name], HValue))
+  -> IO (Maybe (HscEnv, [Name], HValue))
 
-hscStmt hsc_env icontext stmt
+hscStmt hsc_env stmt
   = do { maybe_stmt <- hscParseStmt (hsc_dflags hsc_env) stmt
        ; case maybe_stmt of {
             Nothing      -> return Nothing ;   -- Parse error
@@ -602,8 +607,8 @@ hscStmt hsc_env icontext stmt
             Just (Just parsed_stmt) -> do {    -- The real stuff
 
                -- Rename and typecheck it
-         maybe_tc_result
-                <- tcRnStmt hsc_env icontext parsed_stmt
+         let icontext = hsc_IC hsc_env
+       ; maybe_tc_result <- tcRnStmt hsc_env icontext parsed_stmt
 
        ; case maybe_tc_result of {
                Nothing -> return Nothing ;
@@ -615,17 +620,17 @@ hscStmt hsc_env icontext stmt
                              (ic_type_env new_ic)
                              tc_expr
 
-       ; return (Just (new_ic, bound_names, hval))
+       ; return (Just (hsc_env{ hsc_IC=new_ic }, bound_names, hval))
        }}}}}
 
 hscTcExpr      -- Typecheck an expression (but don't run it)
   :: HscEnv
-  -> InteractiveContext                -- Context for compiling
   -> String                    -- The expression
   -> IO (Maybe Type)
 
-hscTcExpr hsc_env icontext expr
+hscTcExpr hsc_env expr
   = do { maybe_stmt <- hscParseStmt (hsc_dflags hsc_env) expr
+       ; let icontext = hsc_IC hsc_env
        ; case maybe_stmt of {
             Nothing      -> return Nothing ;   -- Parse error
             Just (Just (L _ (ExprStmt expr _)))
@@ -636,12 +641,12 @@ hscTcExpr hsc_env icontext expr
 
 hscKcType      -- Find the kind of a type
   :: HscEnv
-  -> InteractiveContext                -- Context for compiling
   -> String                    -- The type
   -> IO (Maybe Kind)
 
-hscKcType hsc_env icontext str
+hscKcType hsc_env str
   = do { maybe_type <- hscParseType (hsc_dflags hsc_env) str
+       ; let icontext = hsc_IC hsc_env
        ; case maybe_type of {
             Just ty    -> tcRnType hsc_env icontext ty ;
             Just other -> do { errorMsg ("not an type: `" ++ str ++ "'") ;
@@ -698,17 +703,16 @@ hscParseThing parser dflags str
 #ifdef GHCI
 hscGetInfo -- like hscStmt, but deals with a single identifier
   :: HscEnv
-  -> InteractiveContext                -- Context for compiling
   -> String                    -- The identifier
   -> IO [GetInfoResult]
 
-hscGetInfo hsc_env ic str
+hscGetInfo hsc_env str
    = do maybe_rdr_name <- hscParseIdentifier (hsc_dflags hsc_env) str
        case maybe_rdr_name of {
          Nothing -> return [];
          Just (L _ rdr_name) -> do
 
-       maybe_tc_result <- tcRnGetInfo hsc_env ic rdr_name
+       maybe_tc_result <- tcRnGetInfo hsc_env (hsc_IC hsc_env) rdr_name
 
        case maybe_tc_result of
             Nothing     -> return []
index dd4f003..9fecb09 100644 (file)
@@ -5,7 +5,11 @@
 
 \begin{code}
 module HscTypes ( 
-       HscEnv(..), hscEPS,
+       -- * Sessions and compilation state
+       Session(..), HscEnv(..), hscEPS,
+       FinderCache, FinderCacheEntry,
+       Target(..), TargetId(..), pprTarget, pprTargetId,
+       ModuleGraph, emptyMG,
 
        ModDetails(..), 
        ModGuts(..), ModImports(..), ForeignStubs(..),
@@ -83,7 +87,7 @@ import Type           ( TyThing(..) )
 import Class           ( Class, classSelIds, classTyCon )
 import TyCon           ( TyCon, tyConSelIds, tyConDataCons )
 import DataCon         ( dataConImplicitIds )
-import Packages                ( PackageIdH, PackageId )
+import Packages                ( PackageIdH, PackageId, PackageConfig )
 import DynFlags                ( DynFlags(..), isOneShot )
 import DriverPhases    ( HscSource(..), isHsBoot, hscSourceString )
 import BasicTypes      ( Version, initialVersion, IPName, 
@@ -111,13 +115,42 @@ import Time               ( ClockTime )
 %*                                                                     *
 %************************************************************************
 
-The HscEnv gives the environment in which to compile a chunk of code.
+
+\begin{code}
+-- | The Session is a handle to the complete state of a compilation
+-- session.  A compilation session consists of a set of modules
+-- constituting the current program or library, the context for
+-- interactive evaluation, and various caches.
+newtype Session = Session (IORef HscEnv)
+\end{code}
+
+HscEnv is like Session, except that some of the fields are immutable.
+An HscEnv is used to compile a single module from plain Haskell source
+code (after preprocessing) to either C, assembly or C--.  Things like
+the module graph don't change during a single compilation.
+
+Historical note: "hsc" used to be the name of the compiler binary,
+when there was a separate driver and compiler.  To compile a single
+module, the driver would invoke hsc on the source code... so nowadays
+we think of hsc as the layer of the compiler that deals with compiling
+a single module.
 
 \begin{code}
 data HscEnv 
-  = HscEnv { hsc_dflags :: DynFlags,
+  = HscEnv { 
+       hsc_dflags :: DynFlags,
+               -- The dynamic flag settings
+
+       hsc_targets :: [Target],
+               -- The targets (or roots) of the current session
 
-            hsc_HPT    :: HomePackageTable,
+       hsc_mod_graph :: ModuleGraph,
+               -- The module graph of the current session
+
+       hsc_IC :: InteractiveContext,
+               -- The context for evaluating interactive statements
+
+       hsc_HPT    :: HomePackageTable,
                -- The home package table describes already-compiled
                -- home-packge modules, *excluding* the module we 
                -- are compiling right now.
@@ -135,18 +168,47 @@ data HscEnv
                -- but not actually below the current module in the dependency
                -- graph.  (This changes a previous invariant: changed Jan 05.)
        
-               -- The next two are side-effected by compiling
-               -- to reflect sucking in interface files
-            hsc_EPS    :: IORef ExternalPackageState,
-            hsc_NC     :: IORef NameCache }
+       hsc_EPS :: {-# UNPACK #-} !(IORef ExternalPackageState),
+       hsc_NC  :: {-# UNPACK #-} !(IORef NameCache),
+               -- These are side-effected by compiling to reflect
+               -- sucking in interface files.  They cache the state of
+               -- external interface files, in effect.
+
+       hsc_FC  :: {-# UNPACK #-} !(IORef FinderCache)
+               -- The finder's cache.  This caches the location of modules,
+               -- so we don't have to search the filesystem multiple times.
+ }
 
 hscEPS :: HscEnv -> IO ExternalPackageState
 hscEPS hsc_env = readIORef (hsc_EPS hsc_env)
-\end{code}
 
-\begin{code}
-type HomePackageTable  = ModuleEnv HomeModInfo -- Domain = modules in the home package
-type PackageIfaceTable = ModuleEnv ModIface    -- Domain = modules in the imported packages
+-- | A compilation target.
+--
+-- A target may be supplied with the actual text of the
+-- module.  If so, use this instead of the file contents (this
+-- is for use in an IDE where the file hasn't been saved by
+-- the user yet).
+data Target = Target TargetId (Maybe StringBuffer)
+
+data TargetId
+  = TargetModule Module           -- | A module name: search for the file
+  | TargetFile   FilePath  -- | A filename: parse it to find the module name.
+
+
+pprTarget :: Target -> SDoc
+pprTarget (Target id _) = pprTargetId id
+
+pprTargetId (TargetModule m) = ppr m
+pprTargetId (TargetFile f)   = text f
+
+type FinderCache = ModuleEnv FinderCacheEntry
+type FinderCacheEntry = (ModLocation, Maybe (PackageConfig,Bool))
+       -- The finder's cache (see module Finder)
+
+type HomePackageTable  = ModuleEnv HomeModInfo
+       -- Domain = modules in the home package
+type PackageIfaceTable = ModuleEnv ModIface
+       -- Domain = modules in the imported packages
 
 emptyHomePackageTable  = emptyModuleEnv
 emptyPackageIfaceTable = emptyModuleEnv
@@ -404,10 +466,10 @@ emptyModIface pkg mod
 \begin{code}
 data InteractiveContext 
   = InteractiveContext { 
-       ic_toplev_scope :: [String],    -- Include the "top-level" scope of
+       ic_toplev_scope :: [Module],    -- Include the "top-level" scope of
                                        -- these modules
 
-       ic_exports :: [String],         -- Include just the exports of these
+       ic_exports :: [Module],         -- Include just the exports of these
                                        -- modules
 
        ic_rn_gbl_env :: GlobalRdrEnv,  -- The cached GlobalRdrEnv, built from
@@ -852,17 +914,27 @@ addInstsToPool insts new_insts
 
 %************************************************************************
 %*                                                                     *
-               The ModSummary type
+               The module graph and ModSummary type
        A ModSummary is a node in the compilation manager's
        dependency graph, and it's also passed to hscMain
 %*                                                                     *
 %************************************************************************
 
-The nodes of the module graph are
-       EITHER a regular Haskell source module
-       OR     a hi-boot source module
+A ModuleGraph contains all the nodes from the home package (only).  
+There will be a node for each source module, plus a node for each hi-boot
+module.
 
 \begin{code}
+type ModuleGraph = [ModSummary]  -- The module graph, 
+                                -- NOT NECESSARILY IN TOPOLOGICAL ORDER
+
+emptyMG :: ModuleGraph
+emptyMG = []
+
+-- The nodes of the module graph are
+--     EITHER a regular Haskell source module
+--     OR     a hi-boot source module
+
 data ModSummary
    = ModSummary {
         ms_mod       :: Module,                        -- Name of the module
index 8d156db..ad25d55 100644 (file)
@@ -11,33 +11,31 @@ module Main (main) where
 
 #include "HsVersions.h"
 
-#ifdef GHCI
-import InteractiveUI   ( ghciWelcomeMsg, interactiveUI )
-#endif
-
+-- The official GHC API
+import qualified GHC
+import GHC             ( Session, DynFlags(..), GhcMode(..), HscTarget(..) )
+import CmdLineParser
 
+-- Implementations of the various modes (--show-iface, mkdependHS. etc.)
 import MkIface         ( showIface )
-import CompManager     ( cmInit, cmLoadModules, cmDepAnal )
-import Config
-import SysTools
-import Packages                ( dumpPackages, initPackages, haskell98PackageId,
-                         PackageIdH(..) )
-import DriverPipeline  ( runPipeline, staticLink, doMkDLL )
-
+import DriverPipeline  ( oneShot )
 import DriverMkDepend  ( doMkDependHS )
-import DriverPhases    ( Phase(..), isStopLn, isSourceFilename, anyHsc )
+import SysTools                ( getTopDir, getUsageMsgPaths )
+#ifdef GHCI
+import InteractiveUI   ( ghciWelcomeMsg, interactiveUI )
+#endif
 
-import DynFlags
-import StaticFlags     ( parseStaticFlags, staticFlags, v_Ld_inputs )
-import CmdLineParser
+-- Various other random stuff that we need
+import Config          ( cProjectVersion, cBooterVersion, cProjectName )
+import Packages                ( dumpPackages, initPackages )
+import DriverPhases    ( Phase(..), isSourceFilename, anyHsc )
+import StaticFlags     ( staticFlags, v_Ld_inputs )
 import BasicTypes      ( failed )
 import Util
 import Panic
 
 -- Standard Haskell libraries
-import EXCEPTION       ( throwDyn, Exception(..), 
-                         AsyncException(StackOverflow) )
-
+import EXCEPTION       ( throwDyn )
 import IO
 import Directory       ( doesFileExist, doesDirectoryExist )
 import System          ( getArgs, exitWith, ExitCode(..) )
@@ -55,97 +53,65 @@ import Maybe
 -- -K<size>
 
 -----------------------------------------------------------------------------
--- Main loop
+-- GHC's command-line interface
 
 main =
-  ---------------------------------------
-  -- exception handlers
-
-  -- top-level exception handler: any unrecognised exception is a compiler bug.
-  handle (\exception -> do
-          hFlush stdout
-          case exception of
-               -- an IO exception probably isn't our fault, so don't panic
-               IOException _ ->  hPutStrLn stderr (show exception)
-               AsyncException StackOverflow ->
-                       hPutStrLn stderr "stack overflow: use +RTS -K<size> to increase it"
-               _other ->  hPutStr stderr (show (Panic (show exception)))
-          exitWith (ExitFailure 1)
-         ) $ do
-
-  -- all error messages are propagated as exceptions
-  handleDyn (\dyn -> do
-               hFlush stdout
-               case dyn of
-                    PhaseFailed _ code -> exitWith code
-                    Interrupted -> exitWith (ExitFailure 1)
-                    _ -> do hPutStrLn stderr (show (dyn :: GhcException))
-                            exitWith (ExitFailure 1)
-           ) $ do
-
-   installSignalHandlers
-
-   ----------------------------------------
-   -- command-line parsing
-   argv0 <- getArgs
-
-   -- 1. we grab the -B option if there is one
-   let (minusB_args, argv1) = partition (prefixMatch "-B") argv0
-   dflags0 <- initSysTools minusB_args defaultDynFlags
-
-   -- 2. Parse the "mode" flags (--make, --interactive etc.)
-   (cli_mode, argv2) <- parseModeFlags argv1
-
-   -- 3. Parse the static flags
-   argv3 <- parseStaticFlags argv2
-
-   -- 4. Parse the dynamic flags
-   dflags1 <- initDynFlags dflags0
-
-   -- set the default HscTarget.  The HscTarget can be further
-   -- adjusted on a module by module basis, using only the -fvia-C and
-   -- -fasm flags.  If the default HscTarget is not HscC or HscAsm,
-   -- -fvia-C and -fasm have no effect.
-   let lang = case cli_mode of 
-                DoInteractive  -> HscInterpreted
-                DoEval _       -> HscInterpreted
-                _other         -> hscTarget dflags1
+  GHC.defaultErrorHandler $ do
+  
+  argv0 <- getArgs
+  argv1 <- GHC.init argv0
+
+  -- 2. Parse the "mode" flags (--make, --interactive etc.)
+  (cli_mode, argv2) <- parseModeFlags argv1
 
-   let mode = case cli_mode of
+  let mode = case cli_mode of
                DoInteractive   -> Interactive
                DoEval _        -> Interactive
                DoMake          -> BatchCompile
                DoMkDependHS    -> MkDepend
                _               -> OneShot
 
-   let dflags2 = dflags1{ ghcMode = mode,
-                         hscTarget  = lang,
-                         -- leave out hscOutName for now
-                         hscOutName = panic "Main.main:hscOutName not set",
-                         verbosity = case cli_mode of
+  -- start our GHC session
+  session <- GHC.newSession mode
+
+  dflags0 <- GHC.getSessionDynFlags session
+
+  -- set the default HscTarget.  The HscTarget can be further
+  -- adjusted on a module by module basis, using only the -fvia-C and
+  -- -fasm flags.  If the default HscTarget is not HscC or HscAsm,
+  -- -fvia-C and -fasm have no effect.
+  let lang = case cli_mode of 
+                DoInteractive  -> HscInterpreted
+                DoEval _       -> HscInterpreted
+                _other         -> hscTarget dflags0
+
+  let dflags1 = dflags0{ ghcMode = mode,
+                        hscTarget  = lang,
+                        -- leave out hscOutName for now
+                        hscOutName = panic "Main.main:hscOutName not set",
+                        verbosity = case cli_mode of
                                         DoEval _ -> 0
                                         _other   -> 1
                        }
 
        -- The rest of the arguments are "dynamic"
        -- Leftover ones are presumably files
-   (dflags3, fileish_args) <- parseDynamicFlags dflags2 argv3
+  (dflags2, fileish_args) <- GHC.parseDynamicFlags dflags1 argv2
 
        -- make sure we clean up after ourselves
-   later (unless (dopt Opt_KeepTmpFiles dflags3) $ 
-           cleanTempFiles dflags3) $ do
-       -- exceptions will be blocked while we clean the temporary files,
-       -- so there shouldn't be any difficulty if we receive further
-       -- signals.
+  GHC.defaultCleanupHandler dflags2 $ do
 
        -- Display banner
-   showBanner cli_mode dflags3
+  showBanner cli_mode dflags2
 
        -- Read the package config(s), and process the package-related
        -- command-line flags
-   dflags <- initPackages dflags3
+  dflags <- initPackages dflags2
+
+  -- we've finished manipulating the DynFlags, update the session
+  GHC.setSessionDynFlags session dflags
 
-   let
+  let
     {-
       We split out the object files (.o, .dll) and add them
       to v_Ld_inputs for use by the linker.
@@ -173,34 +139,34 @@ main =
     normal_fileish_paths = map normalisePath fileish_args
     (srcs, objs)         = partition looks_like_an_input normal_fileish_paths
 
-    -- Note: have v_Ld_inputs maintain the order in which 'objs' occurred on 
-    --       the command-line.
-   mapM_ (consIORef v_Ld_inputs) (reverse objs)
+  -- Note: have v_Ld_inputs maintain the order in which 'objs' occurred on 
+  --       the command-line.
+  mapM_ (consIORef v_Ld_inputs) (reverse objs)
 
        ---------------- Display configuration -----------
-   when (verbosity dflags >= 4) $
+  when (verbosity dflags >= 4) $
        dumpPackages dflags
 
-   when (verbosity dflags >= 3) $ do
+  when (verbosity dflags >= 3) $ do
        hPutStrLn stderr ("Hsc static flags: " ++ unwords staticFlags)
 
        ---------------- Final sanity checking -----------
-   checkOptions cli_mode dflags srcs objs
+  checkOptions cli_mode dflags srcs objs
 
        ---------------- Do the business -----------
-   case cli_mode of
+  case cli_mode of
        ShowUsage       -> showGhcUsage cli_mode
        PrintLibdir     -> do d <- getTopDir; putStrLn d
        ShowVersion     -> showVersion
         ShowNumVersion  -> putStrLn cProjectVersion
         ShowInterface f -> showIface f
-       DoMake          -> doMake dflags srcs
-       DoMkDependHS    -> doMkDependHS dflags srcs 
+       DoMake          -> doMake session srcs
+       DoMkDependHS    -> doMkDependHS session srcs 
        StopBefore p    -> oneShot dflags p srcs
-       DoInteractive   -> interactiveUI dflags srcs Nothing
-       DoEval expr     -> interactiveUI dflags srcs (Just expr)
+       DoInteractive   -> interactiveUI session srcs Nothing
+       DoEval expr     -> interactiveUI session srcs (Just expr)
 
-   exitWith ExitSuccess
+  exitWith ExitSuccess
 
 #ifndef GHCI
 interactiveUI _ _ _ = 
@@ -236,7 +202,7 @@ checkOptions cli_mode dflags srcs objs = do
 
        -- Check that there are some input files
        -- (except in the interactive case)
-   if null srcs && null objs && not (isInterpretiveMode cli_mode)
+   if null srcs && null objs && needsInputsMode cli_mode
        then throwDyn (UsageError "no input files")
        else do
 
@@ -304,6 +270,11 @@ isInterpretiveMode DoInteractive = True
 isInterpretiveMode (DoEval _)    = True
 isInterpretiveMode _             = False
 
+needsInputsMode DoMkDependHS   = True
+needsInputsMode (StopBefore _) = True
+needsInputsMode DoMake         = True
+needsInputsMode _              = False
+
 -- True if we are going to attempt to link in this mode.
 -- (we might not actually link, depending on the GhcLink flag)
 isLinkMode (StopBefore StopLn) = True
@@ -375,80 +346,18 @@ addFlag s = do
   putCmdLineState (m, f, s:flags)
 
 
--- -----------------------------------------------------------------------------
--- Compile files in one-shot mode.
-
-oneShot :: DynFlags -> Phase -> [String] -> IO ()
-oneShot dflags stop_phase srcs = do
-       o_files <- compileFiles stop_phase dflags srcs 
-       doLink dflags stop_phase o_files
-
-compileFiles :: Phase
-            -> DynFlags
-            -> [String]        -- Source files
-            -> IO [String]     -- Object files
-compileFiles stop_phase dflags srcs 
-  = mapM (compileFile stop_phase dflags) srcs
-
-compileFile :: Phase -> DynFlags -> FilePath -> IO FilePath
-compileFile stop_phase dflags src = do
-   exists <- doesFileExist src
-   when (not exists) $ 
-       throwDyn (CmdLineError ("does not exist: " ++ src))
-   
-   let
-       split    = dopt Opt_SplitObjs dflags
-       o_file   = outputFile dflags
-       ghc_link = ghcLink dflags       -- Set by -c or -no-link
-
-       -- When linking, the -o argument refers to the linker's output. 
-       -- otherwise, we use it as the name for the pipeline's output.
-        maybe_o_file
-        | StopLn <- stop_phase, not (isNoLink ghc_link) = Nothing
-               -- -o foo applies to linker
-        | otherwise = o_file
-               -- -o foo applies to the file we are compiling now
-
-        stop_phase' = case stop_phase of 
-                       As | split -> SplitAs
-                       other      -> stop_phase
-
-   (_, out_file) <- runPipeline stop_phase' dflags
-                        True maybe_o_file src Nothing{-no ModLocation-}
-   return out_file
-
-
-doLink :: DynFlags -> Phase -> [FilePath] -> IO ()
-doLink dflags stop_phase o_files
-  | not (isStopLn stop_phase)
-  = return ()          -- We stopped before the linking phase
-
-  | otherwise
-  = case ghcLink dflags of
-       NoLink     -> return ()
-       StaticLink -> staticLink dflags o_files link_pkgs
-       MkDLL      -> doMkDLL dflags o_files link_pkgs
-  where
-   -- Always link in the haskell98 package for static linking.  Other
-   -- packages have to be specified via the -package flag.
-    link_pkgs
-         | ExtPackage h98_id <- haskell98PackageId (pkgState dflags) = [h98_id]
-         | otherwise = []
-
-
 -- ----------------------------------------------------------------------------
 -- Run --make mode
 
-doMake :: DynFlags -> [String] -> IO ()
-doMake dflags []    = throwDyn (UsageError "no input files")
-doMake dflags srcs  = do 
-    state  <- cmInit dflags
-    graph  <- cmDepAnal state srcs
-    (_, ok_flag, _) <- cmLoadModules state graph
+doMake :: Session -> [String] -> IO ()
+doMake sess []    = throwDyn (UsageError "no input files")
+doMake sess srcs  = do 
+    targets <- mapM GHC.guessTarget srcs
+    GHC.setTargets sess targets
+    ok_flag <- GHC.load sess Nothing
     when (failed ok_flag) (exitWith (ExitFailure 1))
     return ()
 
-
 -- ---------------------------------------------------------------------------
 -- Various banners and verbosity output.
 
index 9fb7177..42c687f 100644 (file)
@@ -1078,12 +1078,11 @@ vanillaProv mod = Imported [ImportSpec mod mod False
 \begin{code}
 getModuleContents
   :: HscEnv
-  -> InteractiveContext
   -> Module                    -- Module to inspect
   -> Bool                      -- Grab just the exports, or the whole toplev
   -> IO (Maybe [IfaceDecl])
 
-getModuleContents hsc_env ictxt mod exports_only
+getModuleContents hsc_env mod exports_only
  = initTcPrintErrors hsc_env iNTERACTIVE (get_mod_contents exports_only)
  where
    get_mod_contents exports_only
@@ -1110,7 +1109,7 @@ getModuleContents hsc_env ictxt mod exports_only
             ; thing     <- tcLookupGlobal main_name
             ; return (filter_decl (availNames avail) (toIfaceDecl ext_nm thing)) }
 
-   ext_nm = interactiveExtNameFun (icPrintUnqual ictxt)
+   ext_nm = interactiveExtNameFun (icPrintUnqual (hsc_IC hsc_env))
 
 ---------------------
 filter_decl occs decl@(IfaceClass {ifSigs = sigs})