Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get type information from the GHC API (for type class support) #269

Closed
chrisdone opened this issue Apr 8, 2013 · 15 comments
Closed

Get type information from the GHC API (for type class support) #269

chrisdone opened this issue Apr 8, 2013 · 15 comments
Labels

Comments

@chrisdone
Copy link
Contributor

So, a while back when I first started Fay I mentioned that my first approach was to use the GHC API. Which is the first thing I wrote:

http://hpaste.org/75112

With the intention that I could get type information and such. But I couldn't see how to do that, and in the interest of expedience I gave up on type-classes and I switched to haskell-src-exts because it was better documented.

Now, looking at it again, I think it may be the answer to many problems, including:

  1. Type-classes.
  2. Name resolution.
  3. Smarter FFI.

At the start I had no idea what was required for a Haskell compiler. Now with experience it's a lot easier to pick out the key requirements.

Notice the definition of Var:

   λ> :i Id
    type Id = Var.Var   -- Defined in `Var'
    λ> :i Var.Var
    data Var.Var
      = Var.TyVar {Var.varName :: !Name,
                   Var.realUnique :: FastTypes.FastInt,
                   Var.varType :: Kind}
      | Var.TcTyVar {Var.varName :: !Name,
                     Var.realUnique :: FastTypes.FastInt,
                     Var.varType :: Kind,
                     Var.tc_tv_details :: TcType.TcTyVarDetails}
      | Var.Id {Var.varName :: !Name,
                Var.realUnique :: FastTypes.FastInt,
                Var.varType :: Type,
                Var.idScope :: Var.IdScope,
                Var.id_details :: IdInfo.IdDetails,
                Var.id_info :: IdInfo.IdInfo}
            -- Defined in `Var'

It appears to me that it contains a name, type and a guid, even scope info. That would be useful for getting name resolution for free but still outputting useful names (i.e. the original), maybe I imagine like foo_1234 or w/e.

Notice also that the typechecked source just gives you a list of binds, and if you want other stuff, it's elsewhere:

