Reputation: 833
I'm trying to list (print) all functions (and their types) that are in scope for a given module.
For example, I have this module:
{-# LANGUAGE NoImplicitPrelude #-}
module Reverse where
import Prelude ((==), String)
myString :: String
myString = "string"
I'm trying to use the GHC API (8.0.2), but I can't seem to find where the information that I'm looking for is stored. I have managed to find all functions in scope, (but not with their types,) with this code:
import Data.IORef
import DynFlags
import GHC
import GHC.LanguageExtensions
import GHC.Paths (libdir)
import HscTypes
import NameEnv
import OccName
import Outputable
import RdrName
import TcRnTypes
main = runGhc (Just libdir) $ do
liftIO $ print sets
dflags <- getSessionDynFlags
let compdflags =
(foldl xopt_set dflags [Cpp, ImplicitPrelude, MagicHash])
setSessionDynFlags compdflags
target <- guessTarget "Reverse.hs" Nothing
setTargets [target]
load LoadAllTargets
modSum <- getModSummary $ mkModuleName "Reverse"
parsedModule <- parseModule modSum
tmod <- typecheckModule parsedModule
let (tcenv, moddets) = tm_internals_ tmod
printO $ map (map gre_name) $ occEnvElts $ tcg_rdr_env tcenv
printO
:: (GhcMonad m, Outputable a)
=> a -> m ()
printO a = do
dfs <- getProgramDynFlags
liftIO $ putStrLn $ showPpr dfs a
I get this output:
[[String], [==], [myString]]
Of course, this is only half of the way to the data I need.
Upvotes: 2
Views: 304
Reputation: 833
The GHC API is rather confusing, you have to get used to a lot of abbreviations, type-synonyms and a style-heterogenous codebase, but finding the the name and type of everything in scope should be possible. Otherwise GHC couldn't tell you that your function is not in scope if you make a typo.
Indeed, once you have type-checked a module, all the relevant information is available.
First you need all the Name
s of your functions, which you can get with this code:
parsedModule <- parseModule modSum
tmod <- typecheckModule parsedModule
let (tcenv, moddets) = tm_internals_ tmod
let names = concatMap (map gre_name) $ occEnvElts $ tcg_rdr_env tcenv
Then you need to lookup the Names
to get TyThing
s with lookupName
.
You'll get a Maybe TyThing
(Nothing
if the Name
is not found), and when the name refers to a function, the TyThing
will be AnId i
where i
is the thing you're looking for.
An Id
is just a name with a type.
You can then get the type with varType
.
You could argue that all these types make this problem a lot harder, but they've made it possible for me to figure out what I need to do without looking into the code and with no documentation.
Upvotes: 2