{-# LANGUAGE CPP, MagicHash #-}

-- | Dynamically lookup up values from modules and loading them.
module GHC.Runtime.Loader (
        initializePlugins,
        -- * Loading plugins
        loadFrontendPlugin,

        -- * Force loading information
        forceLoadModuleInterfaces,
        forceLoadNameModuleInterface,
        forceLoadTyCon,

        -- * Finding names
        lookupRdrNameInModuleForPlugins,

        -- * Loading values
        getValueSafely,
        getHValueSafely,
        lessUnsafeCoerce
    ) where

import GHC.Prelude
import GHC.Driver.Session

import GHC.Runtime.Linker      ( linkModule, getHValue )
import GHC.Runtime.Interpreter ( wormhole, withInterp )
import GHC.Runtime.Interpreter.Types
import GHC.Types.SrcLoc        ( noSrcSpan )
import GHC.Driver.Finder       ( findPluginModule, cannotFindModule )
import GHC.Tc.Utils.Monad      ( initTcInteractive, initIfaceTcRn )
import GHC.Iface.Load          ( loadPluginInterface )
import GHC.Types.Name.Reader   ( RdrName, ImportSpec(..), ImpDeclSpec(..)
                               , ImpItemSpec(..), mkGlobalRdrEnv, lookupGRE_RdrName
                               , gre_name, mkRdrQual )
import GHC.Types.Name.Occurrence ( OccName, mkVarOcc )
import GHC.Rename.Names ( gresFromAvails )
import GHC.Driver.Plugins
import GHC.Builtin.Names ( pluginTyConName, frontendPluginTyConName )

import GHC.Driver.Types
import GHCi.RemoteTypes  ( HValue )
import GHC.Core.Type     ( Type, eqType, mkTyConTy )
import GHC.Core.TyCo.Ppr ( pprTyThingCategory )
import GHC.Core.TyCon    ( TyCon )
import GHC.Types.Name    ( Name, nameModule_maybe )
import GHC.Types.Id      ( idType )
import GHC.Unit.Module   ( Module, ModuleName )
import GHC.Utils.Panic
import GHC.Data.FastString
import GHC.Utils.Error
import GHC.Utils.Outputable
import GHC.Utils.Exception
import GHC.Driver.Hooks

import Control.Monad     ( unless )
import Data.Maybe        ( mapMaybe )
import Unsafe.Coerce     ( unsafeCoerce )

-- | Loads the plugins specified in the pluginModNames field of the dynamic
-- flags. Should be called after command line arguments are parsed, but before
-- actual compilation starts. Idempotent operation. Should be re-called if
-- pluginModNames or pluginModNameOpts changes.
initializePlugins :: HscEnv -> DynFlags -> IO DynFlags
initializePlugins :: HscEnv -> DynFlags -> IO DynFlags
initializePlugins HscEnv
hsc_env DynFlags
df
  | (LoadedPlugin -> ModuleName) -> [LoadedPlugin] -> [ModuleName]
forall a b. (a -> b) -> [a] -> [b]
map LoadedPlugin -> ModuleName
lpModuleName (DynFlags -> [LoadedPlugin]
cachedPlugins DynFlags
df)
         [ModuleName] -> [ModuleName] -> Bool
forall a. Eq a => a -> a -> Bool
== DynFlags -> [ModuleName]
pluginModNames DynFlags
df -- plugins not changed
     Bool -> Bool -> Bool
&& (LoadedPlugin -> Bool) -> [LoadedPlugin] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\LoadedPlugin
p -> PluginWithArgs -> [CommandLineOption]
paArguments (LoadedPlugin -> PluginWithArgs
lpPlugin LoadedPlugin
p)
                       [CommandLineOption] -> [CommandLineOption] -> Bool
forall a. Eq a => a -> a -> Bool
== LoadedPlugin
-> [(ModuleName, CommandLineOption)] -> [CommandLineOption]
forall {b}. LoadedPlugin -> [(ModuleName, b)] -> [b]
argumentsForPlugin LoadedPlugin
p (DynFlags -> [(ModuleName, CommandLineOption)]
pluginModNameOpts DynFlags
df))
            (DynFlags -> [LoadedPlugin]
cachedPlugins DynFlags
df) -- arguments not changed
  = DynFlags -> IO DynFlags
forall (m :: * -> *) a. Monad m => a -> m a
return DynFlags
df -- no need to reload plugins
  | Bool
otherwise
  = do [LoadedPlugin]
loadedPlugins <- HscEnv -> IO [LoadedPlugin]
loadPlugins (HscEnv
hsc_env { hsc_dflags :: DynFlags
hsc_dflags = DynFlags
df })
       let df' :: DynFlags
df' = DynFlags
df { cachedPlugins :: [LoadedPlugin]
cachedPlugins = [LoadedPlugin]
loadedPlugins }
       DynFlags
df'' <- DynFlags -> PluginOperation IO DynFlags -> DynFlags -> IO DynFlags
forall (m :: * -> *) a.
Monad m =>
DynFlags -> PluginOperation m a -> a -> m a
withPlugins DynFlags
df' PluginOperation IO DynFlags
runDflagsPlugin DynFlags
df'
       DynFlags -> IO DynFlags
forall (m :: * -> *) a. Monad m => a -> m a
return DynFlags
df''

  where argumentsForPlugin :: LoadedPlugin -> [(ModuleName, b)] -> [b]
argumentsForPlugin LoadedPlugin
p = ((ModuleName, b) -> b) -> [(ModuleName, b)] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map (ModuleName, b) -> b
forall a b. (a, b) -> b
snd ([(ModuleName, b)] -> [b])
-> ([(ModuleName, b)] -> [(ModuleName, b)])
-> [(ModuleName, b)]
-> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ModuleName, b) -> Bool) -> [(ModuleName, b)] -> [(ModuleName, b)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((ModuleName -> ModuleName -> Bool
forall a. Eq a => a -> a -> Bool
== LoadedPlugin -> ModuleName
lpModuleName LoadedPlugin
p) (ModuleName -> Bool)
-> ((ModuleName, b) -> ModuleName) -> (ModuleName, b) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModuleName, b) -> ModuleName
forall a b. (a, b) -> a
fst)
        runDflagsPlugin :: PluginOperation IO DynFlags
runDflagsPlugin Plugin
p [CommandLineOption]
opts DynFlags
dynflags = PluginOperation IO DynFlags
dynflagsPlugin Plugin
p [CommandLineOption]
opts DynFlags
dynflags

loadPlugins :: HscEnv -> IO [LoadedPlugin]
loadPlugins :: HscEnv -> IO [LoadedPlugin]
loadPlugins HscEnv
hsc_env
  = do { Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([ModuleName] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ModuleName]
to_load) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
           HscEnv -> IO ()
checkExternalInterpreter HscEnv
hsc_env
       ; [(Plugin, ModIface)]
plugins <- (ModuleName -> IO (Plugin, ModIface))
-> [ModuleName] -> IO [(Plugin, ModIface)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ModuleName -> IO (Plugin, ModIface)
forall {a}. ModuleName -> IO (a, ModIface)
loadPlugin [ModuleName]
to_load
       ; [LoadedPlugin] -> IO [LoadedPlugin]
forall (m :: * -> *) a. Monad m => a -> m a
return ([LoadedPlugin] -> IO [LoadedPlugin])
-> [LoadedPlugin] -> IO [LoadedPlugin]
forall a b. (a -> b) -> a -> b
$ (ModuleName -> (Plugin, ModIface) -> LoadedPlugin)
-> [ModuleName] -> [(Plugin, ModIface)] -> [LoadedPlugin]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith ModuleName -> (Plugin, ModIface) -> LoadedPlugin
attachOptions [ModuleName]
to_load [(Plugin, ModIface)]
plugins }
  where
    dflags :: DynFlags
dflags  = HscEnv -> DynFlags
hsc_dflags HscEnv
hsc_env
    to_load :: [ModuleName]
to_load = DynFlags -> [ModuleName]
pluginModNames DynFlags
dflags

    attachOptions :: ModuleName -> (Plugin, ModIface) -> LoadedPlugin
attachOptions ModuleName
mod_nm (Plugin
plug, ModIface
mod) =
        PluginWithArgs -> ModIface -> LoadedPlugin
LoadedPlugin (Plugin -> [CommandLineOption] -> PluginWithArgs
PluginWithArgs Plugin
plug ([CommandLineOption] -> [CommandLineOption]
forall a. [a] -> [a]
reverse [CommandLineOption]
options)) ModIface
mod
      where
        options :: [CommandLineOption]