λ> :i ModuleInfo
data ModuleInfo
  = GHC.ModuleInfo {GHC.minf_type_env :: TypeEnv,
                    GHC.minf_exports :: NameSet,
                    GHC.minf_rdr_env :: Maybe RdrName.GlobalRdrEnv,
                    GHC.minf_instances :: [Instance],
                    GHC.minf_iface :: Maybe ModIface,
                    GHC.minf_modBreaks :: ModBreaks}
        -- Defined in `GHC'

That seems to be pretty much everything that we need.

I've also noticed in the ghc-mod package this code:

class HasType a where
    getType :: GhcMonad m => TypecheckedModule -> a -> m (Maybe (SrcSpan, Type))

instance HasType (LHsExpr Id) where
    getType tcm e = do
        hs_env <- getSession
        (_, mbe) <- Gap.liftIO $ deSugarExpr hs_env modu rn_env ty_env e
        return $ (getLoc e, ) <$> CoreUtils.exprType <$> mbe
      where
        modu = ms_mod $ pm_mod_summary $ tm_parsed_module tcm
        rn_env = tcg_rdr_env $ fst $ tm_internals_ tcm
        ty_env = tcg_type_env $ fst $ tm_internals_ tcm

instance HasType (LHsBind Id) where
    getType _ (L spn FunBind{fun_matches = MatchGroup _ typ}) = return $ Just (spn, typ)
    getType _ _ = return Nothing

instance HasType (LPat Id) where
    getType _ (L spn pat) = return $ Just (spn, hsPatType pat)

And I've tested it and it does indeed give the type information.

The downside would be that we depend directly on GHC. The other downside would be that GHC's API is highly undocumented, and the API is kind of OTT overengineered, which is miserable to use, and subject to change, so version changes would need to be ifdef'd.

Maybe this approach is a different philosophy from Fay (which depends on GHC-independent libraries like haskell-src-exts and after haskell-type-exts) and belongs in a fork or something, I don't know. But it's an approach that I will be taking seriously.

@cartazio
Copy link

cartazio commented Apr 9, 2013

If i can help in some small way, let me know. having a richer subset of ghc extensions / type system features + being able to target JS would really really be valuable for me.

@bergmark
Copy link
Member

bergmark commented Apr 9, 2013

Cool stuff! I don't mind depending on GHC, but my worry is like you said the undocumented API. It would be nice if someone can spend some time experimenting with this. I plan to spend as much time as possible with the haskell-suite on odhac, then we can hopefully evaluate which direction Fay should go.

I have the impression that haskell-suite would be nicer in the long run, but that remains to be seen.

@johncant
Copy link

I'd like to volunteer to do something on this. I see what you mean about the undocumented API, but I'd naively argue that since HTE hasn't really been touched in a year and a half, then if any breaking changes were made to the GHC API that had useful effects, we'd eventually have to implement something equivalent in HTE ourselves to get the benefit of those changes if we used HTE. Does anyone have a branch I can use as a starting point?

@bergmark
Copy link
Member

bergmark commented Jan 5, 2015

I agree, at this point it seems pretty unlikely that the haskell-suite will go further. I also was never against using GHC. I have to admit that I'm pretty clueless about how to get started on using the GHC API apart from what chris described above.

But there are at least three ways of doing this afaics:

  • Request type information on an ad hoc basis, this might be the easiest to get started with to validate the idea.
  • Get everything from the GHC API, which might mean we'd no longer need to use haskell-names and haskell-src-exts.
  • Just work on GHC core like haste and ghcjs does

@johncant
Copy link

johncant commented Jan 5, 2015

OK, here's how I imagined it would work (although I might be talking a load of rubbish, having never hacked on a compiler before):

"Request type information on an ad hoc basis, this might be the easiest to get started with to validate the idea." is pretty much what I propose.

For each function we export, we generate JS for every concrete type signature that it's called with. I've thought of type variables as being equivalent to c++ template arguments, where functions with type arguments are just templates, which would generate a function for each type they are used with. At the call sites, we will know the type, so we can call the correct function. This is where the GHC API comes in.

I haven't really thought about actual typeclasses too much - I could write Fay code with just fine with the current implementation, but the my main blocker is the fact that functions with type variables always get treated as 'unknown'. From reading the issues, I understand that getting type information is the main blocker, and it's also my main blocker so I've started trying to solve it. I think that when we have the concrete type of each function at its call site, we will also have solved the example in the wiki that shows why Fay has no typeclasses.

So far I've been hacking around with the GHC API and I've managed to delve my way into the expressions from TypecheckedSource, but I wondered whether it would be simpler and more maintainable to traverse GHC's DesugaredModule ? (I haven't looked through this yet but will do because I didn't want to have to write matches for all HsExpr constructors)

I'm not even 100% confident that concrete types are ever resolved at any stage within GHC's compilation, and if not, we'd need to resolve type variables ourselves. Also traversing the Fay AST and the GHC AST together to extract the types seems hard. We'd then need to modify the code generation to output different functions for the different types, combining functions that happen to be identical.

It seems really hard but I'm definitely up for it, depending on what else I can extract from the GHC API. I'll put something up when I have a good GHC API example working. What are your thoughts?

@johncant
Copy link

johncant commented Jan 6, 2015

Desugared output from GHC, but not sure how to find locations from it: http://lpaste.net/117909

How hard would it be to implement our own type resolution in Fay?

@bergmark
Copy link
Member

bergmark commented Jan 7, 2015

With the disclaimer that I haven't implemented a type checker myself:

Writing a Haskell98-compatible type checker is described and implemented in the paper Typing Haskell in Haskell. This wouldn't make us completely GHC compatible since its type system has been extended even further and is now using a constraint based solver. But it would give us type classes and more. It might also be helpful to look at purescript's typechecker. To do this I'd imagine that we'd, at least temporarily, add an extra level of annotations with types on top of the haskell-src-exts AST which right now contains name information from haskell-names. One of the problems with haskell-type-exts was that it was written before haskell-names so it had its own implementation of name resolution.

As you probably concluded, trying to match the HSE AST with the output you pasted sounds really hard.

I think typeclasses can be a solution to the FFI problems. We could have typeclasses with methods for transcoding values to JS/JSON and move the notion of Ptr in there, it may also remove the need for Automatic.

@johncant
Copy link

Yesterday evening I started bringing the GHC API into the Fay compiler, but I realised that I might be reinventing the wheel. I'm going to try Haste in my application before I do anything else. I hope the Haste "runtime" is small enough. Thanks to looking at this I've learned more about Hindley Milner types, compilers, Haskell, and GHC. Thankyou for answering my questions so well. This has been really educational! I'd also like to say that I think Fay is really clever to actually work at all without type information.

@bergmark
Copy link
Member

Spring cleaning. Lack of activity and a very big project, it's unlikely that this will happen.

@swamp-agr
Copy link
Contributor

swamp-agr commented May 1, 2019

I find myself studying GHC API [1], [2].

With given module:

module Main where

import Prelude

main = print (toInteractive "1" :: Int)

class Interactive a where
  toInteractive :: String -> a
  fromInteractive :: a -> String
  doSomething :: String -> a -> String

instance Interactive Int where
  toInteractive = read
  fromInteractive = show
  doSomething a b = show (read a + b)

if we pass several flags to produce result of typecheck and desugar like:

ghc -o test -ddump-tc -ddump-ds Main.hs

we will receive output:

TYPE SIGNATURES
  doSomething :: forall a. Interactive a => String -> a -> String
  fromInteractive :: forall a. Interactive a => a -> String
  :Main.main :: IO ()
  main :: IO ()
  toInteractive :: forall a. Interactive a => String -> a
TYPE CONSTRUCTORS
  class Interactive a where
    toInteractive :: String -> a
    fromInteractive :: a -> String
    doSomething :: String -> a -> String
    {-# MINIMAL toInteractive, fromInteractive, doSomething #-}
COERCION AXIOMS
INSTANCES
  instance Interactive Int -- Defined at Main.hs:13:10
Dependent modules: []
Dependent packages: [base-4.12.0.0, ghc-prim-0.5.3,
                     integer-gmp-1.0.2.0]

==================== Typechecker ====================
Main.$tcInteractive
  = GHC.Types.TyCon
      14397081508441979267##
      10936885658591672495##
      Main.$trModule
      (GHC.Types.TrNameS "Interactive"#)
      0
      $krep_a1NO
Main.$tc'C:Interactive
  = GHC.Types.TyCon
      6110756370800370824##
      1740726806081577955##
      Main.$trModule
      (GHC.Types.TrNameS "'C:Interactive"#)
      1
      $krep_a1NQ
$krep_a1NU [InlPrag=NOUSERINLINE[~]] = GHC.Types.KindRepVar 0
$krep_a1NW [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepFun $krep_a1NU $krep_a1NS
$krep_a1NV [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepFun $krep_a1NW $krep_a1NX
$krep_a1NQ [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepFun $krep_a1NR $krep_a1NV
$krep_a1NX [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepFun $krep_a1NY $krep_a1NZ
$krep_a1NO [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepFun GHC.Types.krep$* $krep_a1NP
$krep_a1NR [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepFun $krep_a1NS $krep_a1NU
$krep_a1NY [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepFun $krep_a1NS $krep_a1NW
$krep_a1NS [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepTyConApp GHC.Types.$tc[] ((:) $krep_a1NT [])
$krep_a1NP [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepTyConApp GHC.Types.$tcConstraint []
$krep_a1NT [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepTyConApp GHC.Types.$tcChar []
$krep_a1NZ [InlPrag=NOUSERINLINE[~]]
  = GHC.Types.KindRepTyConApp Main.$tcInteractive ((:) $krep_a1NU [])
Main.$trModule
  = GHC.Types.Module
      (GHC.Types.TrNameS "main"#) (GHC.Types.TrNameS "Main"#)
main = print (toInteractive "1" :: Int)
$dInteractive_a1Bm
  = Main.C:Interactive
      $ctoInteractive_a1ji $cfromInteractive_a1AW $cdoSomething_a1B2
toInteractive_a1jk = read
fromInteractive_a1AY = show
doSomething_a1B4 a_a1bi b_a1bj = show (read a_a1bi + b_a1bj)
:Main.main = GHC.TopHandler.runMainIO main


==================== Desugar (after optimization) ====================
Result size of Desugar (after optimization)
  = {terms: 108, types: 45, coercions: 0, joins: 0/0}

-- RHS size: {terms: 10, types: 5, coercions: 0, joins: 0/0}
$cdoSomething_a1B1 :: String -> Int -> String
[LclId]
$cdoSomething_a1B1
  = \ (a_a1be :: String) (b_a1bf :: Int) ->
      show
        @ Int
        GHC.Show.$fShowInt
        (+ @ Int
           GHC.Num.$fNumInt
           (read @ Int GHC.Read.$fReadInt a_a1be)
           b_a1bf)

-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
$cfromInteractive_a1AV :: Int -> String
[LclId]
$cfromInteractive_a1AV = show @ Int GHC.Show.$fShowInt

-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
$ctoInteractive_a1jh :: String -> Int
[LclId]
$ctoInteractive_a1jh = read @ Int GHC.Read.$fReadInt

-- RHS size: {terms: 4, types: 1, coercions: 0, joins: 0/0}
Main.$fInteractiveInt [InlPrag=NOUSERINLINE CONLIKE]
  :: Interactive Int
[LclIdX[DFunId],
 Unf=DFun: \ ->
       Main.C:Interactive TYPE: Int
                          $ctoInteractive_a1jh
                          $cfromInteractive_a1AV
                          $cdoSomething_a1B1]
Main.$fInteractiveInt
  = Main.C:Interactive
      @ Int
      $ctoInteractive_a1jh
      $cfromInteractive_a1AV
      $cdoSomething_a1B1

-- RHS size: {terms: 6, types: 2, coercions: 0, joins: 0/0}
main :: IO ()
[LclIdX]
main
  = print
      @ Int
      GHC.Show.$fShowInt
      (toInteractive
         @ Int Main.$fInteractiveInt (GHC.CString.unpackCString# "1"#))

-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
:Main.main :: IO ()
[LclIdX]
:Main.main = GHC.TopHandler.runMainIO @ () main

-- RHS size: {terms: 5, types: 0, coercions: 0, joins: 0/0}
Main.$trModule :: GHC.Types.Module
[LclIdX]
Main.$trModule
  = GHC.Types.Module
      (GHC.Types.TrNameS "main"#) (GHC.Types.TrNameS "Main"#)

-- RHS size: {terms: 3, types: 1, coercions: 0, joins: 0/0}
$krep_a1NT [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NT
  = GHC.Types.KindRepTyConApp
      GHC.Types.$tcChar (GHC.Types.[] @ GHC.Types.KindRep)

-- RHS size: {terms: 3, types: 1, coercions: 0, joins: 0/0}
$krep_a1NP [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NP
  = GHC.Types.KindRepTyConApp
      GHC.Types.$tcConstraint (GHC.Types.[] @ GHC.Types.KindRep)

-- RHS size: {terms: 5, types: 2, coercions: 0, joins: 0/0}
$krep_a1NS [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NS
  = GHC.Types.KindRepTyConApp
      GHC.Types.$tc[]
      (GHC.Types.:
         @ GHC.Types.KindRep $krep_a1NT (GHC.Types.[] @ GHC.Types.KindRep))

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NO [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NO = GHC.Types.KindRepFun GHC.Types.krep$* $krep_a1NP

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NU [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NU = GHC.Types.$WKindRepVar (GHC.Types.I# 0#)

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NW [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NW = GHC.Types.KindRepFun $krep_a1NU $krep_a1NS

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NY [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NY = GHC.Types.KindRepFun $krep_a1NS $krep_a1NW

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NR [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NR = GHC.Types.KindRepFun $krep_a1NS $krep_a1NU

-- RHS size: {terms: 8, types: 0, coercions: 0, joins: 0/0}
Main.$tcInteractive :: GHC.Types.TyCon
[LclIdX]
Main.$tcInteractive
  = GHC.Types.TyCon
      14397081508441979267##
      10936885658591672495##
      Main.$trModule
      (GHC.Types.TrNameS "Interactive"#)
      0#
      $krep_a1NO

-- RHS size: {terms: 5, types: 2, coercions: 0, joins: 0/0}
$krep_a1NZ [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NZ
  = GHC.Types.KindRepTyConApp
      Main.$tcInteractive
      (GHC.Types.:
         @ GHC.Types.KindRep $krep_a1NU (GHC.Types.[] @ GHC.Types.KindRep))

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NX [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NX = GHC.Types.KindRepFun $krep_a1NY $krep_a1NZ

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NV [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NV = GHC.Types.KindRepFun $krep_a1NW $krep_a1NX

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
$krep_a1NQ [InlPrag=NOUSERINLINE[~]] :: GHC.Types.KindRep
[LclId]
$krep_a1NQ = GHC.Types.KindRepFun $krep_a1NR $krep_a1NV

-- RHS size: {terms: 8, types: 0, coercions: 0, joins: 0/0}
Main.$tc'C:Interactive :: GHC.Types.TyCon
[LclIdX]
Main.$tc'C:Interactive
  = GHC.Types.TyCon
      6110756370800370824##
      1740726806081577955##
      Main.$trModule
      (GHC.Types.TrNameS "'C:Interactive"#)
      1#
      $krep_a1NQ

[1] https://wiki.haskell.org/GHC/As_a_library#Another_example
[2] https://gitlab.haskell.org/ghc/ghc/wikis/commentary/compiler/hsc-main

@swamp-agr
Copy link
Contributor

swamp-agr commented May 2, 2019

From desugarring step the most valuable part is instance Interactive Int:

-- RHS size: {terms: 4, types: 1, coercions: 0, joins: 0/0}
Main.$fInteractiveInt [InlPrag=NOUSERINLINE CONLIKE]
  :: Interactive Int
[LclIdX[DFunId],
 Unf=DFun: \ ->
       Main.C:Interactive TYPE: Int
                          $ctoInteractive_a1jh
                          $cfromInteractive_a1AV
                          $cdoSomething_a1B1]
Main.$fInteractiveInt
  = Main.C:Interactive
      @ Int
      $ctoInteractive_a1jh
      $cfromInteractive_a1AV
      $cdoSomething_a1B1

as it contained exact methods for type Int that should be somehow passed to Fay.Compiler.

There are two ways: either to typecheck only and to deal with Bag of items, or to desugar TypecheckedSource in advance and to deal with Core [3].

[3] https://gitlab.haskell.org/ghc/ghc/blob/master/compiler/deSugar/Desugar.hs#L271-273

@swamp-agr
Copy link
Contributor

swamp-agr commented May 3, 2019

With given modified example from wiki [1]

withGhc act = do
  res <- act
  runGhc (Just libdir) $ do
    dflags <- getSessionDynFlags
    return $ (dflags, res)

example = 
    defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
      runGhc (Just libdir) $ do
        dflags <- getSessionDynFlags
        let dflags' = foldl xopt_set dflags
                            []
        setSessionDynFlags dflags'
        target <- guessTarget targetFile Nothing
        setTargets [target]
        load LoadAllTargets
        modSum <- getModSummary $ mkModuleName "Main"
        p <- parseModule modSum
        t <- typecheckModule p
        d <- desugarModule t
        l <- loadModule d
        n <- getNamesInScope
        c <- return $ coreModule d
 
        g <- getModuleGraph
        -- mapM showModule g     
        return $ (parsedSource d,"/n-----/n",  typecheckedSource d)

...and Main.hs from previous comments, I obtained the access to typechecker's intermediate representation of AbsBinds (items from the Bag).

*Main> (flags, res) <- withGhc example
*Main> let (ps, _, ts) = res
Prelude> :m Bag HsBinds GHC Outputable Data.Data SrcLoc
Prelude Bag HsBinds GHC Outputable Data.Data SrcLoc> let lts = bagToList ts
Prelude Bag HsBinds GHC Outputable Data.Data SrcLoc> mapM_ (putStrLn . show . toConstr . unLoc) lts
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
VarBind
AbsBinds
AbsBinds
AbsBinds
AbsBinds
AbsBinds
VarBind
Prelude Bag HsBinds GHC Outputable Data.Data SrcLoc> let abslts = filter ((=="AbsBinds") . show . toConstr . unLoc) lts
Prelude Bag HsBinds GHC Outputable Data.Data SrcLoc> (showSDoc flags . ppr) <$> (concat ((bagToList . abs_binds . unLoc) <$> abslts))
["main = print (toInteractive \"1\" :: Int)","$dInteractive_a10nl\n  = C:Interactive $ctoInteractive $cfromInteractive $cdoSomething","toInteractive = read","fromInteractive = show","doSomething a b = show (read a + b)"]

However, top Bag contained few singleton Bags inside with only FunBind element.

I am going to spend some time with these new concepts to make them familiar to me.

@swamp-agr
Copy link
Contributor

Instead, with Core the same info could be much easily received via ModGuts [4].

Prelude Main GHC Outputable HscTypes> :t dm
dm :: DesugaredModule
Prelude Main GHC Outputable HscTypes> mapM_ (putStrLn . showSDoc flags . ppr) $ mg_tcs $ dm_core_module dm
Interactive
Prelude Main GHC Outputable HscTypes> mapM_ (putStrLn . showSDoc flags . ppr) $ mg_insts $ dm_core_module dm
instance [safe] Interactive Int -- Defined at Main.hs:13:10
Prelude Main GHC Outputable HscTypes> putStrLn . showSDoc flags . ppr $ mg_inst_env $ dm_core_module dm
[r14ss :-> instance Interactive Int -- Defined at Main.hs:13:10]
Prelude Main GHC Outputable HscTypes> putStrLn . showSDoc flags . ppr $ mg_binds $ dm_core_module dm
[$cdoSomething :: String -> Int -> String
 [LclId]
 $cdoSomething
   = \ (a :: String) (b :: Int) ->
       show @ Int $fShowInt (+ @ Int $fNumInt (read @ Int $fReadInt a) b),
 $cfromInteractive :: Int -> String
 [LclId]
 $cfromInteractive = show @ Int $fShowInt,
 $ctoInteractive :: String -> Int
 [LclId]
 $ctoInteractive = read @ Int $fReadInt,
 $fInteractiveInt [InlPrag=NOUSERINLINE CONLIKE] :: Interactive Int
 [LclIdX[DFunId],
  Unf=DFun: \ ->
        C:Interactive TYPE: Int
                      $ctoInteractive
                      $cfromInteractive
                      $cdoSomething]
 $fInteractiveInt
   = C:Interactive
       @ Int $ctoInteractive $cfromInteractive $cdoSomething,
 main :: IO ()
 [LclIdX]
 main
   = print
       @ Int
       $fShowInt
       (toInteractive @ Int $fInteractiveInt (unpackCString# "1"#)),
 main :: IO ()
 [LclIdX]
 main = runMainIO @ () main,
 $trModule :: Module
 [LclIdX]
 $trModule = Module (TrNameS "main"#) (TrNameS "Main"#),
 $krep_a16gq [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gq = KindRepTyConApp $tcChar ([] @ KindRep),
 $krep_a16gm [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gm = KindRepTyConApp $tcConstraint ([] @ KindRep),
 $krep_a16gp [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gp
   = KindRepTyConApp $tc[] (: @ KindRep $krep_a16gq ([] @ KindRep)),
 $krep_a16gl [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gl = KindRepFun krep$* $krep_a16gm,
 $krep_a16gr [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gr = $WKindRepVar (I# 0#),
 $krep_a16gt [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gt = KindRepFun $krep_a16gr $krep_a16gp,
 $krep_a16gv [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gv = KindRepFun $krep_a16gp $krep_a16gt,
 $krep_a16go [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16go = KindRepFun $krep_a16gp $krep_a16gr,
 $tcInteractive :: TyCon
 [LclIdX]
 $tcInteractive
   = TyCon
       14397081508441979267##
       10936885658591672495##
       $trModule
       (TrNameS "Interactive"#)
       0#
       $krep_a16gl,
 $krep_a16gw [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gw
   = KindRepTyConApp
       $tcInteractive (: @ KindRep $krep_a16gr ([] @ KindRep)),
 $krep_a16gu [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gu = KindRepFun $krep_a16gv $krep_a16gw,
 $krep_a16gs [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gs = KindRepFun $krep_a16gt $krep_a16gu,
 $krep_a16gn [InlPrag=NOUSERINLINE[~]] :: KindRep
 [LclId]
 $krep_a16gn = KindRepFun $krep_a16go $krep_a16gs,
 $tc'C:Interactive :: TyCon
 [LclIdX]
 $tc'C:Interactive
   = TyCon
       6110756370800370824##
       1740726806081577955##
       $trModule
       (TrNameS "'C:Interactive"#)
       1#
       $krep_a16gn]

[4] https://downloads.haskell.org/~ghc/8.6.3/docs/html/libraries/ghc-8.6.3/HscTypes.html#t:ModGuts

@swamp-agr
Copy link
Contributor

swamp-agr commented May 14, 2019

I spent some time trying to realise, how to deal with Compile a and what is going on under the hood of Fay. And it was quite hard. Instead, I will use Language.Haskell.Exts to understand sunny day scenario and then move to the case above, which by the way could be represented in terms of haskell-src-exts as (without annoying SrcSpanInfo's):

Module  (Just (ModuleHead  (ModuleName  "Main") Nothing Nothing)) [] [ImportDecl {importAnn = SrcSpanInfo {srcInfoSpan = SrcSpan "..." 4 1 4 15,
 srcInfoPoints = [SrcSpan "..." 4 1 4 7]},
 importModule = ModuleName  "Prelude",
 importQualified = False,
 importSrc = False,
 importSafe = False,
 importPkg = Nothing,
 importAs = Nothing,
 importSpecs = Nothing}]

[ PatBind  (PVar  (Ident  "main")) (UnGuardedRhs  (App  (Var  (UnQual  (Ident  "print"))) (Paren  (ExpTypeSig  (App  (Var  (UnQual  (Ident  "doSomething"))) (Paren  (NegApp  (Lit  (Int  1 "1"))))) (TyCon  (UnQual  (Ident  "Int"))))))) Nothing
, ClassDecl  Nothing (DHApp  (DHead  (Ident  "Interactive")) (UnkindedVar  (Ident  "a"))) [] (Just [ClsDecl  (TypeSig  [Ident  "doSomething"] (TyFun  (TyVar  (Ident  "a")) (TyVar  (Ident  "a"))))])
, InstDecl  Nothing (IRule  Nothing Nothing (IHApp  (IHCon  (UnQual  (Ident  "Interactive"))) (TyCon  (UnQual  (Ident  "Int"))))) (Just [InsDecl  (FunBind  [Match  (Ident  "doSomething") [PVar  (Ident  "a")] (UnGuardedRhs  (App  (Var  (UnQual  (Ident  "abs"))) (Var  (UnQual  (Ident  "a"))))) Nothing])])
]

@swamp-agr
Copy link
Contributor

swamp-agr commented May 17, 2019

As it was described here six years ago, ghc-mod contained interesting function, which could be useful for type resolution based on TypechedSource and SrcSpan of tricky type class function in compiled source code. I will give it a chance to reproduce Chris's experiments "to start feel better" with AST, but will not proceed with its usage, since it definitely would be a subject of License changing from BSD-3 to AGPL 3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants