Re-entrant TcRnIf

Thomas Schilling nominolo at
Tue Jun 11 13:46:20 CEST 2013

There are quite a lot of dependencies between different parts of the AST.

The renamer takes the whole parser output and then discovers its
dependencies.  After that you can split things into smaller units
based on this dependency graph.

The renamer and type checker do not necessarily need to be
interleaved.  Every Haskell file is de-facto split apart after each
top-level TH splice.

If I understand you correctly you want to build some IDE functionality
that only recompiles the parts that changed.  You can do that
currently (crudely) by splitting the file into three parts based on
the dependency graph that the renamer discovered:

 1. Everything upstream of the focused definition, i.e., everything
that does not depend on the focused definition.
 2. The focused definition and everything that is in its recursive group.
 3. Everything downstream of the focused, i.e., everything that
directly or indirectly depends on the focused definition.

You can put each part into a separate file and only recompile part 2.
Of course you also need to detect when new (renamer) dependencies are
formed as that will change the split between parts 1, 2, and 3.

Let me know if you need more details on this approach.

 / Thomas

On 11 June 2013 11:55,  <p.k.f.holzenspies at> wrote:
> Dear GHC-ers,
> The current API *seems* to assume that all different stages of the compiler pipeline are always passed successively (with the exception of the interleaving of the renamer and the type checker for the sake of Template Haskell), in other words, it is assumed all parsing has been done once we start renaming and that when we desugar the AST, we can through out all type checker state. I'm working on an interactive environment (different in many ways from ghci), in which I would like to incrementally parse a statement, rename it and type check it, after which I may chose to wash, rinse and repeat.
> This is somewhat problematic in the renamer (at least; this is how far I have come), at the very least with regards to the unique source and the provenance of things. What I'm hoping to do is to generalize the monads in the GHC API to some class, along these lines:
> class Generalizes m n where
>   glift :: n a -> m a
> class (GhcMonad m, Generalizes m TcRnIf, Generalizes m CoreM, ...) => GHCAPI m
> What such a monad needs is to be able to evaluate some function in (for example) the renamer monad, extract the part of the renamer state that needs to persist and store that for whenever another renamer function is evaluated. One such thing would be the supply of unique names.
> I tried simply carrying over everything in the Env, except the env_top (HscEnv), but this broke things. Upon inspection of the TcGblEnv and TcLclEnv, this seems logical, considering they are dependent on the HscEnv (at least in terms of tcg_type_env_var, but there may be other dependencies I've not spotted). The thing that seems to bite me is the assumption that the top-level environment is assumed to be fixed [1]. In my scenario, this assumption does not hold.
> Concretely:
> 1) Do ways exist to carry over the part of the TcRnMonad state that is required to restart the renamer / type checker / etc later on?
> 2) If not, what parts of the Env, TcGblEnv and TcLclEnv should I copy over to the new state, assuming the HscEnv changed between consecutive runs?
> 3) Is there a particular reason why the front-end (of the front-end) is defined in an overloaded monad (GhcMonad) and the later bits all take concrete monads (TcRnIf etc.)?
> Regards,
> Philip
> [1]
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at

More information about the Glasgow-haskell-users mailing list