Split the Hsc phase into two subphases
[ghc.git] / compiler / main / HscMain.hs
index fe827e3..0aab82f 100644 (file)
@@ -32,16 +32,21 @@ module HscMain
       newHscEnv
 
     -- * Compiling complete source files
-    , Compiler
-    , HscStatus' (..)
-    , InteractiveStatus, HscStatus
+    , Messager, batchMsg
+    , HscStatus (..)
     , hscCompileOneShot
-    , hscCompileBatch
-    , hscCompileNothing
-    , hscCompileInteractive
     , hscCompileCmmFile
     , hscCompileCore
 
+    , genericHscCompileGetFrontendResult
+
+    , genModDetails
+    , hscSimpleIface
+    , hscWriteIface
+    , hscNormalIface
+    , hscGenHardCode
+    , hscInteractive
+
     -- * Running passes separately
     , hscParse
     , hscTypecheckRename
@@ -50,12 +55,6 @@ module HscMain
     , makeSimpleDetails
     , hscSimplify -- ToDo, shouldn't really export this
 
-    -- ** Backends
-    , hscOneShotBackendOnly
-    , hscBatchBackendOnly
-    , hscNothingBackendOnly
-    , hscInteractiveBackendOnly
-
     -- * Support for interactive evaluation
     , hscParseIdentifier
     , hscTcRcLookupName
@@ -525,188 +524,102 @@ This is the only thing that isn't caught by the type-system.
 -}
 
 
--- | Status of a compilation to hard-code or nothing.
-data HscStatus' a
-    = HscNoRecomp
-    | HscRecomp
-          (Maybe FilePath) -- Has stub files. This is a hack. We can't compile
-                           -- C files here since it's done in DriverPipeline.
-                           -- For now we just return True if we want the caller
-                           -- to compile them for us.
-          a
-
--- This is a bit ugly. Since we use a typeclass below and would like to avoid
--- functional dependencies, we have to parameterise the typeclass over the
--- result type. Therefore we need to artificially distinguish some types. We do
--- this by adding type tags which will simply be ignored by the caller.
-type HscStatus         = HscStatus' ()
-type InteractiveStatus = HscStatus' (Maybe (CompiledByteCode, ModBreaks))
-    -- INVARIANT: result is @Nothing@ <=> input was a boot file
-
-type OneShotResult     = HscStatus
-type BatchResult       = (HscStatus, ModIface, ModDetails)
-type NothingResult     = (HscStatus, ModIface, ModDetails)
-type InteractiveResult = (InteractiveStatus, ModIface, ModDetails)
-
--- ToDo: The old interface and module index are only using in 'batch' and
---       'interactive' mode. They should be removed from 'oneshot' mode.
-type Compiler result =  HscEnv
-                     -> ModSummary
-                     -> SourceModified
-                     -> Maybe ModIface  -- Old interface, if available
-                     -> Maybe (Int,Int) -- Just (i,n) <=> module i of n (for msgs)
-                     -> IO result
-
-data HsCompiler a = HsCompiler {
-    -- | Called when no recompilation is necessary.
-    hscNoRecomp :: ModIface
-                -> Hsc a,
-
-    -- | Called to recompile the module.
-    hscRecompile :: ModSummary -> Maybe Fingerprint
-                 -> Hsc a,
-
-    hscBackend :: TcGblEnv -> ModSummary -> Maybe Fingerprint
-               -> Hsc a,
-
-    -- | Code generation for Boot modules.
-    hscGenBootOutput :: TcGblEnv -> ModSummary -> Maybe Fingerprint
-                     -> Hsc a,
-
-    -- | Code generation for normal modules.
-    hscGenOutput :: ModGuts -> ModSummary -> Maybe Fingerprint
-                 -> Hsc a
-  }
-
-genericHscCompile :: HsCompiler a
-                  -> (HscEnv -> Maybe (Int,Int) -> RecompileRequired -> ModSummary -> IO ())
-                  -> HscEnv -> ModSummary -> SourceModified
-                  -> Maybe ModIface -> Maybe (Int, Int)
-                  -> IO a
-genericHscCompile compiler hscMessage hsc_env
-                  mod_summary source_modified
-                  mb_old_iface0 mb_mod_index
-  = do
-    (recomp_reqd, mb_checked_iface)
-        <- {-# SCC "checkOldIface" #-}
-           checkOldIface hsc_env mod_summary
-                         source_modified mb_old_iface0
-    -- save the interface that comes back from checkOldIface.
-    -- In one-shot mode we don't have the old iface until this
-    -- point, when checkOldIface reads it from the disk.
-    let mb_old_hash = fmap mi_iface_hash mb_checked_iface
+-- | Status of a compilation to hard-code
+data HscStatus
+    = HscNotGeneratingCode
+    | HscUpToDate
+    | HscUpdateBoot
+    | HscRecomp CgGuts ModSummary
+
+type Messager = HscEnv -> (Int,Int) -> RecompileRequired -> ModSummary -> IO ()
+
+genericHscCompileGetFrontendResult ::
+                     Bool -- always do basic recompilation check?
+                  -> Maybe TcGblEnv
+                  -> Maybe Messager
+                  -> HscEnv
+                  -> ModSummary
+                  -> SourceModified
+                  -> Maybe ModIface  -- Old interface, if available
+                  -> (Int,Int)       -- (i,n) = module i of n (for msgs)
+                  -> IO (Either ModIface (TcGblEnv, Maybe Fingerprint))
+
+genericHscCompileGetFrontendResult always_do_basic_recompilation_check m_tc_result
+                                   mHscMessage hsc_env mod_summary source_modified mb_old_iface mod_index
+    = do
+
+    let msg what = case mHscMessage of
+                   Just hscMessage -> hscMessage hsc_env mod_index what mod_summary
+                   Nothing -> return ()
 
-    let skip iface = do
-            hscMessage hsc_env mb_mod_index UpToDate mod_summary
-            runHsc hsc_env $ hscNoRecomp compiler iface
+        skip iface = do
+            msg UpToDate
+            return $ Left iface
 
-        compile reason = do
-            hscMessage hsc_env mb_mod_index reason mod_summary
-            runHsc hsc_env $ hscRecompile compiler mod_summary mb_old_hash
+        compile mb_old_hash reason = do
+            msg reason
+            tc_result <- runHsc hsc_env $ genericHscFrontend mod_summary
+            return $ Right (tc_result, mb_old_hash)
 
         stable = case source_modified of
                      SourceUnmodifiedAndStable -> True
                      _                         -> False
 
-        -- If the module used TH splices when it was last compiled,
-        -- then the recompilation check is not accurate enough (#481)
-        -- and we must ignore it. However, if the module is stable
-        -- (none of the modules it depends on, directly or indirectly,
-        -- changed), then we *can* skip recompilation. This is why
-        -- the SourceModified type contains SourceUnmodifiedAndStable,
-        -- and it's pretty important: otherwise ghc --make would
-        -- always recompile TH modules, even if nothing at all has
-        -- changed. Stability is just the same check that make is
-        -- doing for us in one-shot mode.
-
-    case mb_checked_iface of
-        Just iface | not (recompileRequired recomp_reqd) ->
-            if mi_used_th iface && not stable
-                then compile (RecompBecause "TH")
-                else skip iface
-        _otherwise ->
-            compile recomp_reqd
-
-hscCheckRecompBackend :: HsCompiler a -> TcGblEnv -> Compiler a
-hscCheckRecompBackend compiler tc_result hsc_env mod_summary
-                      source_modified mb_old_iface _m_of_n
-  = do
-    (recomp_reqd, mb_checked_iface)
-        <- {-# SCC "checkOldIface" #-}
-           checkOldIface hsc_env mod_summary
-                         source_modified mb_old_iface
-
-    let mb_old_hash = fmap mi_iface_hash mb_checked_iface
-    case mb_checked_iface of
-        Just iface | not (recompileRequired recomp_reqd)
-            -> runHsc hsc_env $
-                   hscNoRecomp compiler
-                       iface{ mi_globals = Just (tcg_rdr_env tc_result) }
-        _otherwise
-            -> runHsc hsc_env $
-                   hscBackend compiler tc_result mod_summary mb_old_hash
-
-genericHscRecompile :: HsCompiler a
-                    -> ModSummary -> Maybe Fingerprint
-                    -> Hsc a
-genericHscRecompile compiler mod_summary mb_old_hash
+    case m_tc_result of
+         Just tc_result
+          | not always_do_basic_recompilation_check ->
+             return $ Right (tc_result, Nothing)
+         _ -> do
+            (recomp_reqd, mb_checked_iface)
+                <- {-# SCC "checkOldIface" #-}
+                   checkOldIface hsc_env mod_summary
+                                source_modified mb_old_iface
+            -- save the interface that comes back from checkOldIface.
+            -- In one-shot mode we don't have the old iface until this
+            -- point, when checkOldIface reads it from the disk.
+            let mb_old_hash = fmap mi_iface_hash mb_checked_iface
+
+            case mb_checked_iface of
+                Just iface | not (recompileRequired recomp_reqd) ->
+                    -- If the module used TH splices when it was last compiled,
+                    -- then the recompilation check is not accurate enough (#481)
+                    -- and we must ignore it. However, if the module is stable
+                    -- (none of the modules it depends on, directly or indirectly,
+                    -- changed), then we *can* skip recompilation. This is why
+                    -- the SourceModified type contains SourceUnmodifiedAndStable,
+                    -- and it's pretty important: otherwise ghc --make would
+                    -- always recompile TH modules, even if nothing at all has
+                    -- changed. Stability is just the same check that make is
+                    -- doing for us in one-shot mode.
+                    case m_tc_result of
+                    Nothing
+                     | mi_used_th iface && not stable ->
+                        compile mb_old_hash (RecompBecause "TH")
+                    _ ->
+                        skip iface
+                _ ->
+                    case m_tc_result of
+                    Nothing -> compile mb_old_hash recomp_reqd
+                    Just tc_result ->
+                        return $ Right (tc_result, mb_old_hash)
+
+genericHscFrontend :: ModSummary -> Hsc TcGblEnv
+genericHscFrontend mod_summary
     | ExtCoreFile <- ms_hsc_src mod_summary =
         panic "GHC does not currently support reading External Core files"
     | otherwise = do
-        tc_result <- hscFileFrontEnd mod_summary
-        hscBackend compiler tc_result mod_summary mb_old_hash
-
-genericHscBackend :: HsCompiler a
-                  -> TcGblEnv -> ModSummary -> Maybe Fingerprint
-                  -> Hsc a
-genericHscBackend compiler tc_result mod_summary mb_old_hash
-    | HsBootFile <- ms_hsc_src mod_summary =
-        hscGenBootOutput compiler tc_result mod_summary mb_old_hash
-    | otherwise = do
-        guts <- hscDesugar' (ms_location mod_summary) tc_result
-        hscGenOutput compiler guts mod_summary mb_old_hash
-
-compilerBackend :: HsCompiler a -> TcGblEnv -> Compiler a
-compilerBackend comp tcg hsc_env ms' _ _mb_old_iface _ =
-    runHsc hsc_env $ hscBackend comp tcg ms' Nothing
+        hscFileFrontEnd mod_summary
 
 --------------------------------------------------------------
 -- Compilers
 --------------------------------------------------------------
 
-hscOneShotCompiler :: HsCompiler OneShotResult
-hscOneShotCompiler = HsCompiler {
-
-    hscNoRecomp = \_old_iface -> do
-        hsc_env <- getHscEnv
-        liftIO $ dumpIfaceStats hsc_env
-        return HscNoRecomp
-
-  , hscRecompile = genericHscRecompile hscOneShotCompiler
-
-  , hscBackend = \tc_result mod_summary mb_old_hash -> do
-        dflags <- getDynFlags
-        case hscTarget dflags of
-            HscNothing -> return (HscRecomp Nothing ())
-            _otherw    -> genericHscBackend hscOneShotCompiler
-                              tc_result mod_summary mb_old_hash
-
-  , hscGenBootOutput = \tc_result mod_summary mb_old_iface -> do
-        (iface, changed, _) <- hscSimpleIface tc_result mb_old_iface
-        hscWriteIface iface changed mod_summary
-        return (HscRecomp Nothing ())
-
-  , hscGenOutput = \guts0 mod_summary mb_old_iface -> do
-        guts <- hscSimplify' guts0
-        (iface, changed, _details, cgguts) <- hscNormalIface guts mb_old_iface
-        hscWriteIface iface changed mod_summary
-        hasStub <- hscGenHardCode cgguts mod_summary
-        return (HscRecomp hasStub ())
-  }
-
 -- Compile Haskell, boot and extCore in OneShot mode.
-hscCompileOneShot :: Compiler OneShotResult
-hscCompileOneShot hsc_env mod_summary src_changed mb_old_iface mb_i_of_n
+hscCompileOneShot :: HscEnv
+                  -> ModSummary
+                  -> SourceModified
+                  -> IO HscStatus
+hscCompileOneShot hsc_env mod_summary src_changed
   = do
     -- One-shot mode needs a knot-tying mutable variable for interface
     -- files. See TcRnTypes.TcGblEnv.tcg_type_env_var.
@@ -714,134 +627,88 @@ hscCompileOneShot hsc_env mod_summary src_changed mb_old_iface mb_i_of_n
     let mod = ms_mod mod_summary
         hsc_env' = hsc_env{ hsc_type_env_var = Just (mod, type_env_var) }
 
-    genericHscCompile hscOneShotCompiler
-                      oneShotMsg hsc_env' mod_summary src_changed
-                      mb_old_iface mb_i_of_n
-
-hscOneShotBackendOnly :: TcGblEnv -> Compiler OneShotResult
-hscOneShotBackendOnly = compilerBackend hscOneShotCompiler
-
---------------------------------------------------------------
-
-hscBatchCompiler :: HsCompiler BatchResult
-hscBatchCompiler = HsCompiler {
-
-    hscNoRecomp = \iface -> do
-        details <- genModDetails iface
-        return (HscNoRecomp, iface, details)
-
-  , hscRecompile = genericHscRecompile hscBatchCompiler
-
-  , hscBackend = genericHscBackend hscBatchCompiler
-
-  , hscGenBootOutput = \tc_result mod_summary mb_old_iface -> do
-        (iface, changed, details) <- hscSimpleIface tc_result mb_old_iface
-        hscWriteIface iface changed mod_summary
-        return (HscRecomp Nothing (), iface, details)
-
-  , hscGenOutput = \guts0 mod_summary mb_old_iface -> do
-        guts <- hscSimplify' guts0
-        (iface, changed, details, cgguts) <- hscNormalIface guts mb_old_iface
-        hscWriteIface iface changed mod_summary
-        hasStub <- hscGenHardCode cgguts mod_summary
-        return (HscRecomp hasStub (), iface, details)
-  }
-
--- | Compile Haskell, boot and extCore in batch mode.
-hscCompileBatch :: Compiler (HscStatus, ModIface, ModDetails)
-hscCompileBatch = genericHscCompile hscBatchCompiler batchMsg
-
-hscBatchBackendOnly :: TcGblEnv -> Compiler BatchResult
-hscBatchBackendOnly = hscCheckRecompBackend hscBatchCompiler
-
---------------------------------------------------------------
-
-hscInteractiveCompiler :: HsCompiler InteractiveResult
-hscInteractiveCompiler = HsCompiler {
-    hscNoRecomp = \iface -> do
-        details <- genModDetails iface
-        return (HscNoRecomp, iface, details)
-
-  , hscRecompile = genericHscRecompile hscInteractiveCompiler
-
-  , hscBackend = genericHscBackend hscInteractiveCompiler
-
-  , hscGenBootOutput = \tc_result _mod_summary mb_old_iface -> do
-        (iface, _changed, details) <- hscSimpleIface tc_result mb_old_iface
-        return (HscRecomp Nothing Nothing, iface, details)
-
-  , hscGenOutput = \guts0 mod_summary mb_old_iface -> do
-        guts <- hscSimplify' guts0
-        (iface, _changed, details, cgguts) <- hscNormalIface guts mb_old_iface
-        hscInteractive (iface, details, cgguts) mod_summary
-  }
-
--- Compile Haskell, extCore to bytecode.
-hscCompileInteractive :: Compiler (InteractiveStatus, ModIface, ModDetails)
-hscCompileInteractive = genericHscCompile hscInteractiveCompiler batchMsg
-
-hscInteractiveBackendOnly :: TcGblEnv -> Compiler InteractiveResult
-hscInteractiveBackendOnly = compilerBackend hscInteractiveCompiler
-
---------------------------------------------------------------
-
-hscNothingCompiler :: HsCompiler NothingResult
-hscNothingCompiler = HsCompiler {
-    hscNoRecomp = \iface -> do
-        details <- genModDetails iface
-        return (HscNoRecomp, iface, details)
-
-  , hscRecompile = genericHscRecompile hscNothingCompiler
-
-  , hscBackend = \tc_result _mod_summary mb_old_iface -> do
-        handleWarnings
-        (iface, _changed, details) <- hscSimpleIface tc_result mb_old_iface
-        return (HscRecomp Nothing (), iface, details)
-
-  , hscGenBootOutput = \_ _ _ ->
-        panic "hscCompileNothing: hscGenBootOutput should not be called"
-
-  , hscGenOutput = \_ _ _ ->
-        panic "hscCompileNothing: hscGenOutput should not be called"
-  }
+        msg what = oneShotMsg hsc_env' what
+
+        skip = do msg UpToDate
+                  dumpIfaceStats hsc_env'
+                  return HscUpToDate
+
+        compile mb_old_hash reason = runHsc hsc_env' $ do
+            liftIO $ msg reason
+            tc_result <- genericHscFrontend mod_summary
+            dflags <- getDynFlags
+            case hscTarget dflags of
+                HscNothing -> return HscNotGeneratingCode
+                _ ->
+                    case ms_hsc_src mod_summary of
+                    HsBootFile ->
+                        do (iface, changed, _) <- hscSimpleIface' tc_result mb_old_hash
+                           liftIO $ hscWriteIface dflags iface changed mod_summary
+                           return HscUpdateBoot
+                    _ ->
+                        do guts0 <- hscDesugar' (ms_location mod_summary) tc_result
+                           guts <- hscSimplify' guts0
+                           (iface, changed, _details, cgguts) <- hscNormalIface' guts mb_old_hash
+                           liftIO $ hscWriteIface dflags iface changed mod_summary
+                           return $ HscRecomp cgguts mod_summary
+
+        stable = case src_changed of
+                     SourceUnmodifiedAndStable -> True
+                     _                         -> False
 
--- Type-check Haskell and .hs-boot only (no external core)
-hscCompileNothing :: Compiler (HscStatus, ModIface, ModDetails)
-hscCompileNothing = genericHscCompile hscNothingCompiler batchMsg
+    (recomp_reqd, mb_checked_iface)
+        <- {-# SCC "checkOldIface" #-}
+           checkOldIface hsc_env' mod_summary src_changed Nothing
+    -- save the interface that comes back from checkOldIface.
+    -- In one-shot mode we don't have the old iface until this
+    -- point, when checkOldIface reads it from the disk.
+    let mb_old_hash = fmap mi_iface_hash mb_checked_iface
 
-hscNothingBackendOnly :: TcGblEnv -> Compiler NothingResult
-hscNothingBackendOnly = compilerBackend hscNothingCompiler
+    case mb_checked_iface of
+        Just iface | not (recompileRequired recomp_reqd) ->
+            -- If the module used TH splices when it was last compiled,
+            -- then the recompilation check is not accurate enough (#481)
+            -- and we must ignore it. However, if the module is stable
+            -- (none of the modules it depends on, directly or indirectly,
+            -- changed), then we *can* skip recompilation. This is why
+            -- the SourceModified type contains SourceUnmodifiedAndStable,
+            -- and it's pretty important: otherwise ghc --make would
+            -- always recompile TH modules, even if nothing at all has
+            -- changed. Stability is just the same check that make is
+            -- doing for us in one-shot mode.
+            if mi_used_th iface && not stable
+            then compile mb_old_hash (RecompBecause "TH")
+            else skip
+        _ ->
+            compile mb_old_hash recomp_reqd
 
 --------------------------------------------------------------
 -- NoRecomp handlers
 --------------------------------------------------------------
 
-genModDetails :: ModIface -> Hsc ModDetails
-genModDetails old_iface
+genModDetails :: HscEnv -> ModIface -> IO ModDetails
+genModDetails hsc_env old_iface
   = do
-    hsc_env <- getHscEnv
     new_details <- {-# SCC "tcRnIface" #-}
-                   liftIO $ initIfaceCheck hsc_env (typecheckIface old_iface)
-    liftIO $ dumpIfaceStats hsc_env
+                   initIfaceCheck hsc_env (typecheckIface old_iface)
+    dumpIfaceStats hsc_env
     return new_details
 
 --------------------------------------------------------------
 -- Progress displayers.
 --------------------------------------------------------------
 
-oneShotMsg :: HscEnv -> Maybe (Int,Int) -> RecompileRequired -> ModSummary
-            -> IO ()
-oneShotMsg hsc_env _mb_mod_index recomp _mod_summary =
+oneShotMsg :: HscEnv -> RecompileRequired -> IO ()
+oneShotMsg hsc_env recomp =
     case recomp of
         UpToDate ->
             compilationProgressMsg (hsc_dflags hsc_env) $
                    "compilation IS NOT required"
-        _other ->
+        _ ->
             return ()
 
-batchMsg :: HscEnv -> Maybe (Int,Int) -> RecompileRequired -> ModSummary
-         -> IO ()
-batchMsg hsc_env mb_mod_index recomp mod_summary =
+batchMsg :: Messager
+batchMsg hsc_env mod_index recomp mod_summary =
     case recomp of
         MustCompile -> showMsg "Compiling " ""
         UpToDate
@@ -852,7 +719,7 @@ batchMsg hsc_env mb_mod_index recomp mod_summary =
         dflags = hsc_dflags hsc_env
         showMsg msg reason =
             compilationProgressMsg dflags $
-            (showModuleIndex mb_mod_index ++
+            (showModuleIndex mod_index ++
             msg ++ showModMsg dflags (hscTarget dflags)
                               (recompileRequired recomp) mod_summary)
                 ++ reason
@@ -1192,10 +1059,17 @@ hscSimplify' ds_result = do
 -- Interface generators
 --------------------------------------------------------------
 
-hscSimpleIface :: TcGblEnv
+hscSimpleIface :: HscEnv
+               -> TcGblEnv
                -> Maybe Fingerprint
-               -> Hsc (ModIface, Bool, ModDetails)
-hscSimpleIface tc_result mb_old_iface = do
+               -> IO (ModIface, Bool, ModDetails)
+hscSimpleIface hsc_env tc_result mb_old_iface
+    = runHsc hsc_env $ hscSimpleIface' tc_result mb_old_iface
+
+hscSimpleIface' :: TcGblEnv
+                -> Maybe Fingerprint
+                -> Hsc (ModIface, Bool, ModDetails)
+hscSimpleIface' tc_result mb_old_iface = do
     hsc_env   <- getHscEnv
     details   <- liftIO $ mkBootModDetailsTc hsc_env tc_result
     safe_mode <- hscGetSafeMode tc_result
@@ -1207,10 +1081,17 @@ hscSimpleIface tc_result mb_old_iface = do
     liftIO $ dumpIfaceStats hsc_env
     return (new_iface, no_change, details)
 
-hscNormalIface :: ModGuts
+hscNormalIface :: HscEnv
+               -> ModGuts
                -> Maybe Fingerprint
-               -> Hsc (ModIface, Bool, ModDetails, CgGuts)
-hscNormalIface simpl_result mb_old_iface = do
+               -> IO (ModIface, Bool, ModDetails, CgGuts)
+hscNormalIface hsc_env simpl_result mb_old_iface =
+    runHsc hsc_env $ hscNormalIface' simpl_result mb_old_iface
+
+hscNormalIface' :: ModGuts
+                -> Maybe Fingerprint
+                -> Hsc (ModIface, Bool, ModDetails, CgGuts)
+hscNormalIface' simpl_result mb_old_iface = do
     hsc_env <- getHscEnv
     (cg_guts, details) <- {-# SCC "CoreTidy" #-}
                           liftIO $ tidyProgram hsc_env simpl_result
@@ -1239,19 +1120,24 @@ hscNormalIface simpl_result mb_old_iface = do
 -- BackEnd combinators
 --------------------------------------------------------------
 
-hscWriteIface :: ModIface -> Bool -> ModSummary -> Hsc ()
-hscWriteIface iface no_change mod_summary = do
-    dflags <- getDynFlags
+hscWriteIface :: DynFlags -> ModIface -> Bool -> ModSummary -> IO ()
+hscWriteIface dflags iface no_change mod_summary = do
+    let ifaceFile = ml_hi_file (ms_location mod_summary)
     unless no_change $
         {-# SCC "writeIface" #-}
-        liftIO $ writeIfaceFile dflags (ms_location mod_summary) iface
+        writeIfaceFile dflags ifaceFile iface
+    whenGeneratingDynamicToo dflags $ do
+        -- TODO: We should do a no_change check for the dynamic
+        --       interface file too
+        let dynIfaceFile = replaceExtension ifaceFile (dynHiSuf dflags)
+            dynIfaceFile' = addBootSuffix_maybe (mi_boot iface) dynIfaceFile
+            dynDflags = doDynamicToo dflags
+        writeIfaceFile dynDflags dynIfaceFile' iface
 
 -- | Compile to hard-code.
-hscGenHardCode :: CgGuts -> ModSummary
-               -> Hsc (Maybe FilePath) -- ^ @Just f@ <=> _stub.c is f
-hscGenHardCode cgguts mod_summary = do
-    hsc_env <- getHscEnv
-    liftIO $ do
+hscGenHardCode :: HscEnv -> CgGuts -> ModSummary
+               -> IO (FilePath, Maybe FilePath) -- ^ @Just f@ <=> _stub.c is f
+hscGenHardCode hsc_env cgguts mod_summary = do
         let CgGuts{ -- This is the last use of the ModGuts in a compilation.
                     -- From now on, we just use the bits we need.
                     cg_module   = this_mod,
@@ -1290,24 +1176,25 @@ hscGenHardCode cgguts mod_summary = do
         rawcmms0 <- {-# SCC "cmmToRawCmm" #-}
                    cmmToRawCmm dflags cmms
 
-        let dump a = do dumpIfSet_dyn dflags Opt_D_dump_raw_cmm "Raw Cmm"
+        let dump a = do dumpIfSet_dyn dflags Opt_D_dump_cmm_raw "Raw Cmm"
                            (ppr a)
                         return a
             rawcmms1 = Stream.mapM dump rawcmms0
 
-        (_stub_h_exists, stub_c_exists)
+        (output_filename, (_stub_h_exists, stub_c_exists))
             <- {-# SCC "codeOutput" #-}
                codeOutput dflags this_mod location foreign_stubs
                dependencies rawcmms1
-        return stub_c_exists
+        return (output_filename, stub_c_exists)
 
 
-hscInteractive :: (ModIface, ModDetails, CgGuts)
+hscInteractive :: HscEnv
+               -> CgGuts
                -> ModSummary
-               -> Hsc (InteractiveStatus, ModIface, ModDetails)
+               -> IO (Maybe FilePath, CompiledByteCode, ModBreaks)
 #ifdef GHCI
-hscInteractive (iface, details, cgguts) mod_summary = do
-    dflags <- getDynFlags
+hscInteractive hsc_env cgguts mod_summary = do
+    let dflags = hsc_dflags hsc_env
     let CgGuts{ -- This is the last use of the ModGuts in a compilation.
                 -- From now on, we just use the bits we need.
                cg_module   = this_mod,
@@ -1324,18 +1211,14 @@ hscInteractive (iface, details, cgguts) mod_summary = do
     -------------------
     -- PREPARE FOR CODE GENERATION
     -- Do saturation and convert to A-normal form
-    hsc_env <- getHscEnv
     prepd_binds <- {-# SCC "CorePrep" #-}
-                   liftIO $ corePrepPgm dflags hsc_env core_binds data_tycons
+                   corePrepPgm dflags hsc_env core_binds data_tycons
     -----------------  Generate byte code ------------------
-    comp_bc <- liftIO $ byteCodeGen dflags this_mod prepd_binds
-                                    data_tycons mod_breaks
+    comp_bc <- byteCodeGen dflags this_mod prepd_binds data_tycons mod_breaks
     ------------------ Create f-x-dynamic C-side stuff ---
     (_istub_h_exists, istub_c_exists)
-        <- liftIO $ outputForeignStubs dflags this_mod
-                                        location foreign_stubs
-    return (HscRecomp istub_c_exists (Just (comp_bc, mod_breaks))
-           , iface, details)
+        <- outputForeignStubs dflags this_mod location foreign_stubs
+    return (istub_c_exists, comp_bc, mod_breaks)
 #else
 hscInteractive _ _ = panic "GHC not compiled with interpreter"
 #endif
@@ -1349,7 +1232,7 @@ hscCompileCmmFile hsc_env filename = runHsc hsc_env $ do
     liftIO $ do
         us <- mkSplitUniqSupply 'S'
         let initTopSRT = initUs_ us emptySRT
-        dumpIfSet_dyn dflags Opt_D_dump_cmmz "Parsed Cmm" (ppr cmm)
+        dumpIfSet_dyn dflags Opt_D_dump_cmm "Parsed Cmm" (ppr cmm)
         (_, cmmgroup) <- cmmPipeline hsc_env initTopSRT cmm
         rawCmms <- cmmToRawCmm dflags (Stream.yield cmmgroup)
         _ <- codeOutput dflags no_mod no_loc NoStubs [] rawCmms
@@ -1384,7 +1267,7 @@ tryNewCodeGen hsc_env this_mod data_tycons
         -- CmmGroup on input may produce many CmmGroups on output due
         -- to proc-point splitting).
 
-    let dump1 a = do dumpIfSet_dyn dflags Opt_D_dump_cmmz
+    let dump1 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm
                        "Cmm produced by new codegen" (ppr a)
                      return a
 
@@ -1422,7 +1305,7 @@ tryNewCodeGen hsc_env this_mod data_tycons
                 Stream.yield (srtToData topSRT)
 
     let
-        dump2 a = do dumpIfSet_dyn dflags Opt_D_dump_cmmz "Output Cmm" $ ppr a
+        dump2 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm" $ ppr a
                      return a
 
         ppr_stream2 = Stream.mapM dump2 pipeline_stream
@@ -1606,6 +1489,7 @@ hscImport hsc_env str = runInteractiveHsc hsc_env $ do
                      ptext (sLit "parse error in import declaration")
 
 -- | Typecheck an expression (but don't run it)
+-- Returns its most general type
 hscTcExpr :: HscEnv
           -> String -- ^ The expression
           -> IO Type
@@ -1620,6 +1504,7 @@ hscTcExpr hsc_env0 expr = runInteractiveHsc hsc_env0 $ do
                 (text "not an expression:" <+> quotes (text expr))
 
 -- | Find the kind of a type
+-- Currently this does *not* generalise the kinds of the type
 hscKcType
   :: HscEnv
   -> Bool            -- ^ Normalise the type
@@ -1674,9 +1559,9 @@ hscCompileCore :: HscEnv -> Bool -> SafeHaskellMode -> ModSummary
 hscCompileCore hsc_env simplify safe_mode mod_summary binds
   = runHsc hsc_env $ do
         guts <- maybe_simplify (mkModGuts (ms_mod mod_summary) safe_mode binds)
-        (iface, changed, _details, cgguts) <- hscNormalIface guts Nothing
-        hscWriteIface iface changed mod_summary
-        _ <- hscGenHardCode cgguts mod_summary
+        (iface, changed, _details, cgguts) <- hscNormalIface' guts Nothing
+        liftIO $ hscWriteIface (hsc_dflags hsc_env) iface changed mod_summary
+        _ <- liftIO $ hscGenHardCode hsc_env cgguts mod_summary
         return ()
 
   where
@@ -1787,9 +1672,8 @@ dumpIfaceStats hsc_env = do
 %*                                                                      *
 %********************************************************************* -}
 
-showModuleIndex :: Maybe (Int, Int) -> String
-showModuleIndex Nothing = ""
-showModuleIndex (Just (i,n)) = "[" ++ padded ++ " of " ++ n_str ++ "] "
+showModuleIndex :: (Int, Int) -> String
+showModuleIndex (i,n) = "[" ++ padded ++ " of " ++ n_str ++ "] "
   where
     n_str = show n
     i_str = show i