GHC produces grouped declarations in a weird order
Consider very simple module like
module J where
class A a where
f, g, h, i :: a -> ()
Now when we ask GHC about declarations in the module and extract function signatures, we don't get f, g, h, i :: a -> ()
as we could expect. We instead get f, i, h, g :: a -> ()
. The pattern is that the first name is in a correct position and the rest is reversed. This leads to whatever uses the API get the names in order different than that in the source file. See http://trac.haskell.org/haddock/ticket/188 for an example when this matters.
I have prepared an example using GHC API which you can run on your machine with your own test files and see the results for yourselves.
-- GHC.Paths requires the very small ghc-paths package.
-- if you don't want it, libdir = ghc --print-libdir
module Main where
import Control.Monad (ap, liftM2)
import Data.Functor ((<$>))
import System.Environment (getArgs)
import Digraph (flattenSCCs)
import GHC
import GHC.Paths (libdir)
import Outputable (text, ppr, showSDoc, (<>), (<+>))
main :: IO ()
main = do
(dfs, modules) <- getArgs >>= withGhc Nothing . processModules
let r = map (showSDoc dfs . (\(x,y) -> text x <> text ":" <+> ppr y) . f)
modules
putStrLn $ unlines r
where
f (s, t) = (ms_hspp_file s, (\(x,_,_,_) -> x) <$> tm_renamed_source t)
type ModuleName' = String
withGhc :: Maybe DynFlags -> Ghc a -> IO (DynFlags, a)
withGhc d act =
runGhc (Just libdir) $ do
dynflags <- case d of
Nothing -> getSessionDynFlags
Just d' -> return d'
_ <- setSessionDynFlags dynflags
liftM2 (,) getSessionDynFlags act
processModules :: [ModuleName']
-> Ghc [(ModSummary, TypecheckedModule)]
processModules modules = do
mg <- depAnalysis
let sortedMods = flattenSCCs $ topSortModuleGraph False mg Nothing
mapM (\x -> return (\y -> (x,y)) `ap`
(parseModule x >>= typecheckModule >>= loadModule))
sortedMods
where
depAnalysis :: Ghc ModuleGraph
depAnalysis = do
targets <- mapM (\f -> guessTarget f Nothing) modules
setTargets targets
depanal [] False
In this case, using the tiny module I posted at the beginning, I get:
*Main> :main "/tmp/J.hs"
/tmp/J.hs: Just class J.A a where
J.f, J.i, J.h, J.g :: a -> ()
It looks to me like it's just an oversight somewhere in the API and should be an easy fix for someone familiar with that part. I'd rather save myself many hours trying to find it on my own.
PS: Are the rules for when grouping happens documented somewhere? Grouping functions in class definitions is the only sure-fire way I can get a grouped signature but I'm sure there were others in the past that no longer work.
Trac metadata
Trac field | Value |
---|---|
Version | 7.9 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | GHC API |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |