GHC Contributors’ Workshop
Sam Derbyshire, Well-Typed
June 7th, 2023
COMPLETE
sets of pattern synonyms and
do
notation).⭲
⭲
There are many ways that GHC can refer to an identifier depending on how much it knows about it.
OccName
Name
RdrName
GlobalRdrElt
Var
, TyVar
, Id
⭲
OccName
: occurrences with a NameSpace
Name
: unique identifiersRdrName
: umbrella datatypeVar
and Id
: variablesdata Var -- slightly abridged
= TyVar { varName :: Name
, varType :: Kind }
| TcTyVar { varName :: Name
, varType :: Kind
, tc_tv_details :: TcTyVarDetails }
| Id { varName :: Name
, varType :: Type
, varMult :: Mult
, idScope :: IdScope
, id_details :: IdDetails
, id_info :: IdInfo
}
data IdScope = GlobalId | LocalId ExportFlag
data ExportFlag = NotExported | Exported
data IdDetails = VanillaId | RecSelId {} | PrimOpId {} | CoVarId {} | ...
type TyVar = Var
type Id = Var
Name
s: TyThing
and
GREInfo
GlobalRdrElt
and the GlobalRdrEnv
The renamer primarily deals with GlobalRdrElt
, which
consists of a Name
, information about how it’s in scope in
the renamer, and additional information that the renamer might need to
know.
TcRn
monadRenaming and typechecking happens in a shared monad, TcM
(also called TcRn
or RnM
).
This is ReaderT
over IO
, with access
to:
HscEnv
–
per-module options (e.g. flags passed to GHC) and environmentUnitEnv
,
currently loaded modules;TcGblEnv
–
generated during typechecking and passed onTypeEnv
,
InstEnv
, GlobalRdrEnv
;TcLclEnv
–
changes as we move inside expressionsSrcSpan
,
TcLevel
, LocalRdrEnv
.
⭲
Start by looking at rnExpr (RecordUpd {..})
:
After handling duplicates, rnHsRecUpdFields
starts by
calling lookupRecUpdFields
to look up each field
individually.
We retrieve GlobalRdrElt
s for each record field.
These have GREInfo
s which specify which constructors have
that field.
We can use that to disambiguate.
⭲
Lookup:
[(x, [MkS1, MkS2, MkT1]), (y, [MkS1, MkS2, MkT2])]
.
Intersect all the possible data constructors:
[MkS1, MkS2]
.
Take parents (removing duplicates): [S]
.
There is a single parent: the record update is unambiguous!
⭲
We start off by lexing. See GHC.Parser.Lexer.x
:
@varid = $small $idchar* -- variable identifiers
@conid = $large $idchar* -- constructor identifiers
@varsym = ($symbol # \:) $symbol* -- variable (operator) symbol
@consym = \: $symbol* -- constructor (operator) symbol
$small = [a-z \_]
$large = [A-Z]
$symbol = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:]
$idchar = [$small $large $digit \']
⭲
Then parsing, in GHC.Parser.y
.
RdrName
.
mkQual
/mkUnqual
depending on
qualification.
NameSpace
using context (e.g. whether we are
parsing a term or a type).
Parse this as a type first. Then, after properly associating using
the fixities, we find that :+:
should be namespaced as a
data constructor, and the others remain type constructors.
GHC.Parser.PostProcess
.
⭲
The main entry point is
GHC.Tc.Module.tcRnModuleTcRnM
.
tcRnImports
.
tcRnSrcDecls
.
rnTopSrcDecls
.
tcTopSrcDecls
.
rnExportList
. This allows us to
assemble a final TcGblEnv
which contains everything
provided by the module.
Assemble the final typechecked module, to be passed onto the next
stage of the compiler pipeline. Everything is extracted from the
TcGblEnv
.
⭲
Entry point: GHC.Rename.Names.rnImportDecl
.
filterImports
.
import M( A(x, ..), B(..) )
import M hiding ( .. )
Works the same, except now we filter out instead.
Add all the imported identifiers to the GlobalRdrEnv
. We
will look up in this environment when renaming the body of the
module.
⭲
The main entry point to renaming local declarations is
GHC.Rename.Module.rnSrcDecls
. Control flow:
Name
s for all binders.
getLocalNonValBinders
.
extendPatSynEnv
.
Name
s and rename the LHS of top-level value
bindings (rnTopBindsLHS
).
⤞
rnTyClDecls
.
rnValBindsRHS
.
RULES
, foreign import/exports, default
declarations…
⭲
rnTyClDecls
- renames all types/classes defined in the
module - uses this information to compute dependency groups
(strongly-connected components).
rnTyClDecls :: [TyClGroup GhcPs] -> RnM ([TyClGroup GhcRn], FreeVars)
rnTyClDecls tycl_ds =
do { tycls_w_fvs <- mapM rnTyClDecl (tyClGroupTyClDecls tycl_ds)
; kisigs_w_fvs <- rnStandaloneKindSigs (tyClGroupKindSigs tycl_ds)
; instds_w_fvs <- mapM rnSrcInstDecl (tyClGroupInstDecls tycl_ds)
; let tycl_sccs = depAnalTyClDecls kisig_fv_env tycls_w_fvs
; .. }
See Note [Dependency analysis of type, class, and instance decls] in
GHC.Rename.Module
.
⭲
rnValBindsRHS
- renames all value bindings - performs
dependency analysis
Slides available online: sheaf.github.io/ghc-renamer.