Chapter 2

The renamer

How every occurrence gets tied to the thing it names, and how the phase that is supposedly "just name resolution" ends up re-associating your operators and quietly desugaring half of Haskell's syntactic sugar.

Where this lives in the tree

The parser handed over a tree in which every identifier is still just text. map is the string “map”; whether that means Prelude.map, a local binding, or nothing at all is an open question. The renamer answers it, for every occurrence in the module.

That sounds mechanical, and the first half of it is. The interesting part is what else GHC decided to put here: because the renamer is the first phase that knows what names mean, several problems that look like they belong elsewhere can only be solved once, right here.

RdrName becomes Name

The input side is RdrName, which is simply what the user wrote:

data RdrName
  = Unqual OccName        -- ^ Unqualified name, e.g. @x@, @y@ or @Foo@
  | Qual ModuleName OccName
  | Orig Module OccName
  | Exact Name

An OccName is a string plus a namespace: Haskell lets you use the same spelling for a variable, a type constructor, and a data constructor without collision, so “which namespace” is part of the name itself.

The output side is Name:

data Name = Name
  { n_sort :: NameSort   -- ^ external, internal, system, wired-in
  , n_occ  :: OccName    -- ^ its occurrence name
  , n_uniq :: {-# UNPACK #-} !Unique
  }

The Unique is what makes the rest of the compiler work. After renaming, two Names refer to the same entity exactly when their uniques are equal: no string comparison, no scope walking, no ambiguity. Every later phase relies on this.

Two environments drive the translation:

data LocalRdrEnv = LRE { lre_env :: OccEnv Name, ... }

type GlobalRdrEnv = GlobalRdrEnvX GREInfo
type GlobalRdrEnvX info = OccEnv [GlobalRdrEltX info]

Note the asymmetry. The local environment maps an OccName to one Name: lexical scoping means the innermost binding wins and shadowing is resolved by construction. The global environment maps to a list, because a name can legitimately be in scope from several imports at once. That is not an error until someone actually uses it ambiguously, and it is why GHC can tell you an occurrence is ambiguous while pointing at every import responsible.

It runs in the typechecker’s monad

type RnM = TcRn

The renamer does not have a monad of its own. RnM is a synonym for the typechecker’s TcRn, and the two phases share their environment type. This is not an accident of history: renaming and typechecking are interleaved at the top level, because Template Haskell splices must be renamed, typechecked, run, and the results renamed again before the surrounding module can be finished.

The practical consequence for reading the code: you will see the renamer calling things that look like typechecker utilities, and the shared TcGblEnv threading through both. That is by design, not layering violation.

Fixity: the loose end from the parser

The parser chapter ended with x |+| y * 2 sitting in the tree as a flat chain, because the parser cannot know any operator’s fixity. The renamer can (it has just resolved those operators to Names, so it can look up their declared fixity), and so it re-associates the tree here:

mkOpAppRn :: NegationHandling
          -> LHsExpr GhcRn             -- Left operand; already rearranged
          -> LHsExpr GhcRn -> Fixity   -- Operator and fixity
          -> LHsExpr GhcRn             -- Right operand
          -> RnM (HsExpr GhcRn)

-- (e1a `op1` e1b) `op2` e2
mkOpAppRn negation_handling e1@(L _ (OpApp fix1 e1a op1 e1b)) op2 fix2 e2
  | nofix_error
  = do precParseErr (get_op op1,fix1) (get_op op2,fix2)
       return (OpApp fix2 e1 op2 e2)

  | associate_right = do
    new_e <- mkOpAppRn negation_handling e1b op2 fix2 e2
    return (OpApp fix1 e1a op1 (L loc' new_e))
  where
    (nofix_error, associate_right) = compareFixity fix1 fix2

Three outcomes, and the middle one is the one people forget exists: two operators of equal precedence and incompatible associativity is a parse error, reported here rather than by the parser. compareFixity returns exactly that flag.

There is a matching mkHsOpTyRn for types, because type-level operators need the same treatment. And fixity lookup itself has a wrinkle worth seeing, since a fixity declaration does not say which namespace it means:

Note [Fixity signature lookup] GHC/Rename/Fixity.hs:45
A fixity declaration like

    infixr 2 ?

can refer to a value-level operator, e.g.:

    (?) :: String -> String -> String

or a type-level operator, like:

    data (?) a b = A a | B b

so we extend the lookup of the reader name '?' to the TcClsName namespace, as
well as the original namespace.

The extended lookup is also used in other places, like resolution of
deprecation declarations, and lookup of names in GHCi.

The renamer desugars

Here is the part that surprises people. The renamer does not merely resolve names; for overloaded and rebindable constructs it rewrites the tree into something else entirely, before the typechecker ever sees it.

Note [Handling overloaded and rebindable constructs] GHC/Rename/Expr.hs:90
Nomenclature

* Expansion (`HsExpr GhcRn -> HsExpr GhcRn`): expand between renaming and
  typechecking, using the `XXExprGhcRn` constructor of `HsExpr`.
* Desugaring (`HsExpr GhcTc -> Core.Expr`): convert the typechecked `HsSyn` to Core.  This is done in GHC.HsToCore


For overloaded constructs (overloaded literals, lists, strings), and
rebindable constructs (e.g. if-then-else), our general plan is this,
using overloaded labels #foo as an example:

* In the RENAMER: transform
      HsOverLabel "foo"
      ==> XExpr (ExpandedThingRn (HsOverLabel #foo)
                                 (fromLabel `HsAppType` "foo"))
  We write this more compactly in concrete-syntax form like this
      #foo  ==>  fromLabel @"foo"

  Recall that in (ExpandedThingRn orig expanded), 'orig' is the original term
  the user wrote, and 'expanded' is the expanded or desugared version
  to be typechecked.

* In the TYPECHECKER: typecheck the expansion, in this case
      fromLabel @"foo"
  The typechecker (and desugarer) will never see HsOverLabel

In effect, the renamer does a bit of desugaring. Recall GHC.Hs.Expr
Note [Rebindable syntax and XXExprGhcRn], which describes the use of XXExprGhcRn.

RebindableSyntax:
  If RebindableSyntax is off we use the built-in 'fromLabel', defined in
     GHC.Builtin.Names.fromLabelClassOpName
  If RebindableSyntax if ON, we look up "fromLabel" in the environment
     to get whichever one is in scope.
This is accomplished by lookupSyntaxName, and it applies to all the
constructs below.

See also Note [Handling overloaded and rebindable patterns] in GHC.Rename.Pat
for the story with patterns.
Show the rest of this Note (68 more lines)
Here are the expressions that we transform in this way. Some are uniform,
but several have a little bit of special treatment:

* HsIf (if-the-else)
     if b then e1 else e2  ==>  ifThenElse b e1 e2
  We do this /only/ if rebindable syntax is on, because the coverage
  checker looks for HsIf (see GHC.HsToCore.Ticks.addTickHsExpr)
  That means the typechecker and desugarer need to understand HsIf
  for the non-rebindable-syntax case.

* OverLabel (overloaded labels, #lbl)
     #lbl  ==>  fromLabel @"lbl"
  As ever, we use lookupSyntaxName to look up 'fromLabel'
  See Note [Overloaded labels] below

* ExplicitList (explicit lists [a,b,c])
  When (and only when) OverloadedLists is on
     [e1,e2]  ==>  fromListN 2 [e1,e2]
  NB: the type checker and desugarer still see ExplicitList,
      but to them it always means the built-in lists.

* SectionL and SectionR (left and right sections)
     (`op` e) ==> rightSection op e
     (e `op`) ==> leftSection  (op e)
  where `leftSection` and `rightSection` are representation-polymorphic
  wired-in Ids. See Note [Left and right sections]

* To understand why expansions for `OpApp` is done in `GHC.Tc.Gen.Head.splitHsApps`
  see Note [Doing XXExprGhcRn in the Renamer vs Typechecker] below.

* RecordUpd: we desugar record updates into case expressions,
  in GHC.Tc.Gen.Expr.tcExpr.

  Example:

    data T p q = T1 { x :: Int, y :: Bool, z :: Char }
               | T2 { v :: Char }
               | T3 { x :: Int }
               | T4 { p :: Float, y :: Bool, x :: Int }
               | T5

    e { x=e1, y=e2 }
      ===>
    let { x' = e1; y' = e2 } in
    case e of
       T1 _ _ z -> T1 x' y' z
       T4 p _ _ -> T4 p y' x'

  See Note [Record Updates] in GHC.Tc.Gen.Expr for more details.

  To understand Why is this done in the typechecker, and not in the renamer
  see Note [Doing XXExprGhcRn in the Renamer vs Typechecker]

* HsDo: We expand `HsDo` statements in `Ghc.Tc.Gen.Do`.

    - For example, a user written code:

                  do { x <- e1 ; g x ; return (f x) }

      is expanded to:

                   (>>=) e1
                         (\x -> ((>>) (g x)
                                      (return (f x))))

     See Note [Expanding HsDo with XXExprGhcRn] in `Ghc.Tc.Gen.Do` for more details.
     To understand why is this done in the typechecker and not in the renamer.
     See Note [Doing XXExprGhcRn in the Renamer vs Typechecker]

Read the nomenclature at the top carefully, because GHC is precise about it: expansion is HsExpr GhcRn -> HsExpr GhcRn and happens here; desugaring is HsExpr GhcTc -> Core.Expr and happens much later. The Note’s own summary, “in effect, the renamer does a bit of desugaring”, is the honest description.

The reason this must happen at renaming time rather than later is RebindableSyntax. With the extension off, #foo expands using the built-in fromLabel. With it on, it expands using whatever fromLabel is in scope. Only the renamer knows what is in scope. By the time the typechecker runs, the question is already settled, and HsOverLabel no longer exists in the tree.

The ExpandedThingRn constructor keeps both halves (the original term the user wrote and the expansion to be typechecked) so error messages can still talk about the program you actually wrote rather than the one GHC rewrote it into.

Order out of a flat file

Haskell declarations may appear in any order and may be mutually recursive. The typechecker cannot exploit that: it needs to generalise a binding group before typechecking anything that uses it, so it needs the groups, in dependency order. Computing them requires knowing what refers to what. That, again, is something only the renamer knows.

So the renamer performs strongly-connected-component analysis over the declarations and hands the typechecker an ordered sequence of binding groups. Type and class declarations get their own analysis:

Note [Dependency analysis of type and class decls] GHC/Rename/Module.hs:1313
A TyClGroup represents a strongly connected component of type/class/instance
decls, together with the role annotations and standalone kind signatures for the
type/class declarations. The renamer uses strongly connected component analysis
to build these groups. We do this for a number of reasons:

* Improve kind error messages. Consider

     data T f a = MkT f a
     data S f a = MkS f (T f a)

  This has a kind error, but the error message is better if you
  check T first, (fixing its kind) and *then* S.  If you do kind
  inference together, you might get an error reported in S, which
  is jolly confusing.  See #4875

* Increase kind polymorphism.  See GHC.Tc.TyCl
  Note [Grouping of type and class declarations]

What about instances? Based on a number of tickets (#12088, #12239, #14668,
#15561, #16410, #16448, #16693, #19611, #20875, #21172, #22257, #25238, #25834,
etc) we concluded that we cannot handle them at this stage.
Show the rest of this Note (139 more lines)
It is not possible, by looking at the free variables of a declaration, to
determine which instances a declaration depends on; furthermore, it is not
possible to discover dependencies between instances, for the same reason.

Previously GHC inserted instances at the earliest positions where their FVs are
bound, but it only helped with a subset of tickets. The current approach is to
accept that the dependency analysis here is incomplete and recover in the kind
checker with a retrying mechanism. See Note [Retrying TyClGroups] in GHC.Tc.TyCl


So much for why we want SCCs.  What about how and when we construct them?

First, an overview:
  (TCDEP1) Flatten TyClGroups from the parser
  (TCDEP2) Rename the type/class declarations, standalone kind signatures, role
           declarations, and instances individually
  (TCDEP3) Preprocess FVs and build a dependency graph
  (TCDEP4) Find strongly connected components (SCCs) of declarations
  (TCDEP5) Attach roles and kind signatures to the appropriate SCC
  (TCDEP6) Create one singleton "SCC" per instance and put them at the end

And now the deep dive:

(TCDEP1) We start with a `HsGroup GhcPs`, containing a `[TyClGroup GhcPs]`:
  a big pile of declarations. It is not important how the parser distributes
  declarations across those TyClGroups, as the first thing we do in `rnTyClDecls`
  is flatten them using a few helpers:

    tyClGroupTyClDecls = Data.List.concatMap group_tyclds
    tyClGroupInstDecls = Data.List.concatMap group_instds
    tyClGroupRoleDecls = Data.List.concatMap group_roles
    tyClGroupKindSigs  = Data.List.concatMap group_kisigs

  In practice, the parser just puts all declarations in a single `TyClGroup`,
  so the `concatMap` is a no-op.

(TCDEP2) Rename each declaration separately, yielding the following lists
  in `rnTyClDecls`:

    tycls_w_fvs  :: [(LTyClDecl GhcRn, FreeVars)]
    instds_w_fvs :: [(LInstDecl GhcRn, FreeVars)]
    kisigs_w_fvs :: [(LStandaloneKindSig GhcRn, FreeVars)]
    role_annots  :: [LRoleAnnotDecl GhcRn]

  The `FreeVars` are the free type/data constructors of the decl. For example:

    type family F (a :: k)        -- FVs: {}
    data X = MkX Char (Maybe X)   -- FVs: {Char, Maybe, X}
    data Y = MkY X (Maybe Y)      -- FVs: {Maybe, Y, X}
    type instance F MkX = X       -- FVs: {F, MkX, X}
    type instance F MkY = Int     -- FVs: {F, MkY, Int}

(TCDEP3) Build a graph where each node is a `TyClDecl` keyed by its name, and
  its `FreeVars` give rise to edges. Happens in `depAnalTyClDecls`. Examples:

    data A x = MkA x       -- node `A`, edges: {}
    data B x = MkB (A x)   -- node `B`, edges: {B -> A}
    data C = MkC (B C)     -- node `C`, edges: {C -> B, C -> C}

  The `FreeVars` are not used "as is" to create the edges. They first undergo a
  few transformations.

  (TCDEP3.fvs_kisig) If a standalone kind signature is present, add its free
    variables to those of the declaration. Consider:

      data A = MkA
      data B = MkB

      type P :: A -> Type           -- sig  FVs: {A, Type}
      data P x = MkP (Proxy MkB)    -- decl FVs: {Proxy, MkB}

    By adding the sig and decl FVs together, we get {A, Type, Proxy, MkB}.
    Then proceed to the next step.

  (TCDEP3.fvs_parent) Replace any mention of a (promoted) data constructor
    with its parent TyCon. Consider the FVs from the previous step:

      the name set {A, Type, Proxy, MkB}
      turns into   {A, Type, Proxy, B}

    MkB does not get its own node in the graph, so an edge to it must actually
    point to B.

  (TCDEP3.fvs_nogbl) Filter out references to type constructors outside this
    `HsGroup`. They just clutter things up:

      the name set {A, Type, Proxy, B}
      turns into   {A, B}

  Note [Prepare TyClGroup FVs] describes these transformations in more detail.
  Back to our `P` example, the final nodes and edges are as follows:

      data A = MkA    -- node `A`, edges: {}
      data B = MkB    -- node `B`, edges: {}

      type P :: A -> Type
      data P x = MkP (Proxy MkB)  -- node `P`, edges: {P -> A, P -> B}

(TCDEP4) Find strongly connected components (SCCs) of `TyClDecl`s.
  This happens immediately after building the dependency graph in
  `depAnalTyClDecls`. As the result, in `rnTyClDecls` we get

    tycl_sccs :: [SCC (LTyClDecl GhcRn, NameSet)]

  These SCCs are topologically sorted, but only according to lexical
  dependencies (i.e. dependencies that can be found by looking at the FVs).
  Non-lexical dependencies (i.e. dependencies on instances) are ignored because
  they can't be reliably found prior to type checking.

  More on that in Note [Retrying TyClGroups] in GHC.Tc.TyCl.

(TCDEP5) For each SCC, create a `TyClGroup GhcRn`. Standalone kind signatures
  and role annotations are looked up by name and included in the same
  `TyClGroup` as the corresponding type/class declarations.

  The extension field `group_ext` of `TyClGroup GhcRn` contains the dependencies
  of the SCC computed from FVs in step (TCDEP3), but /excluding/ the type
  constructors bound by the group itself. Example:

     TyClGroup: binds {Z}
                depends on {}
     data Z = MkZ      -- FVs: {}

     TyClGroup: binds {X, Y}
                depends on {Z} rather than {X, Y, Z}
     data X = MkX Y Z  -- FVs: {Y, Z}
     data Y = MkY X Z  -- FVs: {X, Z}

  Reason: `isReadyTyClGroup` in GHC.Tc.TyCl is a function that checks whether
  all of a TyClGroup's dependencies are present in the type checking env, and we
  wouldn't want it to consider a group to be "blocked" on its own declarations.

(TCDEP6) For each instance, create a singleton `TyClGroup GhcRn`, and put them
  all at the end, where their lexical dependencies are surely satisfied.
  More on that in Note [Put instances at the end].

  The `group_ext` field in an instance TyClGroup is set to the FVs of the
  instance, preprocessed much in the same way as declaration FVs in step
  (TCDEP3). See Note [Prepare TyClGroup FVs] for details.

This is also where the unused-binding and unused-import warnings come from: the renamer is tracking free variables to do the dependency analysis anyway, so it already knows what was never mentioned.

Seeing it happen

The Renamed tab is this chapter’s output. Compare it with Parsed:

What you wrote.

-- | A deliberately small module aimed at the *front* of the pipeline.
--
-- The point of interest here is the parsed AST rather than the Core: layout
-- (no braces or semicolons are written, yet the parser inserts them),
-- operator sections, `do` notation, and an infix operator whose fixity is not
-- known until the renamer runs.
module Syntax where

infixl 6 |+|

(|+|) :: Int -> Int -> Int
x |+| y = x + y * 2

total :: [Int] -> Int
total xs = sum (map (|+| 1) xs)

greet :: Maybe String -> String
greet name = case name of
  Just n -> "hello, " ++ n
  Nothing -> "hello"

collect :: [Int] -> [Int]
collect xs = do
  x <- xs
  let doubled = x * 2
  pure doubled
The same module before and after renaming. Watch the operator chain acquire its grouping, and every name acquire a specific referent.

What the renamer hands on

HsGroup GhcRn: the same AST types as before, at the next phase index. Every RdrName is now a Name; operator applications are correctly grouped; overloaded constructs have been expanded; declarations arrive in dependency order.

What is not done: nothing has been type-checked. describe x = "value: " ++ show x has been fully resolved, and GHC still has no idea whether x has a Show instance. That question, and roughly eight hundred Notes’ worth of machinery for answering it, is the next chapter.

Reading the source yourself

  1. GHC/Types/Name/Reader.hs first, for RdrName, GlobalRdrEnv and GlobalRdrElt. The renamer is mostly operations on these; the rest reads far more easily once the data types are familiar.
  2. GHC/Rename/Env.hs: lookup, and where ambiguity and shadowing are actually decided.
  3. GHC/Rename/Expr.hs: start at the Note quoted above, then read rnExpr. The expansion machinery is the least obvious thing in the phase.

A good first contribution here is an error message. The renamer produces many of GHC’s most user-visible diagnostics (out-of-scope names, ambiguous occurrences, unused imports), and improving one is self-contained, testable with a single source file, and cannot break code generation.