summaryrefslogtreecommitdiff
path: root/compiler/main/HscMain.hs
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2020-02-18 11:08:48 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-02-21 20:46:40 -0500
commit240f5bf6f53515535be5bf3ef7632aa69ae21e3e (patch)
treedc7be78ca126c66af0aeb9f7944ebfc0ac5a211c /compiler/main/HscMain.hs
parentbe7068a6130f394dcefbcb5d09c2944deca2270d (diff)
downloadhaskell-240f5bf6f53515535be5bf3ef7632aa69ae21e3e.tar.gz
Modules: Driver (#13009)
submodule updates: nofib, haddock
Diffstat (limited to 'compiler/main/HscMain.hs')
-rw-r--r--compiler/main/HscMain.hs1952
1 files changed, 0 insertions, 1952 deletions
diff --git a/compiler/main/HscMain.hs b/compiler/main/HscMain.hs
deleted file mode 100644
index 879d8a05ec..0000000000
--- a/compiler/main/HscMain.hs
+++ /dev/null
@@ -1,1952 +0,0 @@
-{-# LANGUAGE BangPatterns, CPP, MagicHash, NondecreasingIndentation #-}
-{-# OPTIONS_GHC -fprof-auto-top #-}
-
--------------------------------------------------------------------------------
---
--- | Main API for compiling plain Haskell source code.
---
--- This module implements compilation of a Haskell source. It is
--- /not/ concerned with preprocessing of source files; this is handled
--- in "DriverPipeline".
---
--- There are various entry points depending on what mode we're in:
--- "batch" mode (@--make@), "one-shot" mode (@-c@, @-S@ etc.), and
--- "interactive" mode (GHCi). There are also entry points for
--- individual passes: parsing, typechecking/renaming, desugaring, and
--- simplification.
---
--- All the functions here take an 'HscEnv' as a parameter, but none of
--- them return a new one: 'HscEnv' is treated as an immutable value
--- from here on in (although it has mutable components, for the
--- caches).
---
--- We use the Hsc monad to deal with warning messages consistently:
--- specifically, while executing within an Hsc monad, warnings are
--- collected. When a Hsc monad returns to an IO monad, the
--- warnings are printed, or compilation aborts if the @-Werror@
--- flag is enabled.
---
--- (c) The GRASP/AQUA Project, Glasgow University, 1993-2000
---
--------------------------------------------------------------------------------
-
-module HscMain
- (
- -- * Making an HscEnv
- newHscEnv
-
- -- * Compiling complete source files
- , Messager, batchMsg
- , HscStatus (..)
- , hscIncrementalCompile
- , hscMaybeWriteIface
- , hscCompileCmmFile
-
- , hscGenHardCode
- , hscInteractive
-
- -- * Running passes separately
- , hscParse
- , hscTypecheckRename
- , hscDesugar
- , makeSimpleDetails
- , hscSimplify -- ToDo, shouldn't really export this
-
- -- * Safe Haskell
- , hscCheckSafe
- , hscGetSafe
-
- -- * Support for interactive evaluation
- , hscParseIdentifier
- , hscTcRcLookupName
- , hscTcRnGetInfo
- , hscIsGHCiMonad
- , hscGetModuleInterface
- , hscRnImportDecls
- , hscTcRnLookupRdrName
- , hscStmt, hscParseStmtWithLocation, hscStmtWithLocation, hscParsedStmt
- , hscDecls, hscParseDeclsWithLocation, hscDeclsWithLocation, hscParsedDecls
- , hscTcExpr, TcRnExprMode(..), hscImport, hscKcType
- , hscParseExpr
- , hscParseType
- , hscCompileCoreExpr
- -- * Low-level exports for hooks
- , hscCompileCoreExpr'
- -- We want to make sure that we export enough to be able to redefine
- -- hsc_typecheck in client code
- , hscParse', hscSimplify', hscDesugar', tcRnModule', doCodeGen
- , getHscEnv
- , hscSimpleIface'
- , oneShotMsg
- , dumpIfaceStats
- , ioMsgMaybe
- , showModuleIndex
- , hscAddSptEntries
- ) where
-
-import GhcPrelude
-
-import Data.Data hiding (Fixity, TyCon)
-import Data.Maybe ( fromJust )
-import Id
-import GHC.Runtime.Interpreter ( addSptEntry )
-import GHCi.RemoteTypes ( ForeignHValue )
-import GHC.CoreToByteCode ( byteCodeGen, coreExprToBCOs )
-import GHC.Runtime.Linker
-import CoreTidy ( tidyExpr )
-import Type ( Type )
-import {- Kind parts of -} Type ( Kind )
-import CoreLint ( lintInteractiveExpr )
-import VarEnv ( emptyTidyEnv )
-import Panic
-import ConLike
-import Control.Concurrent
-
-import ApiAnnotation
-import Module
-import Packages
-import RdrName
-import GHC.Hs
-import GHC.Hs.Dump
-import CoreSyn
-import StringBuffer
-import Parser
-import Lexer
-import SrcLoc
-import TcRnDriver
-import GHC.IfaceToCore ( typecheckIface )
-import TcRnMonad
-import TcHsSyn ( ZonkFlexi (DefaultFlexi) )
-import NameCache ( initNameCache )
-import GHC.Iface.Load ( ifaceStats, initExternalPackageState )
-import PrelInfo
-import GHC.Iface.Utils
-import GHC.HsToCore
-import SimplCore
-import GHC.Iface.Tidy
-import GHC.CoreToStg.Prep
-import GHC.CoreToStg ( coreToStg )
-import GHC.Stg.Syntax
-import GHC.Stg.FVs ( annTopBindingsFreeVars )
-import GHC.Stg.Pipeline ( stg2stg )
-import qualified GHC.StgToCmm as StgToCmm ( codeGen )
-import CostCentre
-import ProfInit
-import TyCon
-import Name
-import NameSet
-import GHC.Cmm
-import GHC.Cmm.Parser ( parseCmmFile )
-import GHC.Cmm.Info.Build
-import GHC.Cmm.Pipeline
-import GHC.Cmm.Info
-import CodeOutput
-import InstEnv
-import FamInstEnv
-import Fingerprint ( Fingerprint )
-import Hooks
-import TcEnv
-import PrelNames
-import Plugins
-import GHC.Runtime.Loader ( initializePlugins )
-
-import DynFlags
-import ErrUtils
-
-import Outputable
-import NameEnv
-import HscStats ( ppSourceStats )
-import HscTypes
-import FastString
-import UniqSupply
-import Bag
-import Exception
-import qualified Stream
-import Stream (Stream)
-
-import Util
-
-import Data.List ( nub, isPrefixOf, partition )
-import Control.Monad
-import Data.IORef
-import System.FilePath as FilePath
-import System.Directory
-import System.IO (fixIO)
-import qualified Data.Map as M
-import qualified Data.Set as S
-import Data.Set (Set)
-import Data.Functor
-import Control.DeepSeq (force)
-
-import GHC.Iface.Ext.Ast ( mkHieFile )
-import GHC.Iface.Ext.Types ( getAsts, hie_asts, hie_module )
-import GHC.Iface.Ext.Binary ( readHieFile, writeHieFile , hie_file_result)
-import GHC.Iface.Ext.Debug ( diffFile, validateScopes )
-
-#include "HsVersions.h"
-
-
-{- **********************************************************************
-%* *
- Initialisation
-%* *
-%********************************************************************* -}
-
-newHscEnv :: DynFlags -> IO HscEnv
-newHscEnv dflags = do
- eps_var <- newIORef initExternalPackageState
- us <- mkSplitUniqSupply 'r'
- nc_var <- newIORef (initNameCache us knownKeyNames)
- fc_var <- newIORef emptyInstalledModuleEnv
- iserv_mvar <- newMVar Nothing
- emptyDynLinker <- uninitializedLinker
- return HscEnv { hsc_dflags = dflags
- , hsc_targets = []
- , hsc_mod_graph = emptyMG
- , hsc_IC = emptyInteractiveContext dflags
- , hsc_HPT = emptyHomePackageTable
- , hsc_EPS = eps_var
- , hsc_NC = nc_var
- , hsc_FC = fc_var
- , hsc_type_env_var = Nothing
- , hsc_iserv = iserv_mvar
- , hsc_dynLinker = emptyDynLinker
- }
-
--- -----------------------------------------------------------------------------
-
-getWarnings :: Hsc WarningMessages
-getWarnings = Hsc $ \_ w -> return (w, w)
-
-clearWarnings :: Hsc ()
-clearWarnings = Hsc $ \_ _ -> return ((), emptyBag)
-
-logWarnings :: WarningMessages -> Hsc ()
-logWarnings w = Hsc $ \_ w0 -> return ((), w0 `unionBags` w)
-
-getHscEnv :: Hsc HscEnv
-getHscEnv = Hsc $ \e w -> return (e, w)
-
-handleWarnings :: Hsc ()
-handleWarnings = do
- dflags <- getDynFlags
- w <- getWarnings
- liftIO $ printOrThrowWarnings dflags w
- clearWarnings
-
--- | log warning in the monad, and if there are errors then
--- throw a SourceError exception.
-logWarningsReportErrors :: Messages -> Hsc ()
-logWarningsReportErrors (warns,errs) = do
- logWarnings warns
- when (not $ isEmptyBag errs) $ throwErrors errs
-
--- | Log warnings and throw errors, assuming the messages
--- contain at least one error (e.g. coming from PFailed)
-handleWarningsThrowErrors :: Messages -> Hsc a
-handleWarningsThrowErrors (warns, errs) = do
- logWarnings warns
- dflags <- getDynFlags
- (wWarns, wErrs) <- warningsToMessages dflags <$> getWarnings
- liftIO $ printBagOfErrors dflags wWarns
- throwErrors (unionBags errs wErrs)
-
--- | Deal with errors and warnings returned by a compilation step
---
--- In order to reduce dependencies to other parts of the compiler, functions
--- outside the "main" parts of GHC return warnings and errors as a parameter
--- and signal success via by wrapping the result in a 'Maybe' type. This
--- function logs the returned warnings and propagates errors as exceptions
--- (of type 'SourceError').
---
--- This function assumes the following invariants:
---
--- 1. If the second result indicates success (is of the form 'Just x'),
--- there must be no error messages in the first result.
---
--- 2. If there are no error messages, but the second result indicates failure
--- there should be warnings in the first result. That is, if the action
--- failed, it must have been due to the warnings (i.e., @-Werror@).
-ioMsgMaybe :: IO (Messages, Maybe a) -> Hsc a
-ioMsgMaybe ioA = do
- ((warns,errs), mb_r) <- liftIO ioA
- logWarnings warns
- case mb_r of
- Nothing -> throwErrors errs
- Just r -> ASSERT( isEmptyBag errs ) return r
-
--- | like ioMsgMaybe, except that we ignore error messages and return
--- 'Nothing' instead.
-ioMsgMaybe' :: IO (Messages, Maybe a) -> Hsc (Maybe a)
-ioMsgMaybe' ioA = do
- ((warns,_errs), mb_r) <- liftIO $ ioA
- logWarnings warns
- return mb_r
-
--- -----------------------------------------------------------------------------
--- | Lookup things in the compiler's environment
-
-hscTcRnLookupRdrName :: HscEnv -> Located RdrName -> IO [Name]
-hscTcRnLookupRdrName hsc_env0 rdr_name
- = runInteractiveHsc hsc_env0 $
- do { hsc_env <- getHscEnv
- ; ioMsgMaybe $ tcRnLookupRdrName hsc_env rdr_name }
-
-hscTcRcLookupName :: HscEnv -> Name -> IO (Maybe TyThing)
-hscTcRcLookupName hsc_env0 name = runInteractiveHsc hsc_env0 $ do
- hsc_env <- getHscEnv
- ioMsgMaybe' $ tcRnLookupName hsc_env name
- -- ignore errors: the only error we're likely to get is
- -- "name not found", and the Maybe in the return type
- -- is used to indicate that.
-
-hscTcRnGetInfo :: HscEnv -> Name
- -> IO (Maybe (TyThing, Fixity, [ClsInst], [FamInst], SDoc))
-hscTcRnGetInfo hsc_env0 name
- = runInteractiveHsc hsc_env0 $
- do { hsc_env <- getHscEnv
- ; ioMsgMaybe' $ tcRnGetInfo hsc_env name }
-
-hscIsGHCiMonad :: HscEnv -> String -> IO Name
-hscIsGHCiMonad hsc_env name
- = runHsc hsc_env $ ioMsgMaybe $ isGHCiMonad hsc_env name
-
-hscGetModuleInterface :: HscEnv -> Module -> IO ModIface
-hscGetModuleInterface hsc_env0 mod = runInteractiveHsc hsc_env0 $ do
- hsc_env <- getHscEnv
- ioMsgMaybe $ getModuleInterface hsc_env mod
-
--- -----------------------------------------------------------------------------
--- | Rename some import declarations
-hscRnImportDecls :: HscEnv -> [LImportDecl GhcPs] -> IO GlobalRdrEnv
-hscRnImportDecls hsc_env0 import_decls = runInteractiveHsc hsc_env0 $ do
- hsc_env <- getHscEnv
- ioMsgMaybe $ tcRnImportDecls hsc_env import_decls
-
--- -----------------------------------------------------------------------------
--- | parse a file, returning the abstract syntax
-
-hscParse :: HscEnv -> ModSummary -> IO HsParsedModule
-hscParse hsc_env mod_summary = runHsc hsc_env $ hscParse' mod_summary
-
--- internal version, that doesn't fail due to -Werror
-hscParse' :: ModSummary -> Hsc HsParsedModule
-hscParse' mod_summary
- | Just r <- ms_parsed_mod mod_summary = return r
- | otherwise = {-# SCC "Parser" #-}
- withTimingD (text "Parser"<+>brackets (ppr $ ms_mod mod_summary))
- (const ()) $ do
- dflags <- getDynFlags
- let src_filename = ms_hspp_file mod_summary
- maybe_src_buf = ms_hspp_buf mod_summary
-
- -------------------------- Parser ----------------
- -- sometimes we already have the buffer in memory, perhaps
- -- because we needed to parse the imports out of it, or get the
- -- module name.
- buf <- case maybe_src_buf of
- Just b -> return b
- Nothing -> liftIO $ hGetStringBuffer src_filename
-
- let loc = mkRealSrcLoc (mkFastString src_filename) 1 1
- let parseMod | HsigFile == ms_hsc_src mod_summary
- = parseSignature
- | otherwise = parseModule
-
- case unP parseMod (mkPState dflags buf loc) of
- PFailed pst ->
- handleWarningsThrowErrors (getMessages pst dflags)
- POk pst rdr_module -> do
- let (warns, errs) = getMessages pst dflags
- logWarnings warns
- liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser"
- FormatHaskell (ppr rdr_module)
- liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST"
- FormatHaskell (showAstData NoBlankSrcSpan rdr_module)
- liftIO $ dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics"
- FormatText (ppSourceStats False rdr_module)
- when (not $ isEmptyBag errs) $ throwErrors errs
-
- -- To get the list of extra source files, we take the list
- -- that the parser gave us,
- -- - eliminate files beginning with '<'. gcc likes to use
- -- pseudo-filenames like "<built-in>" and "<command-line>"
- -- - normalise them (eliminate differences between ./f and f)
- -- - filter out the preprocessed source file
- -- - filter out anything beginning with tmpdir
- -- - remove duplicates
- -- - filter out the .hs/.lhs source filename if we have one
- --
- let n_hspp = FilePath.normalise src_filename
- srcs0 = nub $ filter (not . (tmpDir dflags `isPrefixOf`))
- $ filter (not . (== n_hspp))
- $ map FilePath.normalise
- $ filter (not . isPrefixOf "<")
- $ map unpackFS
- $ srcfiles pst
- srcs1 = case ml_hs_file (ms_location mod_summary) of
- Just f -> filter (/= FilePath.normalise f) srcs0
- Nothing -> srcs0
-
- -- sometimes we see source files from earlier
- -- preprocessing stages that cannot be found, so just
- -- filter them out:
- srcs2 <- liftIO $ filterM doesFileExist srcs1
-
- let api_anns = ApiAnns {
- apiAnnItems = M.fromListWith (++) $ annotations pst,
- apiAnnEofPos = eof_pos pst,
- apiAnnComments = M.fromList (annotations_comments pst),
- apiAnnRogueComments = comment_q pst
- }
- res = HsParsedModule {
- hpm_module = rdr_module,
- hpm_src_files = srcs2,
- hpm_annotations = api_anns
- }
-
- -- apply parse transformation of plugins
- let applyPluginAction p opts
- = parsedResultAction p opts mod_summary
- withPlugins dflags applyPluginAction res
-
-
--- -----------------------------------------------------------------------------
--- | If the renamed source has been kept, extract it. Dump it if requested.
-extract_renamed_stuff :: ModSummary -> TcGblEnv -> Hsc RenamedStuff
-extract_renamed_stuff mod_summary tc_result = do
- let rn_info = getRenamedStuff tc_result
-
- dflags <- getDynFlags
- liftIO $ dumpIfSet_dyn dflags Opt_D_dump_rn_ast "Renamer"
- FormatHaskell (showAstData NoBlankSrcSpan rn_info)
-
- -- Create HIE files
- when (gopt Opt_WriteHie dflags) $ do
- -- I assume this fromJust is safe because `-fwrite-hie-file`
- -- enables the option which keeps the renamed source.
- hieFile <- mkHieFile mod_summary tc_result (fromJust rn_info)
- let out_file = ml_hie_file $ ms_location mod_summary
- liftIO $ writeHieFile out_file hieFile
-
- -- Validate HIE files
- when (gopt Opt_ValidateHie dflags) $ do
- hs_env <- Hsc $ \e w -> return (e, w)
- liftIO $ do
- -- Validate Scopes
- let mdl = hie_module hieFile
- case validateScopes mdl $ getAsts $ hie_asts hieFile of
- [] -> putMsg dflags $ text "Got valid scopes"
- xs -> do
- putMsg dflags $ text "Got invalid scopes"
- mapM_ (putMsg dflags) xs
- -- Roundtrip testing
- nc <- readIORef $ hsc_NC hs_env
- (file', _) <- readHieFile nc out_file
- case diffFile hieFile (hie_file_result file') of
- [] ->
- putMsg dflags $ text "Got no roundtrip errors"
- xs -> do
- putMsg dflags $ text "Got roundtrip errors"
- mapM_ (putMsg dflags) xs
- return rn_info
-
-
--- -----------------------------------------------------------------------------
--- | Rename and typecheck a module, additionally returning the renamed syntax
-hscTypecheckRename :: HscEnv -> ModSummary -> HsParsedModule
- -> IO (TcGblEnv, RenamedStuff)
-hscTypecheckRename hsc_env mod_summary rdr_module = runHsc hsc_env $
- hsc_typecheck True mod_summary (Just rdr_module)
-
-
--- | A bunch of logic piled around around @tcRnModule'@, concerning a) backpack
--- b) concerning dumping rename info and hie files. It would be nice to further
--- separate this stuff out, probably in conjunction better separating renaming
--- and type checking (#17781).
-hsc_typecheck :: Bool -- ^ Keep renamed source?
- -> ModSummary -> Maybe HsParsedModule
- -> Hsc (TcGblEnv, RenamedStuff)
-hsc_typecheck keep_rn mod_summary mb_rdr_module = do
- hsc_env <- getHscEnv
- let hsc_src = ms_hsc_src mod_summary
- dflags = hsc_dflags hsc_env
- outer_mod = ms_mod mod_summary
- mod_name = moduleName outer_mod
- outer_mod' = mkModule (thisPackage dflags) mod_name
- inner_mod = canonicalizeHomeModule dflags mod_name
- src_filename = ms_hspp_file mod_summary
- real_loc = realSrcLocSpan $ mkRealSrcLoc (mkFastString src_filename) 1 1
- keep_rn' = gopt Opt_WriteHie dflags || keep_rn
- MASSERT( moduleUnitId outer_mod == thisPackage dflags )
- tc_result <- if hsc_src == HsigFile && not (isHoleModule inner_mod)
- then ioMsgMaybe $ tcRnInstantiateSignature hsc_env outer_mod' real_loc
- else
- do hpm <- case mb_rdr_module of
- Just hpm -> return hpm
- Nothing -> hscParse' mod_summary
- tc_result0 <- tcRnModule' mod_summary keep_rn' hpm
- if hsc_src == HsigFile
- then do (iface, _, _) <- liftIO $ hscSimpleIface hsc_env tc_result0 Nothing
- ioMsgMaybe $
- tcRnMergeSignatures hsc_env hpm tc_result0 iface
- else return tc_result0
- -- TODO are we extracting anything when we merely instantiate a signature?
- -- If not, try to move this into the "else" case above.
- rn_info <- extract_renamed_stuff mod_summary tc_result
- return (tc_result, rn_info)
-
--- wrapper around tcRnModule to handle safe haskell extras
-tcRnModule' :: ModSummary -> Bool -> HsParsedModule
- -> Hsc TcGblEnv
-tcRnModule' sum save_rn_syntax mod = do
- hsc_env <- getHscEnv
- dflags <- getDynFlags
-
- -- -Wmissing-safe-haskell-mode
- when (not (safeHaskellModeEnabled dflags)
- && wopt Opt_WarnMissingSafeHaskellMode dflags) $
- logWarnings $ unitBag $
- makeIntoWarning (Reason Opt_WarnMissingSafeHaskellMode) $
- mkPlainWarnMsg dflags (getLoc (hpm_module mod)) $
- warnMissingSafeHaskellMode
-
- tcg_res <- {-# SCC "Typecheck-Rename" #-}
- ioMsgMaybe $
- tcRnModule hsc_env sum
- save_rn_syntax mod
-
- -- See Note [Safe Haskell Overlapping Instances Implementation]
- -- although this is used for more than just that failure case.
- (tcSafeOK, whyUnsafe) <- liftIO $ readIORef (tcg_safeInfer tcg_res)
- let allSafeOK = safeInferred dflags && tcSafeOK
-
- -- end of the safe haskell line, how to respond to user?
- res <- if not (safeHaskellOn dflags)
- || (safeInferOn dflags && not allSafeOK)
- -- if safe Haskell off or safe infer failed, mark unsafe
- then markUnsafeInfer tcg_res whyUnsafe
-
- -- module (could be) safe, throw warning if needed
- else do
- tcg_res' <- hscCheckSafeImports tcg_res
- safe <- liftIO $ fst <$> readIORef (tcg_safeInfer tcg_res')
- when safe $ do
- case wopt Opt_WarnSafe dflags of
- True
- | safeHaskell dflags == Sf_Safe -> return ()
- | otherwise -> (logWarnings $ unitBag $
- makeIntoWarning (Reason Opt_WarnSafe) $
- mkPlainWarnMsg dflags (warnSafeOnLoc dflags) $
- errSafe tcg_res')
- False | safeHaskell dflags == Sf_Trustworthy &&
- wopt Opt_WarnTrustworthySafe dflags ->
- (logWarnings $ unitBag $
- makeIntoWarning (Reason Opt_WarnTrustworthySafe) $
- mkPlainWarnMsg dflags (trustworthyOnLoc dflags) $
- errTwthySafe tcg_res')
- False -> return ()
- return tcg_res'
-
- -- apply plugins to the type checking result
-
-
- return res
- where
- pprMod t = ppr $ moduleName $ tcg_mod t
- errSafe t = quotes (pprMod t) <+> text "has been inferred as safe!"
- errTwthySafe t = quotes (pprMod t)
- <+> text "is marked as Trustworthy but has been inferred as safe!"
- warnMissingSafeHaskellMode = ppr (moduleName (ms_mod sum))
- <+> text "is missing Safe Haskell mode"
-
--- | Convert a typechecked module to Core
-hscDesugar :: HscEnv -> ModSummary -> TcGblEnv -> IO ModGuts
-hscDesugar hsc_env mod_summary tc_result =
- runHsc hsc_env $ hscDesugar' (ms_location mod_summary) tc_result
-
-hscDesugar' :: ModLocation -> TcGblEnv -> Hsc ModGuts
-hscDesugar' mod_location tc_result = do
- hsc_env <- getHscEnv
- r <- ioMsgMaybe $
- {-# SCC "deSugar" #-}
- deSugar hsc_env mod_location tc_result
-
- -- always check -Werror after desugaring, this is the last opportunity for
- -- warnings to arise before the backend.
- handleWarnings
- return r
-
--- | Make a 'ModDetails' from the results of typechecking. Used when
--- typechecking only, as opposed to full compilation.
-makeSimpleDetails :: HscEnv -> TcGblEnv -> IO ModDetails
-makeSimpleDetails hsc_env tc_result = mkBootModDetailsTc hsc_env tc_result
-
-
-{- **********************************************************************
-%* *
- The main compiler pipeline
-%* *
-%********************************************************************* -}
-
-{-
- --------------------------------
- The compilation proper
- --------------------------------
-
-It's the task of the compilation proper to compile Haskell, hs-boot and core
-files to either byte-code, hard-code (C, asm, LLVM, etc.) or to nothing at all
-(the module is still parsed and type-checked. This feature is mostly used by
-IDE's and the likes). Compilation can happen in either 'one-shot', 'batch',
-'nothing', or 'interactive' mode. 'One-shot' mode targets hard-code, 'batch'
-mode targets hard-code, 'nothing' mode targets nothing and 'interactive' mode
-targets byte-code.
-
-The modes are kept separate because of their different types and meanings:
-
- * In 'one-shot' mode, we're only compiling a single file and can therefore
- discard the new ModIface and ModDetails. This is also the reason it only
- targets hard-code; compiling to byte-code or nothing doesn't make sense when
- we discard the result.
-
- * 'Batch' mode is like 'one-shot' except that we keep the resulting ModIface
- and ModDetails. 'Batch' mode doesn't target byte-code since that require us to
- return the newly compiled byte-code.
-
- * 'Nothing' mode has exactly the same type as 'batch' mode but they're still
- kept separate. This is because compiling to nothing is fairly special: We
- don't output any interface files, we don't run the simplifier and we don't
- generate any code.
-
- * 'Interactive' mode is similar to 'batch' mode except that we return the
- compiled byte-code together with the ModIface and ModDetails.
-
-Trying to compile a hs-boot file to byte-code will result in a run-time error.
-This is the only thing that isn't caught by the type-system.
--}
-
-
-type Messager = HscEnv -> (Int,Int) -> RecompileRequired -> ModSummary -> IO ()
-
--- | This function runs GHC's frontend with recompilation
--- avoidance. Specifically, it checks if recompilation is needed,
--- and if it is, it parses and typechecks the input module.
--- It does not write out the results of typechecking (See
--- compileOne and hscIncrementalCompile).
-hscIncrementalFrontend :: Bool -- always do basic recompilation check?
- -> Maybe TcGblEnv
- -> Maybe Messager
- -> ModSummary
- -> SourceModified
- -> Maybe ModIface -- Old interface, if available
- -> (Int,Int) -- (i,n) = module i of n (for msgs)
- -> Hsc (Either ModIface (FrontendResult, Maybe Fingerprint))
-
-hscIncrementalFrontend
- always_do_basic_recompilation_check m_tc_result
- mHscMessage mod_summary source_modified mb_old_iface mod_index
- = do
- hsc_env <- getHscEnv
-
- let msg what = case mHscMessage of
- Just hscMessage -> hscMessage hsc_env mod_index what mod_summary
- Nothing -> return ()
-
- skip iface = do
- liftIO $ msg UpToDate
- return $ Left iface
-
- compile mb_old_hash reason = do
- liftIO $ msg reason
- (tc_result, _) <- hsc_typecheck False mod_summary Nothing
- return $ Right (FrontendTypecheck tc_result, mb_old_hash)
-
- stable = case source_modified of
- SourceUnmodifiedAndStable -> True
- _ -> False
-
- case m_tc_result of
- Just tc_result
- | not always_do_basic_recompilation_check ->
- return $ Right (FrontendTypecheck tc_result, Nothing)
- _ -> do
- (recomp_reqd, mb_checked_iface)
- <- {-# SCC "checkOldIface" #-}
- liftIO $ 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 . mi_final_exts) 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 (FrontendTypecheck tc_result, mb_old_hash)
-
---------------------------------------------------------------
--- Compilers
---------------------------------------------------------------
-
--- | Used by both OneShot and batch mode. Runs the pipeline HsSyn and Core parts
--- of the pipeline.
--- We return a interface if we already had an old one around and recompilation
--- was not needed. Otherwise it will be created during later passes when we
--- run the compilation pipeline.
-hscIncrementalCompile :: Bool
- -> Maybe TcGblEnv
- -> Maybe Messager
- -> HscEnv
- -> ModSummary
- -> SourceModified
- -> Maybe ModIface
- -> (Int,Int)
- -> IO (HscStatus, DynFlags)
-hscIncrementalCompile always_do_basic_recompilation_check m_tc_result
- mHscMessage hsc_env' mod_summary source_modified mb_old_iface mod_index
- = do
- dflags <- initializePlugins hsc_env' (hsc_dflags hsc_env')
- let hsc_env'' = hsc_env' { hsc_dflags = dflags }
-
- -- One-shot mode needs a knot-tying mutable variable for interface
- -- files. See TcRnTypes.TcGblEnv.tcg_type_env_var.
- -- See also Note [hsc_type_env_var hack]
- type_env_var <- newIORef emptyNameEnv
- let mod = ms_mod mod_summary
- hsc_env | isOneShot (ghcMode (hsc_dflags hsc_env''))
- = hsc_env'' { hsc_type_env_var = Just (mod, type_env_var) }
- | otherwise
- = hsc_env''
-
- -- NB: enter Hsc monad here so that we don't bail out early with
- -- -Werror on typechecker warnings; we also want to run the desugarer
- -- to get those warnings too. (But we'll always exit at that point
- -- because the desugarer runs ioMsgMaybe.)
- runHsc hsc_env $ do
- e <- hscIncrementalFrontend always_do_basic_recompilation_check m_tc_result mHscMessage
- mod_summary source_modified mb_old_iface mod_index
- case e of
- -- We didn't need to do any typechecking; the old interface
- -- file on disk was good enough.
- Left iface -> do
- -- Knot tying! See Note [Knot-tying typecheckIface]
- details <- liftIO . fixIO $ \details' -> do
- let hsc_env' =
- hsc_env {
- hsc_HPT = addToHpt (hsc_HPT hsc_env)
- (ms_mod_name mod_summary) (HomeModInfo iface details' Nothing)
- }
- -- NB: This result is actually not that useful
- -- in one-shot mode, since we're not going to do
- -- any further typechecking. It's much more useful
- -- in make mode, since this HMI will go into the HPT.
- details <- genModDetails hsc_env' iface
- return details
- return (HscUpToDate iface details, dflags)
- -- We finished type checking. (mb_old_hash is the hash of
- -- the interface that existed on disk; it's possible we had
- -- to retypecheck but the resulting interface is exactly
- -- the same.)
- Right (FrontendTypecheck tc_result, mb_old_hash) -> do
- status <- finish mod_summary tc_result mb_old_hash
- return (status, dflags)
-
--- Runs the post-typechecking frontend (desugar and simplify). We want to
--- generate most of the interface as late as possible. This gets us up-to-date
--- and good unfoldings and other info in the interface file.
---
--- We might create a interface right away, in which case we also return the
--- updated HomeModInfo. But we might also need to run the backend first. In the
--- later case Status will be HscRecomp and we return a function from ModIface ->
--- HomeModInfo.
---
--- HscRecomp in turn will carry the information required to compute a interface
--- when passed the result of the code generator. So all this can and is done at
--- the call site of the backend code gen if it is run.
-finish :: ModSummary
- -> TcGblEnv
- -> Maybe Fingerprint
- -> Hsc HscStatus
-finish summary tc_result mb_old_hash = do
- hsc_env <- getHscEnv
- let dflags = hsc_dflags hsc_env
- target = hscTarget dflags
- hsc_src = ms_hsc_src summary
-
- -- Desugar, if appropriate
- --
- -- We usually desugar even when we are not generating code, otherwise we
- -- would miss errors thrown by the desugaring (see #10600). The only
- -- exceptions are when the Module is Ghc.Prim or when it is not a
- -- HsSrcFile Module.
- mb_desugar <-
- if ms_mod summary /= gHC_PRIM && hsc_src == HsSrcFile
- then Just <$> hscDesugar' (ms_location summary) tc_result
- else pure Nothing
-
- -- Simplify, if appropriate, and (whether we simplified or not) generate an
- -- interface file.
- case mb_desugar of
- -- Just cause we desugared doesn't mean we are generating code, see above.
- Just desugared_guts | target /= HscNothing -> do
- plugins <- liftIO $ readIORef (tcg_th_coreplugins tc_result)
- simplified_guts <- hscSimplify' plugins desugared_guts
-
- (cg_guts, details) <- {-# SCC "CoreTidy" #-}
- liftIO $ tidyProgram hsc_env simplified_guts
-
- let !partial_iface =
- {-# SCC "HscMain.mkPartialIface" #-}
- -- This `force` saves 2M residency in test T10370
- -- See Note [Avoiding space leaks in toIface*] for details.
- force (mkPartialIface hsc_env details simplified_guts)
-
- return HscRecomp { hscs_guts = cg_guts,
- hscs_mod_location = ms_location summary,
- hscs_mod_details = details,
- hscs_partial_iface = partial_iface,
- hscs_old_iface_hash = mb_old_hash,
- hscs_iface_dflags = dflags }
-
- -- We are not generating code, so we can skip simplification
- -- and generate a simple interface.
- _ -> do
- (iface, mb_old_iface_hash, details) <- liftIO $
- hscSimpleIface hsc_env tc_result mb_old_hash
-
- liftIO $ hscMaybeWriteIface dflags iface mb_old_iface_hash (ms_location summary)
-
- return $ case (target, hsc_src) of
- (HscNothing, _) -> HscNotGeneratingCode iface details
- (_, HsBootFile) -> HscUpdateBoot iface details
- (_, HsigFile) -> HscUpdateSig iface details
- _ -> panic "finish"
-
-{-
-Note [Writing interface files]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We write interface files in HscMain.hs and DriverPipeline.hs using
-hscMaybeWriteIface, but only once per compilation (twice with dynamic-too).
-
-* If a compilation does NOT require (re)compilation of the hard code we call
- hscMaybeWriteIface inside HscMain:finish.
-* If we run in One Shot mode and target bytecode we write it in compileOne'
-* Otherwise we must be compiling to regular hard code and require recompilation.
- In this case we create the interface file inside RunPhase using the interface
- generator contained inside the HscRecomp status.
--}
-hscMaybeWriteIface :: DynFlags -> ModIface -> Maybe Fingerprint -> ModLocation -> IO ()
-hscMaybeWriteIface dflags iface old_iface location = do
- let force_write_interface = gopt Opt_WriteInterface dflags
- write_interface = case hscTarget dflags of
- HscNothing -> False
- HscInterpreted -> False
- _ -> True
- no_change = old_iface == Just (mi_iface_hash (mi_final_exts iface))
-
- when (write_interface || force_write_interface) $
- hscWriteIface dflags iface no_change location
-
---------------------------------------------------------------
--- NoRecomp handlers
---------------------------------------------------------------
-
--- NB: this must be knot-tied appropriately, see hscIncrementalCompile
-genModDetails :: HscEnv -> ModIface -> IO ModDetails
-genModDetails hsc_env old_iface
- = do
- new_details <- {-# SCC "tcRnIface" #-}
- initIfaceLoad hsc_env (typecheckIface old_iface)
- dumpIfaceStats hsc_env
- return new_details
-
---------------------------------------------------------------
--- Progress displayers.
---------------------------------------------------------------
-
-oneShotMsg :: HscEnv -> RecompileRequired -> IO ()
-oneShotMsg hsc_env recomp =
- case recomp of
- UpToDate ->
- compilationProgressMsg (hsc_dflags hsc_env) $
- "compilation IS NOT required"
- _ ->
- return ()
-
-batchMsg :: Messager
-batchMsg hsc_env mod_index recomp mod_summary =
- case recomp of
- MustCompile -> showMsg "Compiling " ""
- UpToDate
- | verbosity (hsc_dflags hsc_env) >= 2 -> showMsg "Skipping " ""
- | otherwise -> return ()
- RecompBecause reason -> showMsg "Compiling " (" [" ++ reason ++ "]")
- where
- dflags = hsc_dflags hsc_env
- showMsg msg reason =
- compilationProgressMsg dflags $
- (showModuleIndex mod_index ++
- msg ++ showModMsg dflags (hscTarget dflags)
- (recompileRequired recomp) mod_summary)
- ++ reason
-
---------------------------------------------------------------
--- Safe Haskell
---------------------------------------------------------------
-
--- Note [Safe Haskell Trust Check]
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- Safe Haskell checks that an import is trusted according to the following
--- rules for an import of module M that resides in Package P:
---
--- * If M is recorded as Safe and all its trust dependencies are OK
--- then M is considered safe.
--- * If M is recorded as Trustworthy and P is considered trusted and
--- all M's trust dependencies are OK then M is considered safe.
---
--- By trust dependencies we mean that the check is transitive. So if
--- a module M that is Safe relies on a module N that is trustworthy,
--- importing module M will first check (according to the second case)
--- that N is trusted before checking M is trusted.
---
--- This is a minimal description, so please refer to the user guide
--- for more details. The user guide is also considered the authoritative
--- source in this matter, not the comments or code.
-
-
--- Note [Safe Haskell Inference]
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- Safe Haskell does Safe inference on modules that don't have any specific
--- safe haskell mode flag. The basic approach to this is:
--- * When deciding if we need to do a Safe language check, treat
--- an unmarked module as having -XSafe mode specified.
--- * For checks, don't throw errors but return them to the caller.
--- * Caller checks if there are errors:
--- * For modules explicitly marked -XSafe, we throw the errors.
--- * For unmarked modules (inference mode), we drop the errors
--- and mark the module as being Unsafe.
---
--- It used to be that we only did safe inference on modules that had no Safe
--- Haskell flags, but now we perform safe inference on all modules as we want
--- to allow users to set the `-Wsafe`, `-Wunsafe` and
--- `-Wtrustworthy-safe` flags on Trustworthy and Unsafe modules so that a
--- user can ensure their assumptions are correct and see reasons for why a
--- module is safe or unsafe.
---
--- This is tricky as we must be careful when we should throw an error compared
--- to just warnings. For checking safe imports we manage it as two steps. First
--- we check any imports that are required to be safe, then we check all other
--- imports to see if we can infer them to be safe.
-
-
--- | Check that the safe imports of the module being compiled are valid.
--- If not we either issue a compilation error if the module is explicitly
--- using Safe Haskell, or mark the module as unsafe if we're in safe
--- inference mode.
-hscCheckSafeImports :: TcGblEnv -> Hsc TcGblEnv
-hscCheckSafeImports tcg_env = do
- dflags <- getDynFlags
- tcg_env' <- checkSafeImports tcg_env
- checkRULES dflags tcg_env'
-
- where
- checkRULES dflags tcg_env' = do
- case safeLanguageOn dflags of
- True -> do
- -- XSafe: we nuke user written RULES
- logWarnings $ warns dflags (tcg_rules tcg_env')
- return tcg_env' { tcg_rules = [] }
- False
- -- SafeInferred: user defined RULES, so not safe
- | safeInferOn dflags && not (null $ tcg_rules tcg_env')
- -> markUnsafeInfer tcg_env' $ warns dflags (tcg_rules tcg_env')
-
- -- Trustworthy OR SafeInferred: with no RULES
- | otherwise
- -> return tcg_env'
-
- warns dflags rules = listToBag $ map (warnRules dflags) rules
-
- warnRules :: DynFlags -> GenLocated SrcSpan (RuleDecl GhcTc) -> ErrMsg
- warnRules dflags (L loc (HsRule { rd_name = n })) =
- mkPlainWarnMsg dflags loc $
- text "Rule \"" <> ftext (snd $ unLoc n) <> text "\" ignored" $+$
- text "User defined rules are disabled under Safe Haskell"
- warnRules _ (L _ (XRuleDecl nec)) = noExtCon nec
-
--- | Validate that safe imported modules are actually safe. For modules in the
--- HomePackage (the package the module we are compiling in resides) this just
--- involves checking its trust type is 'Safe' or 'Trustworthy'. For modules
--- that reside in another package we also must check that the external package
--- is trusted. See the Note [Safe Haskell Trust Check] above for more
--- information.
---
--- The code for this is quite tricky as the whole algorithm is done in a few
--- distinct phases in different parts of the code base. See
--- GHC.Rename.Names.rnImportDecl for where package trust dependencies for a
--- module are collected and unioned. Specifically see the Note [Tracking Trust
--- Transitively] in GHC.Rename.Names and the Note [Trust Own Package] in
--- GHC.Rename.Names.
-checkSafeImports :: TcGblEnv -> Hsc TcGblEnv
-checkSafeImports tcg_env
- = do
- dflags <- getDynFlags
- imps <- mapM condense imports'
- let (safeImps, regImps) = partition (\(_,_,s) -> s) imps
-
- -- We want to use the warning state specifically for detecting if safe
- -- inference has failed, so store and clear any existing warnings.
- oldErrs <- getWarnings
- clearWarnings
-
- -- Check safe imports are correct
- safePkgs <- S.fromList <$> mapMaybeM checkSafe safeImps
- safeErrs <- getWarnings
- clearWarnings
-
- -- Check non-safe imports are correct if inferring safety
- -- See the Note [Safe Haskell Inference]
- (infErrs, infPkgs) <- case (safeInferOn dflags) of
- False -> return (emptyBag, S.empty)
- True -> do infPkgs <- S.fromList <$> mapMaybeM checkSafe regImps
- infErrs <- getWarnings
- clearWarnings
- return (infErrs, infPkgs)
-
- -- restore old errors
- logWarnings oldErrs
-
- case (isEmptyBag safeErrs) of
- -- Failed safe check
- False -> liftIO . throwIO . mkSrcErr $ safeErrs
-
- -- Passed safe check
- True -> do
- let infPassed = isEmptyBag infErrs
- tcg_env' <- case (not infPassed) of
- True -> markUnsafeInfer tcg_env infErrs
- False -> return tcg_env
- when (packageTrustOn dflags) $ checkPkgTrust pkgReqs
- let newTrust = pkgTrustReqs dflags safePkgs infPkgs infPassed
- return tcg_env' { tcg_imports = impInfo `plusImportAvails` newTrust }
-
- where
- impInfo = tcg_imports tcg_env -- ImportAvails
- imports = imp_mods impInfo -- ImportedMods
- imports1 = moduleEnvToList imports -- (Module, [ImportedBy])
- imports' = map (fmap importedByUser) imports1 -- (Module, [ImportedModsVal])
- pkgReqs = imp_trust_pkgs impInfo -- [UnitId]
-
- condense :: (Module, [ImportedModsVal]) -> Hsc (Module, SrcSpan, IsSafeImport)
- condense (_, []) = panic "HscMain.condense: Pattern match failure!"
- condense (m, x:xs) = do imv <- foldlM cond' x xs
- return (m, imv_span imv, imv_is_safe imv)
-
- -- ImportedModsVal = (ModuleName, Bool, SrcSpan, IsSafeImport)
- cond' :: ImportedModsVal -> ImportedModsVal -> Hsc ImportedModsVal
- cond' v1 v2
- | imv_is_safe v1 /= imv_is_safe v2
- = do
- dflags <- getDynFlags
- throwOneError $ mkPlainErrMsg dflags (imv_span v1)
- (text "Module" <+> ppr (imv_name v1) <+>
- (text $ "is imported both as a safe and unsafe import!"))
- | otherwise
- = return v1
-
- -- easier interface to work with
- checkSafe :: (Module, SrcSpan, a) -> Hsc (Maybe InstalledUnitId)
- checkSafe (m, l, _) = fst `fmap` hscCheckSafe' m l
-
- -- what pkg's to add to our trust requirements
- pkgTrustReqs :: DynFlags -> Set InstalledUnitId -> Set InstalledUnitId ->
- Bool -> ImportAvails
- pkgTrustReqs dflags req inf infPassed | safeInferOn dflags
- && not (safeHaskellModeEnabled dflags) && infPassed
- = emptyImportAvails {
- imp_trust_pkgs = req `S.union` inf
- }
- pkgTrustReqs dflags _ _ _ | safeHaskell dflags == Sf_Unsafe
- = emptyImportAvails
- pkgTrustReqs _ req _ _ = emptyImportAvails { imp_trust_pkgs = req }
-
--- | Check that a module is safe to import.
---
--- We return True to indicate the import is safe and False otherwise
--- although in the False case an exception may be thrown first.
-hscCheckSafe :: HscEnv -> Module -> SrcSpan -> IO Bool
-hscCheckSafe hsc_env m l = runHsc hsc_env $ do
- dflags <- getDynFlags
- pkgs <- snd `fmap` hscCheckSafe' m l
- when (packageTrustOn dflags) $ checkPkgTrust pkgs
- errs <- getWarnings
- return $ isEmptyBag errs
-
--- | Return if a module is trusted and the pkgs it depends on to be trusted.
-hscGetSafe :: HscEnv -> Module -> SrcSpan -> IO (Bool, Set InstalledUnitId)
-hscGetSafe hsc_env m l = runHsc hsc_env $ do
- (self, pkgs) <- hscCheckSafe' m l
- good <- isEmptyBag `fmap` getWarnings
- clearWarnings -- don't want them printed...
- let pkgs' | Just p <- self = S.insert p pkgs
- | otherwise = pkgs
- return (good, pkgs')
-
--- | Is a module trusted? If not, throw or log errors depending on the type.
--- Return (regardless of trusted or not) if the trust type requires the modules
--- own package be trusted and a list of other packages required to be trusted
--- (these later ones haven't been checked) but the own package trust has been.
-hscCheckSafe' :: Module -> SrcSpan
- -> Hsc (Maybe InstalledUnitId, Set InstalledUnitId)
-hscCheckSafe' m l = do
- dflags <- getDynFlags
- (tw, pkgs) <- isModSafe m l
- case tw of
- False -> return (Nothing, pkgs)
- True | isHomePkg dflags m -> return (Nothing, pkgs)
- -- TODO: do we also have to check the trust of the instantiation?
- -- Not necessary if that is reflected in dependencies
- | otherwise -> return (Just $ toInstalledUnitId (moduleUnitId m), pkgs)
- where
- isModSafe :: Module -> SrcSpan -> Hsc (Bool, Set InstalledUnitId)
- isModSafe m l = do
- dflags <- getDynFlags
- iface <- lookup' m
- case iface of
- -- can't load iface to check trust!
- Nothing -> throwOneError $ mkPlainErrMsg dflags l
- $ text "Can't load the interface file for" <+> ppr m
- <> text ", to check that it can be safely imported"
-
- -- got iface, check trust
- Just iface' ->
- let trust = getSafeMode $ mi_trust iface'
- trust_own_pkg = mi_trust_pkg iface'
- -- check module is trusted
- safeM = trust `elem` [Sf_Safe, Sf_SafeInferred, Sf_Trustworthy]
- -- check package is trusted
- safeP = packageTrusted dflags trust trust_own_pkg m
- -- pkg trust reqs
- pkgRs = S.fromList . map fst $ filter snd $ dep_pkgs $ mi_deps iface'
- -- warn if Safe module imports Safe-Inferred module.
- warns = if wopt Opt_WarnInferredSafeImports dflags
- && safeLanguageOn dflags
- && trust == Sf_SafeInferred
- then inferredImportWarn
- else emptyBag
- -- General errors we throw but Safe errors we log
- errs = case (safeM, safeP) of
- (True, True ) -> emptyBag
- (True, False) -> pkgTrustErr
- (False, _ ) -> modTrustErr
- in do
- logWarnings warns
- logWarnings errs
- return (trust == Sf_Trustworthy, pkgRs)
-
- where
- inferredImportWarn = unitBag
- $ makeIntoWarning (Reason Opt_WarnInferredSafeImports)
- $ mkErrMsg dflags l (pkgQual dflags)
- $ sep
- [ text "Importing Safe-Inferred module "
- <> ppr (moduleName m)
- <> text " from explicitly Safe module"
- ]
- pkgTrustErr = unitBag $ mkErrMsg dflags l (pkgQual dflags) $
- sep [ ppr (moduleName m)
- <> text ": Can't be safely imported!"
- , text "The package (" <> ppr (moduleUnitId m)
- <> text ") the module resides in isn't trusted."
- ]
- modTrustErr = unitBag $ mkErrMsg dflags l (pkgQual dflags) $
- sep [ ppr (moduleName m)
- <> text ": Can't be safely imported!"
- , text "The module itself isn't safe." ]
-
- -- | Check the package a module resides in is trusted. Safe compiled
- -- modules are trusted without requiring that their package is trusted. For
- -- trustworthy modules, modules in the home package are trusted but
- -- otherwise we check the package trust flag.
- packageTrusted :: DynFlags -> SafeHaskellMode -> Bool -> Module -> Bool
- packageTrusted _ Sf_None _ _ = False -- shouldn't hit these cases
- packageTrusted _ Sf_Ignore _ _ = False -- shouldn't hit these cases
- packageTrusted _ Sf_Unsafe _ _ = False -- prefer for completeness.
- packageTrusted dflags _ _ _
- | not (packageTrustOn dflags) = True
- packageTrusted _ Sf_Safe False _ = True
- packageTrusted _ Sf_SafeInferred False _ = True
- packageTrusted dflags _ _ m
- | isHomePkg dflags m = True
- | otherwise = trusted $ getPackageDetails dflags (moduleUnitId m)
-
- lookup' :: Module -> Hsc (Maybe ModIface)
- lookup' m = do
- hsc_env <- getHscEnv
- hsc_eps <- liftIO $ hscEPS hsc_env
- let pkgIfaceT = eps_PIT hsc_eps
- homePkgT = hsc_HPT hsc_env
- iface = lookupIfaceByModule homePkgT pkgIfaceT m
- -- the 'lookupIfaceByModule' method will always fail when calling from GHCi
- -- as the compiler hasn't filled in the various module tables
- -- so we need to call 'getModuleInterface' to load from disk
- iface' <- case iface of
- Just _ -> return iface
- Nothing -> snd `fmap` (liftIO $ getModuleInterface hsc_env m)
- return iface'
-
-
- isHomePkg :: DynFlags -> Module -> Bool
- isHomePkg dflags m
- | thisPackage dflags == moduleUnitId m = True
- | otherwise = False
-
--- | Check the list of packages are trusted.
-checkPkgTrust :: Set InstalledUnitId -> Hsc ()
-checkPkgTrust pkgs = do
- dflags <- getDynFlags
- let errors = S.foldr go [] pkgs
- go pkg acc
- | trusted $ getInstalledPackageDetails dflags pkg
- = acc
- | otherwise
- = (:acc) $ mkErrMsg dflags noSrcSpan (pkgQual dflags)
- $ text "The package (" <> ppr pkg <> text ") is required" <>
- text " to be trusted but it isn't!"
- case errors of
- [] -> return ()
- _ -> (liftIO . throwIO . mkSrcErr . listToBag) errors
-
--- | Set module to unsafe and (potentially) wipe trust information.
---
--- Make sure to call this method to set a module to inferred unsafe, it should
--- be a central and single failure method. We only wipe the trust information
--- when we aren't in a specific Safe Haskell mode.
---
--- While we only use this for recording that a module was inferred unsafe, we
--- may call it on modules using Trustworthy or Unsafe flags so as to allow
--- warning flags for safety to function correctly. See Note [Safe Haskell
--- Inference].
-markUnsafeInfer :: TcGblEnv -> WarningMessages -> Hsc TcGblEnv
-markUnsafeInfer tcg_env whyUnsafe = do
- dflags <- getDynFlags
-
- when (wopt Opt_WarnUnsafe dflags)
- (logWarnings $ unitBag $ makeIntoWarning (Reason Opt_WarnUnsafe) $
- mkPlainWarnMsg dflags (warnUnsafeOnLoc dflags) (whyUnsafe' dflags))
-
- liftIO $ writeIORef (tcg_safeInfer tcg_env) (False, whyUnsafe)
- -- NOTE: Only wipe trust when not in an explicitly safe haskell mode. Other
- -- times inference may be on but we are in Trustworthy mode -- so we want
- -- to record safe-inference failed but not wipe the trust dependencies.
- case not (safeHaskellModeEnabled dflags) of
- True -> return $ tcg_env { tcg_imports = wiped_trust }
- False -> return tcg_env
-
- where
- wiped_trust = (tcg_imports tcg_env) { imp_trust_pkgs = S.empty }
- pprMod = ppr $ moduleName $ tcg_mod tcg_env
- whyUnsafe' df = vcat [ quotes pprMod <+> text "has been inferred as unsafe!"
- , text "Reason:"
- , nest 4 $ (vcat $ badFlags df) $+$
- (vcat $ pprErrMsgBagWithLoc whyUnsafe) $+$
- (vcat $ badInsts $ tcg_insts tcg_env)
- ]
- badFlags df = concatMap (badFlag df) unsafeFlagsForInfer
- badFlag df (str,loc,on,_)
- | on df = [mkLocMessage SevOutput (loc df) $
- text str <+> text "is not allowed in Safe Haskell"]
- | otherwise = []
- badInsts insts = concatMap badInst insts
-
- checkOverlap (NoOverlap _) = False
- checkOverlap _ = True
-
- badInst ins | checkOverlap (overlapMode (is_flag ins))
- = [mkLocMessage SevOutput (nameSrcSpan $ getName $ is_dfun ins) $
- ppr (overlapMode $ is_flag ins) <+>
- text "overlap mode isn't allowed in Safe Haskell"]
- | otherwise = []
-
-
--- | Figure out the final correct safe haskell mode
-hscGetSafeMode :: TcGblEnv -> Hsc SafeHaskellMode
-hscGetSafeMode tcg_env = do
- dflags <- getDynFlags
- liftIO $ finalSafeMode dflags tcg_env
-
---------------------------------------------------------------
--- Simplifiers
---------------------------------------------------------------
-
-hscSimplify :: HscEnv -> [String] -> ModGuts -> IO ModGuts
-hscSimplify hsc_env plugins modguts =
- runHsc hsc_env $ hscSimplify' plugins modguts
-
-hscSimplify' :: [String] -> ModGuts -> Hsc ModGuts
-hscSimplify' plugins ds_result = do
- hsc_env <- getHscEnv
- let hsc_env_with_plugins = hsc_env
- { hsc_dflags = foldr addPluginModuleName (hsc_dflags hsc_env) plugins
- }
- {-# SCC "Core2Core" #-}
- liftIO $ core2core hsc_env_with_plugins ds_result
-
---------------------------------------------------------------
--- Interface generators
---------------------------------------------------------------
-
--- | Generate a striped down interface file, e.g. for boot files or when ghci
--- generates interface files. See Note [simpleTidyPgm - mkBootModDetailsTc]
-hscSimpleIface :: HscEnv
- -> TcGblEnv
- -> Maybe Fingerprint
- -> IO (ModIface, Maybe Fingerprint, ModDetails)
-hscSimpleIface hsc_env tc_result mb_old_iface
- = runHsc hsc_env $ hscSimpleIface' tc_result mb_old_iface
-
-hscSimpleIface' :: TcGblEnv
- -> Maybe Fingerprint
- -> Hsc (ModIface, Maybe Fingerprint, ModDetails)
-hscSimpleIface' tc_result mb_old_iface = do
- hsc_env <- getHscEnv
- details <- liftIO $ mkBootModDetailsTc hsc_env tc_result
- safe_mode <- hscGetSafeMode tc_result
- new_iface
- <- {-# SCC "MkFinalIface" #-}
- liftIO $
- mkIfaceTc hsc_env safe_mode details tc_result
- -- And the answer is ...
- liftIO $ dumpIfaceStats hsc_env
- return (new_iface, mb_old_iface, details)
-
---------------------------------------------------------------
--- BackEnd combinators
---------------------------------------------------------------
-{-
-Note [Interface filename extensions]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-ModLocation only contains the base names, however when generating dynamic files
-the actual extension might differ from the default.
-
-So we only load the base name from ModLocation and replace the actual extension
-according to the information in DynFlags.
-
-If we generate a interface file right after running the core pipeline we will
-have set -dynamic-too and potentially generate both interface files at the same
-time.
-
-If we generate a interface file after running the backend then dynamic-too won't
-be set, however then the extension will be contained in the dynflags instead so
-things still work out fine.
--}
-
-hscWriteIface :: DynFlags -> ModIface -> Bool -> ModLocation -> IO ()
-hscWriteIface dflags iface no_change mod_location = do
- -- mod_location only contains the base name, so we rebuild the
- -- correct file extension from the dynflags.
- let ifaceBaseFile = ml_hi_file mod_location
- unless no_change $
- let ifaceFile = buildIfName ifaceBaseFile (hiSuf dflags)
- in {-# SCC "writeIface" #-}
- writeIfaceFile dflags ifaceFile iface
- whenGeneratingDynamicToo dflags $ do
- -- TODO: We should do a no_change check for the dynamic
- -- interface file too
- -- When we generate iface files after core
- let dynDflags = dynamicTooMkDynamicDynFlags dflags
- -- dynDflags will have set hiSuf correctly.
- dynIfaceFile = buildIfName ifaceBaseFile (hiSuf dynDflags)
-
- writeIfaceFile dynDflags dynIfaceFile iface
- where
- buildIfName :: String -> String -> String
- buildIfName baseName suffix
- | Just name <- outputHi dflags
- = name
- | otherwise
- = let with_hi = replaceExtension baseName suffix
- in addBootSuffix_maybe (mi_boot iface) with_hi
-
--- | Compile to hard-code.
-hscGenHardCode :: HscEnv -> CgGuts -> ModLocation -> FilePath
- -> IO (FilePath, Maybe FilePath, [(ForeignSrcLang, FilePath)], NameSet)
- -- ^ @Just f@ <=> _stub.c is f
-hscGenHardCode hsc_env cgguts location output_filename = 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,
- cg_binds = core_binds,
- cg_tycons = tycons,
- cg_foreign = foreign_stubs0,
- cg_foreign_files = foreign_files,
- cg_dep_pkgs = dependencies,
- cg_hpc_info = hpc_info } = cgguts
- dflags = hsc_dflags hsc_env
- data_tycons = filter isDataTyCon tycons
- -- cg_tycons includes newtypes, for the benefit of External Core,
- -- but we don't generate any code for newtypes
-
- -------------------
- -- PREPARE FOR CODE GENERATION
- -- Do saturation and convert to A-normal form
- (prepd_binds, local_ccs) <- {-# SCC "CorePrep" #-}
- corePrepPgm hsc_env this_mod location
- core_binds data_tycons
- ----------------- Convert to STG ------------------
- (stg_binds, (caf_ccs, caf_cc_stacks))
- <- {-# SCC "CoreToStg" #-}
- myCoreToStg dflags this_mod prepd_binds
-
- let cost_centre_info =
- (S.toList local_ccs ++ caf_ccs, caf_cc_stacks)
- prof_init = profilingInitCode this_mod cost_centre_info
- foreign_stubs = foreign_stubs0 `appendStubC` prof_init
-
- ------------------ Code generation ------------------
-
- -- The back-end is streamed: each top-level function goes
- -- from Stg all the way to asm before dealing with the next
- -- top-level function, so showPass isn't very useful here.
- -- Hence we have one showPass for the whole backend, the
- -- next showPass after this will be "Assembler".
- withTiming dflags
- (text "CodeGen"<+>brackets (ppr this_mod))
- (const ()) $ do
- cmms <- {-# SCC "StgToCmm" #-}
- doCodeGen hsc_env this_mod data_tycons
- cost_centre_info
- stg_binds hpc_info
-
- ------------------ Code output -----------------------
- rawcmms0 <- {-# SCC "cmmToRawCmm" #-}
- lookupHook cmmToRawCmmHook
- (\dflg _ -> cmmToRawCmm dflg) dflags dflags (Just this_mod) cmms
-
- let dump a = do
- unless (null a) $
- dumpIfSet_dyn dflags Opt_D_dump_cmm_raw "Raw Cmm" FormatCMM (ppr a)
- return a
- rawcmms1 = Stream.mapM dump rawcmms0
-
- (output_filename, (_stub_h_exists, stub_c_exists), foreign_fps, caf_infos)
- <- {-# SCC "codeOutput" #-}
- codeOutput dflags this_mod output_filename location
- foreign_stubs foreign_files dependencies rawcmms1
- return (output_filename, stub_c_exists, foreign_fps, caf_infos)
-
-
-hscInteractive :: HscEnv
- -> CgGuts
- -> ModLocation
- -> IO (Maybe FilePath, CompiledByteCode, [SptEntry])
-hscInteractive hsc_env cgguts location = 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,
- cg_binds = core_binds,
- cg_tycons = tycons,
- cg_foreign = foreign_stubs,
- cg_modBreaks = mod_breaks,
- cg_spt_entries = spt_entries } = cgguts
-
- data_tycons = filter isDataTyCon tycons
- -- cg_tycons includes newtypes, for the benefit of External Core,
- -- but we don't generate any code for newtypes
-
- -------------------
- -- PREPARE FOR CODE GENERATION
- -- Do saturation and convert to A-normal form
- (prepd_binds, _) <- {-# SCC "CorePrep" #-}
- corePrepPgm hsc_env this_mod location core_binds data_tycons
- ----------------- Generate byte code ------------------
- comp_bc <- byteCodeGen hsc_env this_mod prepd_binds data_tycons mod_breaks
- ------------------ Create f-x-dynamic C-side stuff -----
- (_istub_h_exists, istub_c_exists)
- <- outputForeignStubs dflags this_mod location foreign_stubs
- return (istub_c_exists, comp_bc, spt_entries)
-
-------------------------------
-
-hscCompileCmmFile :: HscEnv -> FilePath -> FilePath -> IO ()
-hscCompileCmmFile hsc_env filename output_filename = runHsc hsc_env $ do
- let dflags = hsc_dflags hsc_env
- cmm <- ioMsgMaybe $ parseCmmFile dflags filename
- liftIO $ do
- dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose_by_proc "Parsed Cmm" FormatCMM (ppr cmm)
- let -- Make up a module name to give the NCG. We can't pass bottom here
- -- lest we reproduce #11784.
- mod_name = mkModuleName $ "Cmm$" ++ FilePath.takeFileName filename
- cmm_mod = mkModule (thisPackage dflags) mod_name
-
- -- Compile decls in Cmm files one decl at a time, to avoid re-ordering
- -- them in SRT analysis.
- --
- -- Re-ordering here causes breakage when booting with C backend because
- -- in C we must declare before use, but SRT algorithm is free to
- -- re-order [A, B] (B refers to A) when A is not CAFFY and return [B, A]
- cmmgroup <-
- concatMapM (\cmm -> snd <$> cmmPipeline hsc_env (emptySRT cmm_mod) [cmm]) cmm
-
- unless (null cmmgroup) $
- dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm"
- FormatCMM (ppr cmmgroup)
- rawCmms <- lookupHook cmmToRawCmmHook
- (\dflgs _ -> cmmToRawCmm dflgs) dflags dflags Nothing (Stream.yield cmmgroup)
- _ <- codeOutput dflags cmm_mod output_filename no_loc NoStubs [] []
- rawCmms
- return ()
- where
- no_loc = ModLocation{ ml_hs_file = Just filename,
- ml_hi_file = panic "hscCompileCmmFile: no hi file",
- ml_obj_file = panic "hscCompileCmmFile: no obj file",
- ml_hie_file = panic "hscCompileCmmFile: no hie file"}
-
--------------------- Stuff for new code gen ---------------------
-
-{-
-Note [Forcing of stg_binds]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The two last steps in the STG pipeline are:
-
-* Sorting the bindings in dependency order.
-* Annotating them with free variables.
-
-We want to make sure we do not keep references to unannotated STG bindings
-alive, nor references to bindings which have already been compiled to Cmm.
-
-We explicitly force the bindings to avoid this.
-
-This reduces residency towards the end of the CodeGen phase significantly
-(5-10%).
--}
-
-doCodeGen :: HscEnv -> Module -> [TyCon]
- -> CollectedCCs
- -> [StgTopBinding]
- -> HpcInfo
- -> IO (Stream IO CmmGroupSRTs NameSet)
- -- Note we produce a 'Stream' of CmmGroups, so that the
- -- backend can be run incrementally. Otherwise it generates all
- -- the C-- up front, which has a significant space cost.
-doCodeGen hsc_env this_mod data_tycons
- cost_centre_info stg_binds hpc_info = do
- let dflags = hsc_dflags hsc_env
-
- let stg_binds_w_fvs = annTopBindingsFreeVars stg_binds
-
- dumpIfSet_dyn dflags Opt_D_dump_stg_final "Final STG:" FormatSTG (pprGenStgTopBindings stg_binds_w_fvs)
-
- let cmm_stream :: Stream IO CmmGroup ()
- -- See Note [Forcing of stg_binds]
- cmm_stream = stg_binds_w_fvs `seqList` {-# SCC "StgToCmm" #-}
- lookupHook stgToCmmHook StgToCmm.codeGen dflags dflags this_mod data_tycons
- cost_centre_info stg_binds_w_fvs hpc_info
-
- -- codegen consumes a stream of CmmGroup, and produces a new
- -- stream of CmmGroup (not necessarily synchronised: one
- -- CmmGroup on input may produce many CmmGroups on output due
- -- to proc-point splitting).
-
- let dump1 a = do
- unless (null a) $
- dumpIfSet_dyn dflags Opt_D_dump_cmm_from_stg
- "Cmm produced by codegen" FormatCMM (ppr a)
- return a
-
- ppr_stream1 = Stream.mapM dump1 cmm_stream
-
- pipeline_stream =
- {-# SCC "cmmPipeline" #-}
- Stream.mapAccumL (cmmPipeline hsc_env) (emptySRT this_mod) ppr_stream1
- <&> (srtMapNonCAFs . moduleSRTMap)
-
- dump2 a = do
- unless (null a) $
- dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm" FormatCMM (ppr a)
- return a
-
- return (Stream.mapM dump2 pipeline_stream)
-
-myCoreToStg :: DynFlags -> Module -> CoreProgram
- -> IO ( [StgTopBinding] -- output program
- , CollectedCCs ) -- CAF cost centre info (declared and used)
-myCoreToStg dflags this_mod prepd_binds = do
- let (stg_binds, cost_centre_info)
- = {-# SCC "Core2Stg" #-}
- coreToStg dflags this_mod prepd_binds
-
- stg_binds2
- <- {-# SCC "Stg2Stg" #-}
- stg2stg dflags this_mod stg_binds
-
- return (stg_binds2, cost_centre_info)
-
-
-{- **********************************************************************
-%* *
-\subsection{Compiling a do-statement}
-%* *
-%********************************************************************* -}
-
-{-
-When the UnlinkedBCOExpr is linked you get an HValue of type *IO [HValue]* When
-you run it you get a list of HValues that should be the same length as the list
-of names; add them to the ClosureEnv.
-
-A naked expression returns a singleton Name [it]. The stmt is lifted into the
-IO monad as explained in Note [Interactively-bound Ids in GHCi] in HscTypes
--}
-
--- | Compile a stmt all the way to an HValue, but don't run it
---
--- We return Nothing to indicate an empty statement (or comment only), not a
--- parse error.
-hscStmt :: HscEnv -> String -> IO (Maybe ([Id], ForeignHValue, FixityEnv))
-hscStmt hsc_env stmt = hscStmtWithLocation hsc_env stmt "<interactive>" 1
-
--- | Compile a stmt all the way to an HValue, but don't run it
---
--- We return Nothing to indicate an empty statement (or comment only), not a
--- parse error.
-hscStmtWithLocation :: HscEnv
- -> String -- ^ The statement
- -> String -- ^ The source
- -> Int -- ^ Starting line
- -> IO ( Maybe ([Id]
- , ForeignHValue {- IO [HValue] -}
- , FixityEnv))
-hscStmtWithLocation hsc_env0 stmt source linenumber =
- runInteractiveHsc hsc_env0 $ do
- maybe_stmt <- hscParseStmtWithLocation source linenumber stmt
- case maybe_stmt of
- Nothing -> return Nothing
-
- Just parsed_stmt -> do
- hsc_env <- getHscEnv
- liftIO $ hscParsedStmt hsc_env parsed_stmt
-
-hscParsedStmt :: HscEnv
- -> GhciLStmt GhcPs -- ^ The parsed statement
- -> IO ( Maybe ([Id]
- , ForeignHValue {- IO [HValue] -}
- , FixityEnv))
-hscParsedStmt hsc_env stmt = runInteractiveHsc hsc_env $ do
- -- Rename and typecheck it
- (ids, tc_expr, fix_env) <- ioMsgMaybe $ tcRnStmt hsc_env stmt
-
- -- Desugar it
- ds_expr <- ioMsgMaybe $ deSugarExpr hsc_env tc_expr
- liftIO (lintInteractiveExpr "desugar expression" hsc_env ds_expr)
- handleWarnings
-
- -- Then code-gen, and link it
- -- It's important NOT to have package 'interactive' as thisUnitId
- -- for linking, else we try to link 'main' and can't find it.
- -- Whereas the linker already knows to ignore 'interactive'
- let src_span = srcLocSpan interactiveSrcLoc
- hval <- liftIO $ hscCompileCoreExpr hsc_env src_span ds_expr
-
- return $ Just (ids, hval, fix_env)
-
--- | Compile a decls
-hscDecls :: HscEnv
- -> String -- ^ The statement
- -> IO ([TyThing], InteractiveContext)
-hscDecls hsc_env str = hscDeclsWithLocation hsc_env str "<interactive>" 1
-
-hscParseDeclsWithLocation :: HscEnv -> String -> Int -> String -> IO [LHsDecl GhcPs]
-hscParseDeclsWithLocation hsc_env source line_num str = do
- L _ (HsModule{ hsmodDecls = decls }) <-
- runInteractiveHsc hsc_env $
- hscParseThingWithLocation source line_num parseModule str
- return decls
-
--- | Compile a decls
-hscDeclsWithLocation :: HscEnv
- -> String -- ^ The statement
- -> String -- ^ The source
- -> Int -- ^ Starting line
- -> IO ([TyThing], InteractiveContext)
-hscDeclsWithLocation hsc_env str source linenumber = do
- L _ (HsModule{ hsmodDecls = decls }) <-
- runInteractiveHsc hsc_env $
- hscParseThingWithLocation source linenumber parseModule str
- hscParsedDecls hsc_env decls
-
-hscParsedDecls :: HscEnv -> [LHsDecl GhcPs] -> IO ([TyThing], InteractiveContext)
-hscParsedDecls hsc_env decls = runInteractiveHsc hsc_env $ do
- {- Rename and typecheck it -}
- hsc_env <- getHscEnv
- tc_gblenv <- ioMsgMaybe $ tcRnDeclsi hsc_env decls
-
- {- Grab the new instances -}
- -- We grab the whole environment because of the overlapping that may have
- -- been done. See the notes at the definition of InteractiveContext
- -- (ic_instances) for more details.
- let defaults = tcg_default tc_gblenv
-
- {- Desugar it -}
- -- We use a basically null location for iNTERACTIVE
- let iNTERACTIVELoc = ModLocation{ ml_hs_file = Nothing,
- ml_hi_file = panic "hsDeclsWithLocation:ml_hi_file",
- ml_obj_file = panic "hsDeclsWithLocation:ml_obj_file",
- ml_hie_file = panic "hsDeclsWithLocation:ml_hie_file" }
- ds_result <- hscDesugar' iNTERACTIVELoc tc_gblenv
-
- {- Simplify -}
- simpl_mg <- liftIO $ do
- plugins <- readIORef (tcg_th_coreplugins tc_gblenv)
- hscSimplify hsc_env plugins ds_result
-
- {- Tidy -}
- (tidy_cg, mod_details) <- liftIO $ tidyProgram hsc_env simpl_mg
-
- let !CgGuts{ cg_module = this_mod,
- cg_binds = core_binds,
- cg_tycons = tycons,
- cg_modBreaks = mod_breaks } = tidy_cg
-
- !ModDetails { md_insts = cls_insts
- , md_fam_insts = fam_insts } = mod_details
- -- Get the *tidied* cls_insts and fam_insts
-
- data_tycons = filter isDataTyCon tycons
-
- {- Prepare For Code Generation -}
- -- Do saturation and convert to A-normal form
- (prepd_binds, _) <- {-# SCC "CorePrep" #-}
- liftIO $ corePrepPgm hsc_env this_mod iNTERACTIVELoc core_binds data_tycons
-
- {- Generate byte code -}
- cbc <- liftIO $ byteCodeGen hsc_env this_mod
- prepd_binds data_tycons mod_breaks
-
- let src_span = srcLocSpan interactiveSrcLoc
- liftIO $ linkDecls hsc_env src_span cbc
-
- {- Load static pointer table entries -}
- liftIO $ hscAddSptEntries hsc_env (cg_spt_entries tidy_cg)
-
- let tcs = filterOut isImplicitTyCon (mg_tcs simpl_mg)
- patsyns = mg_patsyns simpl_mg
-
- ext_ids = [ id | id <- bindersOfBinds core_binds
- , isExternalName (idName id)
- , not (isDFunId id || isImplicitId id) ]
- -- We only need to keep around the external bindings
- -- (as decided by GHC.Iface.Tidy), since those are the only ones
- -- that might later be looked up by name. But we can exclude
- -- - DFunIds, which are in 'cls_insts' (see Note [ic_tythings] in HscTypes
- -- - Implicit Ids, which are implicit in tcs
- -- c.f. TcRnDriver.runTcInteractive, which reconstructs the TypeEnv
-
- new_tythings = map AnId ext_ids ++ map ATyCon tcs ++ map (AConLike . PatSynCon) patsyns
- ictxt = hsc_IC hsc_env
- -- See Note [Fixity declarations in GHCi]
- fix_env = tcg_fix_env tc_gblenv
- new_ictxt = extendInteractiveContext ictxt new_tythings cls_insts
- fam_insts defaults fix_env
- return (new_tythings, new_ictxt)
-
--- | Load the given static-pointer table entries into the interpreter.
--- See Note [Grand plan for static forms] in StaticPtrTable.
-hscAddSptEntries :: HscEnv -> [SptEntry] -> IO ()
-hscAddSptEntries hsc_env entries = do
- let add_spt_entry :: SptEntry -> IO ()
- add_spt_entry (SptEntry i fpr) = do
- val <- getHValue hsc_env (idName i)
- addSptEntry hsc_env fpr val
- mapM_ add_spt_entry entries
-
-{-
- Note [Fixity declarations in GHCi]
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- To support fixity declarations on types defined within GHCi (as requested
- in #10018) we record the fixity environment in InteractiveContext.
- When we want to evaluate something TcRnDriver.runTcInteractive pulls out this
- fixity environment and uses it to initialize the global typechecker environment.
- After the typechecker has finished its business, an updated fixity environment
- (reflecting whatever fixity declarations were present in the statements we
- passed it) will be returned from hscParsedStmt. This is passed to
- updateFixityEnv, which will stuff it back into InteractiveContext, to be
- used in evaluating the next statement.
-
--}
-
-hscImport :: HscEnv -> String -> IO (ImportDecl GhcPs)
-hscImport hsc_env str = runInteractiveHsc hsc_env $ do
- (L _ (HsModule{hsmodImports=is})) <-
- hscParseThing parseModule str
- case is of
- [L _ i] -> return i
- _ -> liftIO $ throwOneError $
- mkPlainErrMsg (hsc_dflags hsc_env) noSrcSpan $
- text "parse error in import declaration"
-
--- | Typecheck an expression (but don't run it)
-hscTcExpr :: HscEnv
- -> TcRnExprMode
- -> String -- ^ The expression
- -> IO Type
-hscTcExpr hsc_env0 mode expr = runInteractiveHsc hsc_env0 $ do
- hsc_env <- getHscEnv
- parsed_expr <- hscParseExpr expr
- ioMsgMaybe $ tcRnExpr hsc_env mode parsed_expr
-
--- | Find the kind of a type, after generalisation
-hscKcType
- :: HscEnv
- -> Bool -- ^ Normalise the type
- -> String -- ^ The type as a string
- -> IO (Type, Kind) -- ^ Resulting type (possibly normalised) and kind
-hscKcType hsc_env0 normalise str = runInteractiveHsc hsc_env0 $ do
- hsc_env <- getHscEnv
- ty <- hscParseType str
- ioMsgMaybe $ tcRnType hsc_env DefaultFlexi normalise ty
-
-hscParseExpr :: String -> Hsc (LHsExpr GhcPs)
-hscParseExpr expr = do
- hsc_env <- getHscEnv
- maybe_stmt <- hscParseStmt expr
- case maybe_stmt of
- Just (L _ (BodyStmt _ expr _ _)) -> return expr
- _ -> throwOneError $ mkPlainErrMsg (hsc_dflags hsc_env) noSrcSpan
- (text "not an expression:" <+> quotes (text expr))
-
-hscParseStmt :: String -> Hsc (Maybe (GhciLStmt GhcPs))
-hscParseStmt = hscParseThing parseStmt
-
-hscParseStmtWithLocation :: String -> Int -> String
- -> Hsc (Maybe (GhciLStmt GhcPs))
-hscParseStmtWithLocation source linenumber stmt =
- hscParseThingWithLocation source linenumber parseStmt stmt
-
-hscParseType :: String -> Hsc (LHsType GhcPs)
-hscParseType = hscParseThing parseType
-
-hscParseIdentifier :: HscEnv -> String -> IO (Located RdrName)
-hscParseIdentifier hsc_env str =
- runInteractiveHsc hsc_env $ hscParseThing parseIdentifier str
-
-hscParseThing :: (Outputable thing, Data thing)
- => Lexer.P thing -> String -> Hsc thing
-hscParseThing = hscParseThingWithLocation "<interactive>" 1
-
-hscParseThingWithLocation :: (Outputable thing, Data thing) => String -> Int
- -> Lexer.P thing -> String -> Hsc thing
-hscParseThingWithLocation source linenumber parser str
- = withTimingD
- (text "Parser [source]")
- (const ()) $ {-# SCC "Parser" #-} do
- dflags <- getDynFlags
-
- let buf = stringToStringBuffer str
- loc = mkRealSrcLoc (fsLit source) linenumber 1
-
- case unP parser (mkPState dflags buf loc) of
- PFailed pst -> do
- handleWarningsThrowErrors (getMessages pst dflags)
-
- POk pst thing -> do
- logWarningsReportErrors (getMessages pst dflags)
- liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser"
- FormatHaskell (ppr thing)
- liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST"
- FormatHaskell (showAstData NoBlankSrcSpan thing)
- return thing
-
-
-{- **********************************************************************
-%* *
- Desugar, simplify, convert to bytecode, and link an expression
-%* *
-%********************************************************************* -}
-
-hscCompileCoreExpr :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue
-hscCompileCoreExpr hsc_env =
- lookupHook hscCompileCoreExprHook hscCompileCoreExpr' (hsc_dflags hsc_env) hsc_env
-
-hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue
-hscCompileCoreExpr' hsc_env srcspan ds_expr
- = do { let dflags = hsc_dflags hsc_env
-
- {- Simplify it -}
- ; simpl_expr <- simplifyExpr hsc_env ds_expr
-
- {- Tidy it (temporary, until coreSat does cloning) -}
- ; let tidy_expr = tidyExpr emptyTidyEnv simpl_expr
-
- {- Prepare for codegen -}
- ; prepd_expr <- corePrepExpr dflags hsc_env tidy_expr
-
- {- Lint if necessary -}
- ; lintInteractiveExpr "hscCompileExpr" hsc_env prepd_expr
-
- {- Convert to BCOs -}
- ; bcos <- coreExprToBCOs hsc_env
- (icInteractiveModule (hsc_IC hsc_env)) prepd_expr
-
- {- link it -}
- ; hval <- linkExpr hsc_env srcspan bcos
-
- ; return hval }
-
-
-{- **********************************************************************
-%* *
- Statistics on reading interfaces
-%* *
-%********************************************************************* -}
-
-dumpIfaceStats :: HscEnv -> IO ()
-dumpIfaceStats hsc_env = do
- eps <- readIORef (hsc_EPS hsc_env)
- dumpIfSet dflags (dump_if_trace || dump_rn_stats)
- "Interface statistics"
- (ifaceStats eps)
- where
- dflags = hsc_dflags hsc_env
- dump_rn_stats = dopt Opt_D_dump_rn_stats dflags
- dump_if_trace = dopt Opt_D_dump_if_trace dflags
-
-
-{- **********************************************************************
-%* *
- Progress Messages: Module i of n
-%* *
-%********************************************************************* -}
-
-showModuleIndex :: (Int, Int) -> String
-showModuleIndex (i,n) = "[" ++ padded ++ " of " ++ n_str ++ "] "
- where
- n_str = show n
- i_str = show i
- padded = replicate (length n_str - length i_str) ' ' ++ i_str