options = [ CommandLineOption
option | (ModuleName
opt_mod_nm, CommandLineOption
option) <- DynFlags -> [(ModuleName, CommandLineOption)]
pluginModNameOpts DynFlags
dflags
                            , ModuleName
opt_mod_nm ModuleName -> ModuleName -> Bool
forall a. Eq a => a -> a -> Bool
== ModuleName
mod_nm ]
    loadPlugin :: ModuleName -> IO (a, ModIface)
loadPlugin = OccName -> Name -> HscEnv -> ModuleName -> IO (a, ModIface)
forall a.
OccName -> Name -> HscEnv -> ModuleName -> IO (a, ModIface)
loadPlugin' (CommandLineOption -> OccName
mkVarOcc CommandLineOption
"plugin") Name
pluginTyConName HscEnv
hsc_env


loadFrontendPlugin :: HscEnv -> ModuleName -> IO FrontendPlugin
loadFrontendPlugin :: HscEnv -> ModuleName -> IO FrontendPlugin
loadFrontendPlugin HscEnv
hsc_env ModuleName
mod_name = do
    HscEnv -> IO ()
checkExternalInterpreter HscEnv
hsc_env
    (FrontendPlugin, ModIface) -> FrontendPlugin
forall a b. (a, b) -> a
fst ((FrontendPlugin, ModIface) -> FrontendPlugin)
-> IO (FrontendPlugin, ModIface) -> IO FrontendPlugin
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> OccName
-> Name -> HscEnv -> ModuleName -> IO (FrontendPlugin, ModIface)
forall a.
OccName -> Name -> HscEnv -> ModuleName -> IO (a, ModIface)
loadPlugin' (CommandLineOption -> OccName
mkVarOcc CommandLineOption
"frontendPlugin") Name
frontendPluginTyConName
                HscEnv
hsc_env ModuleName
mod_name

-- #14335
checkExternalInterpreter :: HscEnv -> IO ()
checkExternalInterpreter :: HscEnv -> IO ()
checkExternalInterpreter HscEnv
hsc_env
  | Just (ExternalInterp {}) <- HscEnv -> Maybe Interp
hsc_interp HscEnv
hsc_env
  = GhcException -> IO ()
forall e a. Exception e => e -> IO a
throwIO (CommandLineOption -> GhcException
InstallationError CommandLineOption
"Plugins require -fno-external-interpreter")
  | Bool
otherwise
  = () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

loadPlugin' :: OccName -> Name -> HscEnv -> ModuleName -> IO (a, ModIface)
loadPlugin' :: forall a.
OccName -> Name -> HscEnv -> ModuleName -> IO (a, ModIface)
loadPlugin' OccName
occ_name Name
plugin_name HscEnv
hsc_env ModuleName
mod_name
  = do { let plugin_rdr_name :: RdrName
plugin_rdr_name = ModuleName -> OccName -> RdrName
mkRdrQual ModuleName
mod_name OccName
occ_name
             dflags :: DynFlags
dflags = HscEnv -> DynFlags
hsc_dflags HscEnv
hsc_env
       ; Maybe (Name, ModIface)
mb_name <- HscEnv -> ModuleName -> RdrName -> IO (Maybe (Name, ModIface))
lookupRdrNameInModuleForPlugins HscEnv
hsc_env ModuleName
mod_name
                        RdrName
plugin_rdr_name
       ; case Maybe (Name, ModIface)
mb_name of {
            Maybe (Name, ModIface)
Nothing ->
                GhcException -> IO (a, ModIface)
forall a. GhcException -> IO a
throwGhcExceptionIO (CommandLineOption -> GhcException
CmdLineError (CommandLineOption -> GhcException)
-> CommandLineOption -> GhcException
forall a b. (a -> b) -> a -> b
$ DynFlags -> SDoc -> CommandLineOption
showSDoc DynFlags
dflags (SDoc -> CommandLineOption) -> SDoc -> CommandLineOption
forall a b. (a -> b) -> a -> b
$ [SDoc] -> SDoc
hsep
                          [ CommandLineOption -> SDoc
text CommandLineOption
"The module", ModuleName -> SDoc
forall a. Outputable a => a -> SDoc
ppr ModuleName
mod_name
                          , CommandLineOption -> SDoc
text CommandLineOption
"did not export the plugin name"
                          , RdrName -> SDoc
forall a. Outputable a => a -> SDoc
ppr RdrName
plugin_rdr_name ]) ;
            Just (Name
name, ModIface
mod_iface) ->

     do { TyCon
plugin_tycon <- HscEnv -> Name -> IO TyCon
forceLoadTyCon HscEnv
hsc_env Name
plugin_name
        ; Maybe a
mb_plugin <- HscEnv -> Name -> Type -> IO (Maybe a)
forall a. HscEnv -> Name -> Type -> IO (Maybe a)
getValueSafely HscEnv
hsc_env Name
name (TyCon -> Type
mkTyConTy TyCon
plugin_tycon)
        ; case Maybe a
mb_plugin of
            Maybe a
Nothing ->
                GhcException -> IO (a, ModIface)
forall a. GhcException -> IO a
throwGhcExceptionIO (CommandLineOption -> GhcException
CmdLineError (CommandLineOption -> GhcException)
-> CommandLineOption -> GhcException
forall a b. (a -> b) -> a -> b
$ DynFlags -> SDoc -> CommandLineOption
showSDoc DynFlags
dflags (SDoc -> CommandLineOption) -> SDoc -> CommandLineOption
forall a b. (a -> b) -> a -> b
$ [SDoc] -> SDoc
hsep
                          [ CommandLineOption -> SDoc
text CommandLineOption
"The value", Name -> SDoc
forall a. Outputable a => a -> SDoc
ppr Name
name
                          , CommandLineOption -> SDoc
text CommandLineOption
"did not have the type"
                          , Name -> SDoc
forall a. Outputable a => a -> SDoc
ppr Name
pluginTyConName, CommandLineOption -> SDoc
text CommandLineOption
"as required"])
            Just a
plugin -> (a, ModIface) -> IO (a, ModIface)
forall (m :: * -> *) a. Monad m => a -> m a
return (a
plugin, ModIface
mod_iface) } } }


-- | Force the interfaces for the given modules to be loaded. The 'SDoc' parameter is used
-- for debugging (@-ddump-if-trace@) only: it is shown as the reason why the module is being loaded.
forceLoadModuleInterfaces :: HscEnv -> SDoc -> [Module] -> IO ()
forceLoadModuleInterfaces :: HscEnv -> SDoc -> [Module] -> IO ()
forceLoadModuleInterfaces HscEnv
hsc_env SDoc
doc [Module]
modules
    = (HscEnv -> TcM () -> IO (Messages, Maybe ())
forall a. HscEnv -> TcM a -> IO (Messages, Maybe a)
initTcInteractive HscEnv
hsc_env (TcM () -> IO (Messages, Maybe ()))
-> TcM () -> IO (Messages, Maybe ())
forall a b. (a -> b) -> a -> b
$
       IfG () -> TcM ()
forall a. IfG a -> TcRn a
initIfaceTcRn (IfG () -> TcM ()) -> IfG () -> TcM ()
forall a b. (a -> b) -> a -> b
$
       (Module -> IOEnv (Env IfGblEnv ()) ModIface) -> [Module] -> IfG ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (SDoc -> Module -> IOEnv (Env IfGblEnv ()) ModIface
forall lcl. SDoc -> Module -> IfM lcl ModIface
loadPluginInterface SDoc
doc) [Module]
modules)
      IO (Messages, Maybe ()) -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | Force the interface for the module containing the name to be loaded. The 'SDoc' parameter is used
-- for debugging (@-ddump-if-trace@) only: it is shown as the reason why the module is being loaded.
forceLoadNameModuleInterface :: HscEnv -> SDoc -> Name -> IO ()
forceLoadNameModuleInterface :: HscEnv -> SDoc -> Name -> IO ()
forceLoadNameModuleInterface HscEnv
hsc_env SDoc
reason Name
name = do
    let name_modules :: [Module]
name_modules = (Name -> Maybe Module) -> [Name] -> [Module]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Name -> Maybe Module
nameModule_maybe [Name
name]
    HscEnv -> SDoc -> [Module] -> IO ()
forceLoadModuleInterfaces HscEnv
hsc_env SDoc
reason [Module]
name_modules

-- | Load the 'TyCon' associated with the given name, come hell or high water. Fails if:
--
-- * The interface could not be loaded
-- * The name is not that of a 'TyCon'
-- * The name did not exist in the loaded module
forceLoadTyCon :: HscEnv -> Name -> IO TyCon
forceLoadTyCon :: HscEnv -> Name -> IO TyCon
forceLoadTyCon HscEnv
hsc_env Name
con_name = do
    HscEnv -> SDoc -> Name -> IO ()
forceLoadNameModuleInterface HscEnv
hsc_env (CommandLineOption -> SDoc
text CommandLineOption
"contains a name used in an invocation of loadTyConTy") Name
con_name

    Maybe TyThing
mb_con_thing <- HscEnv -> Name -> IO (Maybe TyThing)
lookupTypeHscEnv HscEnv
hsc_env Name
con_name
    case Maybe TyThing
mb_con_thing of
        Maybe TyThing
Nothing -> DynFlags -> SDoc -> IO TyCon
forall a. DynFlags -> SDoc -> IO a
throwCmdLineErrorS DynFlags
dflags (SDoc -> IO TyCon) -> SDoc -> IO TyCon
forall a b. (a -> b) -> a -> b
$ Name -> SDoc
missingTyThingError Name
con_name
        Just (ATyCon TyCon
tycon) -> TyCon -> IO TyCon
forall (m :: * -> *) a. Monad m => a -> m a
return TyCon
tycon
        Just TyThing
con_thing -> DynFlags -> SDoc -> IO TyCon
forall a. DynFlags -> SDoc -> IO a
throwCmdLineErrorS DynFlags
dflags (SDoc -> IO TyCon) -> SDoc -> IO TyCon
forall a b. (a -> b) -> a -> b
$ Name -> TyThing -> SDoc
wrongTyThingError Name
con_name TyThing
con_thing
  where dflags :: DynFlags
dflags = HscEnv -> DynFlags
hsc_dflags HscEnv
hsc_env

-- | Loads the value corresponding to a 'Name' if that value has the given 'Type'. This only provides limited safety
-- in that it is up to the user to ensure that that type corresponds to the type you try to use the return value at!
--
-- If the value found was not of the correct type, returns @Nothing@. Any other condition results in an exception:
--
-- * If we could not load the names module
-- * If the thing being loaded is not a value
-- * If the Name does not exist in the module
-- * If the link failed

getValueSafely :: HscEnv -> Name -> Type -> IO (Maybe a)
getValueSafely :: forall a. HscEnv -> Name -> Type -> IO (Maybe a)
getValueSafely HscEnv
hsc_env Name
val_name Type
expected_type = do
  Maybe HValue
mb_hval <- (Hooks -> Maybe (HscEnv -> Name -> Type -> IO (Maybe HValue)))
-> (HscEnv -> Name -> Type -> IO (Maybe HValue))
-> DynFlags
-> HscEnv
-> Name
-> Type
-> IO (Maybe HValue)
forall a. (Hooks -> Maybe a) -> a -> DynFlags -> a
lookupHook Hooks -> Maybe (HscEnv -> Name -> Type -> IO (Maybe HValue))
getValueSafelyHook HscEnv -> Name -> Type -> IO (Maybe HValue)
getHValueSafely DynFlags
dflags HscEnv
hsc_env Name
val_name Type
expected_type
  case Maybe HValue
mb_hval of
    Maybe HValue
Nothing   -> Maybe a -> IO (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing
    Just HValue
hval -> do
      a
value <- DynFlags -> CommandLineOption -> HValue -> IO a
forall a b. DynFlags -> CommandLineOption -> a -> IO b
lessUnsafeCoerce DynFlags
dflags CommandLineOption
"getValueSafely" HValue
hval
      Maybe a -> IO (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Maybe a
forall a. a -> Maybe a
Just a
value)
  where
    dflags :: DynFlags
dflags = HscEnv -> DynFlags
hsc_dflags HscEnv
hsc_env

getHValueSafely :: HscEnv -> Name -> Type -> IO (Maybe HValue)
getHValueSafely :: HscEnv -> Name -> Type -> IO (Maybe HValue)
getHValueSafely HscEnv
hsc_env Name
val_name Type
expected_type = do
    HscEnv -> SDoc -> Name -> IO ()
forceLoadNameModuleInterface HscEnv
hsc_env (CommandLineOption -> SDoc
text CommandLineOption
"contains a name used in an invocation of getHValueSafely") Name
val_name
    -- Now look up the names for the value and type constructor in the type environment
    Maybe TyThing
mb_val_thing <- HscEnv -> Name -> IO (Maybe TyThing)
lookupTypeHscEnv HscEnv
hsc_env Name
val_name
    case Maybe TyThing
mb_val_thing of
        Maybe TyThing
Nothing -> DynFlags -> SDoc -> IO (Maybe HValue)
forall a. DynFlags -> SDoc -> IO a
throwCmdLineErrorS DynFlags
dflags (SDoc -> IO (Maybe HValue)) -> SDoc -> IO (Maybe HValue)
forall a b. (a -> b) -> a -> b
$ Name -> SDoc
missingTyThingError Name
val_name
        Just (AnId Id
id) -> do
            -- Check the value type in the interface against the type recovered from the type constructor
            -- before finally casting the value to the type we assume corresponds to that constructor
            if Type
expected_type Type -> Type -> Bool
`eqType` Id -> Type
idType Id
id
             then do
                -- Link in the module that contains the value, if it has such a module
                case Name -> Maybe Module
nameModule_maybe Name
val_name of
                    Just Module
mod -> do HscEnv -> Module -> IO ()
linkModule HscEnv
hsc_env Module
mod
                                   () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
                    Maybe Module
Nothing ->  () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
                -- Find the value that we just linked in and cast it given that we have proved it's type
                HValue
hval <- HscEnv -> (Interp -> IO HValue) -> IO HValue
forall a. HscEnv -> (Interp -> IO a) -> IO a
withInterp HscEnv
hsc_env ((Interp -> IO HValue) -> IO HValue)
-> (Interp -> IO HValue) -> IO HValue
forall a b. (a -> b) -> a -> b
$ \Interp
interp -> HscEnv -> Name -> IO ForeignHValue
getHValue HscEnv
hsc_env Name
val_name IO ForeignHValue -> (ForeignHValue -> IO HValue) -> IO HValue
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Interp -> ForeignHValue -> IO HValue
forall a. Interp -> ForeignRef a -> IO a
wormhole Interp
interp
                Maybe HValue -> IO (Maybe HValue)
forall (m :: * -> *) a. Monad m => a -> m a
return (HValue -> Maybe HValue
forall a. a -> Maybe a
Just HValue
hval)
             else Maybe HValue -> IO (Maybe HValue)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe HValue
forall a. Maybe a
Nothing
        Just TyThing
val_thing -> DynFlags -> SDoc -> IO (Maybe HValue)
forall a. DynFlags -> SDoc -> IO a
throwCmdLineErrorS DynFlags
dflags (SDoc -> IO (Maybe HValue)) -> SDoc -> IO (Maybe HValue)
forall a b. (a -> b) -> a -> b
$ Name -> TyThing -> SDoc
wrongTyThingError Name
val_name TyThing
val_thing
   where dflags :: DynFlags
dflags = HscEnv -> DynFlags
hsc_dflags HscEnv
hsc_env

-- | Coerce a value as usual, but:
--
-- 1) Evaluate it immediately to get a segfault early if the coercion was wrong
--
-- 2) Wrap it in some debug messages at verbosity 3 or higher so we can see what happened
--    if it /does/ segfault
lessUnsafeCoerce :: DynFlags -> String -> a -> IO b
lessUnsafeCoerce :: forall a b. DynFlags -> CommandLineOption -> a -> IO b
lessUnsafeCoerce DynFlags
dflags CommandLineOption
context a
what = do
    DynFlags -> Int -> SDoc -> IO ()
debugTraceMsg DynFlags
dflags Int
3 (SDoc -> IO ()) -> SDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ (CommandLineOption -> SDoc
text CommandLineOption
"Coercing a value in") SDoc -> SDoc -> SDoc
<+> (CommandLineOption -> SDoc
text CommandLineOption
context) SDoc -> SDoc -> SDoc
<>
                             (CommandLineOption -> SDoc
text CommandLineOption
"...")
    b
