[project @ 2001-10-23 22:25:46 by sof]
[ghc-hetmet.git] / ghc / compiler / compMan / CompManager.lhs
index 347e1e9..1642b26 100644 (file)
@@ -4,6 +4,7 @@
 \section[CompManager]{The Compilation Manager}
 
 \begin{code}
+{-# OPTIONS -fvia-C #-}
 module CompManager ( 
     cmInit,      -- :: GhciMode -> IO CmState
 
@@ -18,7 +19,8 @@ module CompManager (
 #ifdef GHCI
     cmInfoThing,  -- :: CmState -> DynFlags -> String -> IO (Maybe TyThing)
 
-    cmRunStmt,   -- :: CmState -> DynFlags -> String -> IO (CmState, [Name])
+    CmRunResult(..),
+    cmRunStmt,   -- :: CmState -> DynFlags -> String -> IO (CmState, CmRunResult)
 
     cmTypeOfExpr, -- :: CmState -> DynFlags -> String
                  -- -> IO (CmState, Maybe String)
@@ -38,6 +40,7 @@ import CmLink
 import CmTypes
 import DriverPipeline
 import DriverFlags     ( getDynFlags )
+import DriverState     ( v_Output_file )
 import DriverPhases
 import DriverUtil
 import Finder
@@ -49,7 +52,8 @@ import HscMain                ( initPersistentCompilerState )
 import HscTypes
 import RnEnv           ( unQualInScope )
 import Id              ( idType, idName )
-import Name            ( Name, NamedThing(..), nameRdrName )
+import Name            ( Name, NamedThing(..), nameRdrName, nameModule,
+                         isHomePackageName )
 import NameEnv
 import RdrName         ( lookupRdrEnv, emptyRdrEnv )
 import Module
@@ -58,13 +62,15 @@ import Type         ( tidyType )
 import VarEnv          ( emptyTidyEnv )
 import UniqFM
 import Unique          ( Uniquable )
-import Digraph         ( SCC(..), stronglyConnComp, flattenSCC )
+import Digraph         ( SCC(..), stronglyConnComp, flattenSCC, flattenSCCs )
 import ErrUtils                ( showPass )
 import SysTools                ( cleanTempFilesExcept )
 import Util
 import Outputable
+import BasicTypes      ( Fixity, defaultFixity )
 import Panic
 import CmdLineOpts     ( DynFlags(..) )
+
 import IOExts
 
 #ifdef GHCI
@@ -74,7 +80,9 @@ import PrelGHC                ( unsafeCoerce# )
 #endif
 
 -- lang
-import Exception       ( throwDyn )
+import Foreign
+import CForeign
+import Exception       ( Exception, try, throwDyn )
 
 -- std
 import Directory        ( getModificationTime, doesFileExist )
@@ -178,23 +186,41 @@ moduleNameToModule mn
 -- 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.
 
+#ifdef GHCI
 cmInfoThing :: CmState -> DynFlags -> String 
-       -> IO (CmState, PrintUnqualified, [TyThing])
+       -> IO (CmState, PrintUnqualified, [(TyThing,Fixity)])
 cmInfoThing cmstate dflags id
    = do (new_pcs, things) <- hscThing dflags hst hit pcs icontext id
-       return (cmstate{ pcs=new_pcs }, unqual, things)
+       let pairs = map (\x -> (x, getFixity new_pcs (getName x))) things
+       return (cmstate{ pcs=new_pcs }, unqual, pairs)
    where 
      CmState{ hst=hst, hit=hit, pcs=pcs, pls=pls, ic=icontext } = cmstate
      unqual = getUnqual pcs hit icontext
 
+     getFixity :: PersistentCompilerState -> Name -> Fixity
+     getFixity pcs name
+       | Just iface  <- lookupModuleEnv iface_table (nameModule name),
+         Just fixity <- lookupNameEnv (mi_fixities iface) name
+         = fixity
+       | otherwise
+         = defaultFixity
+       where iface_table | isHomePackageName name = hit
+                         | otherwise              = pcs_PIT pcs
+#endif
+
 -----------------------------------------------------------------------------
 -- cmRunStmt:  Run a statement/expr.
 
 #ifdef GHCI
-cmRunStmt :: CmState -> DynFlags -> String
-       -> IO (CmState,                 -- new state
-              [Name])                  -- names bound by this evaluation
-cmRunStmt cmstate dflags expr
+data CmRunResult
+  = CmRunOk [Name]             -- names bound by this evaluation
+  | CmRunFailed 
+  | CmRunDeadlocked            -- statement deadlocked
+  | CmRunException Exception   -- statement raised an exception
+
+cmRunStmt :: CmState -> DynFlags -> String -> IO (CmState, CmRunResult)                
+cmRunStmt cmstate@CmState{ hst=hst, hit=hit, pcs=pcs, pls=pls, ic=icontext }
+          dflags expr
    = do 
        let InteractiveContext { 
                ic_rn_env = rn_env, 
@@ -205,7 +231,7 @@ cmRunStmt cmstate dflags expr
            <- hscStmt dflags hst hit pcs icontext expr False{-stmt-}
 
         case maybe_stuff of
-          Nothing -> return (cmstate{ pcs=new_pcs }, [])
+          Nothing -> return (cmstate{ pcs=new_pcs }, CmRunFailed)
           Just (ids, _, bcos) -> do
 
                -- update the interactive context
@@ -232,17 +258,56 @@ cmRunStmt cmstate dflags expr
 
                -- run it!
                let thing_to_run = unsafeCoerce# hval :: IO [HValue]
-               hvals <- thing_to_run
-
-               -- Get the newly bound things, and bind them.  Don't forget
-               -- to delete any shadowed bindings from the closure_env, lest
-               -- we end up with a space leak.
-               pls <- delListFromClosureEnv pls shadowed
-               new_pls <- addListToClosureEnv pls (zip names hvals)
-
-               return (cmstate{ pcs=new_pcs, pls=new_pls, ic=new_ic }, names)
-   where
-       CmState{ hst=hst, hit=hit, pcs=pcs, pls=pls, ic=icontext } = cmstate
+               either_hvals <- sandboxIO thing_to_run
+               case either_hvals of
+                  Left err
+                       | err == dEADLOCKED
+                       -> return ( cmstate{ pcs=new_pcs, ic=new_ic }, 
+                                   CmRunDeadlocked )
+                       | otherwise
+                       -> do hPutStrLn stderr ("unknown failure, code " ++ show err)
+                             return ( cmstate{ pcs=new_pcs, ic=new_ic }, CmRunFailed )
+
+                  Right maybe_hvals ->
+                    case maybe_hvals of
+                       Left e -> 
+                           return ( cmstate{ pcs=new_pcs, ic=new_ic }, 
+                                    CmRunException e )
+                       Right hvals -> do
+                            -- Get the newly bound things, and bind them.  
+                            -- Don't forget to delete any shadowed bindings from the
+                            -- closure_env, lest we end up with a space leak.
+                            pls <- delListFromClosureEnv pls shadowed
+                            new_pls <- addListToClosureEnv pls (zip names hvals)
+            
+                            return (cmstate{ pcs=new_pcs, pls=new_pls, ic=new_ic }, 
+                                    CmRunOk names)
+
+-- We run the statement in a "sandbox", which amounts to calling into
+-- the RTS to request a new main thread.  The main benefit is that we
+-- get to detect a deadlock this way, but also there's no danger that
+-- exceptions raised by the expression can affect the interpreter.
+
+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))
+
+-- ToDo: slurp this in from ghc/includes/RtsAPI.h somehow
+dEADLOCKED = 4 :: Int
+
+foreign import "rts_evalStableIO"  {- safe -}
+  rts_evalStableIO :: StablePtr (IO a) -> Ptr (StablePtr a) -> IO CInt
+  -- more informative than the C type!
 #endif
 
 -----------------------------------------------------------------------------
@@ -466,9 +531,13 @@ cmLoadModule cmstate1 rootnames
 
         let threaded2 = CmThreaded pcs1 hst1 hit1
 
+       -- clean up between compilations
+       let cleanup = cleanTempFilesExcept verb 
+                         (ppFilesFromSummaries (flattenSCCs upsweep_these))
+
         (upsweep_complete_success, threaded3, modsUpswept, newLis)
            <- upsweep_mods ghci_mode dflags valid_linkables reachable_from 
-                           threaded2 upsweep_these
+                           threaded2 cleanup upsweep_these
 
         let ui3 = add_to_ui valid_linkables newLis
         let (CmThreaded pcs3 hst3 hit3) = threaded3
@@ -498,6 +567,13 @@ cmLoadModule cmstate1 rootnames
              -- clean up after ourselves
              cleanTempFilesExcept verb (ppFilesFromSummaries modsDone)
 
+             -- issue a warning for the confusing case where the user said '-o foo'
+             -- but we're not going to do any linking.
+             ofile <- readIORef v_Output_file
+             when (ghci_mode == Batch && isJust ofile && not a_root_is_Main
+                    && verb > 0) $
+                hPutStrLn stderr "Warning: output was redirected with -o, but no output will be generated\nbecause there is no Main module."
+
              -- link everything together
               linkresult <- link ghci_mode dflags a_root_is_Main ui3 pls2
 
@@ -800,6 +876,7 @@ upsweep_mods :: GhciMode
              -> UnlinkedImage         -- valid linkables
              -> (ModuleName -> [ModuleName])  -- to construct downward closures
              -> CmThreaded            -- PCS & HST & HIT
+            -> IO ()                 -- how to clean up unwanted tmp files
              -> [SCC ModSummary]      -- mods to do (the worklist)
                                       -- ...... RETURNING ......
              -> IO (Bool{-complete success?-},
@@ -807,17 +884,17 @@ upsweep_mods :: GhciMode
                     [ModSummary],     -- mods which succeeded
                     [Linkable])       -- new linkables
 
-upsweep_mods ghci_mode dflags oldUI reachable_from threaded 
+upsweep_mods ghci_mode dflags oldUI reachable_from threaded cleanup
      []
    = return (True, threaded, [], [])
 
-upsweep_mods ghci_mode dflags oldUI reachable_from threaded 
+upsweep_mods ghci_mode dflags oldUI reachable_from threaded cleanup
      ((CyclicSCC ms):_)
    = do hPutStrLn stderr ("Module imports form a cycle for modules:\n\t" ++
                           unwords (map (moduleNameUserString.name_of_summary) ms))
         return (False, threaded, [], [])
 
-upsweep_mods ghci_mode dflags oldUI reachable_from threaded 
+upsweep_mods ghci_mode dflags oldUI reachable_from threaded cleanup
      ((AcyclicSCC mod):mods)
    = do --case threaded of
         --   CmThreaded pcsz hstz hitz
@@ -826,12 +903,16 @@ upsweep_mods ghci_mode dflags oldUI reachable_from threaded
         (threaded1, maybe_linkable) 
            <- upsweep_mod ghci_mode dflags oldUI threaded mod 
                           (reachable_from (name_of_summary mod))
+
+       -- remove unwanted tmp files between compilations
+       cleanup
+
         case maybe_linkable of
            Just linkable 
               -> -- No errors; do the rest
                  do (restOK, threaded2, modOKs, linkables) 
                        <- upsweep_mods ghci_mode dflags oldUI reachable_from 
-                                       threaded1 mods
+                                       threaded1 cleanup mods
                     return (restOK, threaded2, mod:modOKs, linkable:linkables)
            Nothing -- we got a compilation error; give up now
               -> return (False, threaded1, [], [])
@@ -1057,7 +1138,7 @@ summariseFile file
         let (path, basename, ext) = splitFilename3 file
 
        (mod, location)
-          <- mkHomeModuleLocn mod_name (path ++ '/':basename) (Just file)
+          <- mkHomeModuleLocn mod_name (path ++ '/':basename) file
 
         src_timestamp
            <- case ml_hs_file location of 
@@ -1077,14 +1158,7 @@ summarise mod location old_summary
    = do let hs_fn = unJust "summarise" (ml_hs_file location)
 
         case ml_hs_file location of {
-           Nothing -> do {
-               dflags <- getDynFlags;
-               when (verbosity dflags >= 1) $
-                   hPutStrLn stderr ("WARNING: module `" ++ 
-                       moduleUserString mod ++ "' has no source file.");
-               return Nothing;
-            };
-
+           Nothing -> noHsFileErr mod;
            Just src_fn -> do
 
         src_timestamp <- getModificationTime src_fn