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:
- Type-classes.
- Name resolution.
- 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.
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:
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: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:
That seems to be pretty much everything that we need.
I've also noticed in the ghc-mod package this code:
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.