output <- b -> IO b
forall a. a -> IO a
evaluate (a -> b
forall a b. a -> b
unsafeCoerce a
what)
    DynFlags -> Int -> SDoc -> IO ()
debugTraceMsg DynFlags
dflags Int
3 (CommandLineOption -> SDoc
text CommandLineOption
"Successfully evaluated coercion")
    b -> IO b
forall (m :: * -> *) a. Monad m => a -> m a
return b
output


-- | Finds the 'Name' corresponding to the given 'RdrName' in the
-- context of the 'ModuleName'. Returns @Nothing@ if no such 'Name'
-- could be found. Any other condition results in an exception:
--
-- * If the module could not be found
-- * If we could not determine the imports of the module
--
-- Can only be used for looking up names while loading plugins (and is
-- *not* suitable for use within plugins).  The interface file is
-- loaded very partially: just enough that it can be used, without its
-- rules and instances affecting (and being linked from!) the module
-- being compiled.  This was introduced by 57d6798.
--
-- Need the module as well to record information in the interface file
lookupRdrNameInModuleForPlugins :: HscEnv -> ModuleName -> RdrName
                                -> IO (Maybe (Name, ModIface))
lookupRdrNameInModuleForPlugins :: HscEnv -> ModuleName -> RdrName -> IO (Maybe (Name, ModIface))
lookupRdrNameInModuleForPlugins HscEnv
hsc_env ModuleName
mod_name RdrName
rdr_name = do
    -- First find the unit the module resides in by searching exposed units and home modules
    FindResult
found_module <- HscEnv -> ModuleName -> IO FindResult
findPluginModule HscEnv
hsc_env ModuleName
mod_name
    case FindResult
found_module of
        Found ModLocation
_ Module
mod -> do
            -- Find the exports of the module
            (Messages
_, Maybe ModIface
mb_iface) <- HscEnv -> TcM ModIface -> IO (Messages, Maybe ModIface)
forall a. HscEnv -> TcM a -> IO (Messages, Maybe a)
initTcInteractive HscEnv
hsc_env (TcM ModIface -> IO (Messages, Maybe ModIface))
-> TcM ModIface -> IO (Messages, Maybe ModIface)
forall a b. (a -> b) -> a -> b
$
                             IOEnv (Env IfGblEnv ()) ModIface -> TcM ModIface
forall a. IfG a -> TcRn a
initIfaceTcRn (IOEnv (Env IfGblEnv ()) ModIface -> TcM ModIface)
-> IOEnv (Env IfGblEnv ()) ModIface -> TcM ModIface
forall a b. (a -> b) -> a -> b
$
                             SDoc -> Module -> IOEnv (Env IfGblEnv ()) ModIface
forall lcl. SDoc -> Module -> IfM lcl ModIface
loadPluginInterface SDoc
doc Module
mod
            case Maybe ModIface
mb_iface of
                Just ModIface
iface -> do
                    -- Try and find the required name in the exports
                    let decl_spec :: ImpDeclSpec
decl_spec = ImpDeclSpec :: ModuleName -> ModuleName -> Bool -> SrcSpan -> ImpDeclSpec
ImpDeclSpec { is_mod :: ModuleName
is_mod = ModuleName
mod_name, is_as :: ModuleName
is_as = ModuleName
mod_name
                                                , is_qual :: Bool
is_qual = Bool
False, is_dloc :: SrcSpan
is_dloc = SrcSpan
noSrcSpan }
                        imp_spec :: ImportSpec
imp_spec = ImpDeclSpec -> ImpItemSpec -> ImportSpec
ImpSpec ImpDeclSpec
decl_spec ImpItemSpec
ImpAll
                        env :: GlobalRdrEnv
env = [GlobalRdrElt] -> GlobalRdrEnv
mkGlobalRdrEnv (Maybe ImportSpec -> [AvailInfo] -> [GlobalRdrElt]
gresFromAvails (ImportSpec -> Maybe ImportSpec
forall a. a -> Maybe a
Just ImportSpec
imp_spec) (ModIface -> [AvailInfo]
forall (phase :: ModIfacePhase). ModIface_ phase -> [AvailInfo]
mi_exports ModIface
iface))
                    case RdrName -> GlobalRdrEnv -> [GlobalRdrElt]
lookupGRE_RdrName RdrName
rdr_name GlobalRdrEnv
env of
                        [GlobalRdrElt
gre] -> Maybe (Name, ModIface) -> IO (Maybe (Name, ModIface))
forall (m :: * -> *) a. Monad m => a -> m a
return ((Name, ModIface) -> Maybe (Name, ModIface)
forall a. a -> Maybe a
Just (GlobalRdrElt -> Name
gre_name GlobalRdrElt
gre, ModIface
iface))
                        []    -> Maybe (Name, ModIface) -> IO (Maybe (Name, ModIface))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Name, ModIface)
forall a. Maybe a
Nothing
                        [GlobalRdrElt]
_     -> CommandLineOption -> IO (Maybe (Name, ModIface))
forall a. CommandLineOption -> a
panic CommandLineOption
"lookupRdrNameInModule"

                Maybe ModIface
Nothing -> DynFlags -> SDoc -> IO (Maybe (Name, ModIface))
forall a. DynFlags -> SDoc -> IO a
throwCmdLineErrorS DynFlags
dflags (SDoc -> IO (Maybe (Name, ModIface)))
-> SDoc -> IO (Maybe (Name, ModIface))
forall a b. (a -> b) -> a -> b
$ [SDoc] -> SDoc
hsep [CommandLineOption -> SDoc
text CommandLineOption
"Could not determine the exports of the module", ModuleName -> SDoc
forall a. Outputable a => a -> SDoc
ppr ModuleName
mod_name]
        FindResult
err -> DynFlags -> SDoc -> IO (Maybe (Name, ModIface))
forall a. DynFlags -> SDoc -> IO a
throwCmdLineErrorS DynFlags
dflags (SDoc -> IO (Maybe (Name, ModIface)))
-> SDoc -> IO (Maybe (Name, ModIface))
forall a b. (a -> b) -> a -> b
$ DynFlags -> ModuleName -> FindResult -> SDoc
cannotFindModule DynFlags
dflags ModuleName
mod_name FindResult
err
  where
    dflags :: DynFlags
dflags = HscEnv -> DynFlags
hsc_dflags HscEnv
hsc_env
    doc :: SDoc
doc = CommandLineOption -> SDoc
text CommandLineOption
"contains a name used in an invocation of lookupRdrNameInModule"

wrongTyThingError :: Name -> TyThing -> SDoc
wrongTyThingError :: Name -> TyThing -> SDoc
wrongTyThingError Name
name TyThing
got_thing = [SDoc] -> SDoc
hsep [CommandLineOption -> SDoc
text CommandLineOption
"The name", Name -> SDoc
forall a. Outputable a => a -> SDoc
ppr Name
name, PtrString -> SDoc
ptext (CommandLineOption -> PtrString
sLit CommandLineOption
"is not that of a value but rather a"), TyThing -> SDoc
pprTyThingCategory TyThing
got_thing]

missingTyThingError :: Name -> SDoc
missingTyThingError :: Name -> SDoc
missingTyThingError Name
name = [SDoc] -> SDoc
hsep [CommandLineOption -> SDoc
text CommandLineOption
"The name", Name -> SDoc
forall a. Outputable a => a -> SDoc
ppr Name
name, PtrString -> SDoc
ptext (CommandLineOption -> PtrString
sLit CommandLineOption
"is not in the type environment: are you sure it exists?")]

throwCmdLineErrorS :: DynFlags -> SDoc -> IO a
throwCmdLineErrorS :: forall a. DynFlags -> SDoc -> IO a
throwCmdLineErrorS DynFlags
dflags = CommandLineOption -> IO a
forall a. CommandLineOption -> IO a
throwCmdLineError (CommandLineOption -> IO a)
-> (SDoc -> CommandLineOption) -> SDoc -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DynFlags -> SDoc -> CommandLineOption
showSDoc DynFlags
dflags

throwCmdLineError :: String -> IO a
throwCmdLineError :: forall a. CommandLineOption -> IO a
throwCmdLineError = GhcException -> IO a
forall a. GhcException -> IO a
throwGhcExceptionIO (GhcException -> IO a)
-> (CommandLineOption -> GhcException) -> CommandLineOption -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CommandLineOption -> GhcException
CmdLineError