|
|
CONVERSION ERROR
|
|
|
|
|
|
Error: HttpError (HttpExceptionRequest Request {
|
|
|
host = "ghc.haskell.org"
|
|
|
port = 443
|
|
|
secure = True
|
|
|
requestHeaders = []
|
|
|
path = "/trac/ghc/wiki/Commentary/Compiler/Renamer"
|
|
|
queryString = "?version=2"
|
|
|
method = "GET"
|
|
|
proxy = Nothing
|
|
|
rawBody = False
|
|
|
redirectCount = 10
|
|
|
responseTimeout = ResponseTimeoutDefault
|
|
|
requestVersion = HTTP/1.1
|
|
|
}
|
|
|
(StatusCodeException (Response {responseStatus = Status {statusCode = 403, statusMessage = "Forbidden"}, responseVersion = HTTP/1.1, responseHeaders = [("Date","Sun, 10 Mar 2019 06:54:55 GMT"),("Server","Apache/2.2.22 (Debian)"),("Strict-Transport-Security","max-age=63072000; includeSubDomains"),("Vary","Accept-Encoding"),("Content-Encoding","gzip"),("Content-Length","261"),("Content-Type","text/html; charset=iso-8859-1")], responseBody = (), responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}) "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>403 Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\n<p>You don't have permission to access /trac/ghc/wiki/Commentary/Compiler/Renamer\non this server.</p>\n<hr>\n<address>Apache/2.2.22 (Debian) Server at ghc.haskell.org Port 443</address>\n</body></html>\n"))
|
|
|
|
|
|
Original source:
|
|
|
|
|
|
```trac
|
|
|
[ Up: [wiki:Commentary/Compiler/HscMain] ]
|
|
|
|
|
|
= The renamer =
|
|
|
|
|
|
|
|
|
The renamer's Number One taks is to replace [wiki:Commentary/Compiler/RdrNameType RdrNames] with [wiki:Commentary/Compiler/NameType Names]. For example, consider
|
|
|
{{{
|
|
|
|
|
|
\[ Up: [Commentary/Compiler/HscMain](commentary/compiler/hsc-main) \]
|
|
|
|
|
|
# The renamer
|
|
|
|
|
|
|
|
|
The renamer's Number One task is to replace [RdrNames](commentary/compiler/rdr-name-type) with [Names](commentary/compiler/name-type). For example, consider
|
|
|
|
|
|
```wiki
|
|
|
module K where
|
|
|
f x = True
|
|
|
|
... | ... | @@ -35,23 +16,93 @@ module N where |
|
|
module M where
|
|
|
import N( f ) as Q
|
|
|
f = (f, M.f, Q.f, \f -> f)
|
|
|
}}}
|
|
|
(where all the variables are {{{RdrName}}}s). The result of renaming module M is:
|
|
|
{{{
|
|
|
```
|
|
|
|
|
|
|
|
|
(where all the variables are `RdrName`s). The result of renaming module M is:
|
|
|
|
|
|
```wiki
|
|
|
M.f = (M.f, M.f, K.f, \f_22 -> f_22)
|
|
|
}}}
|
|
|
where all these names are now {{{Name}}}s.
|
|
|
* The top-level unqualifed {{{RdrName}}} "{{{f}}}" has become the {{{External}}} {{{Name}}} {{{M.f}}}.
|
|
|
* The occurrences "{{{f}}}" and "{{{M.f}}}" are both bound to this {{{Name}}}.
|
|
|
* The qualified {{{RdrName}}} "{{{Q.f}}}" becomes the {{{Name}}} {{{K.f}}}, because the function is defined in module K.
|
|
|
* The lambda-bound "{{{f}}}" becomes an {{{Internal}}} name, here written {{{f_22}}}. (All the {{{External}}} names have uniques too, but we often do not print them.)
|
|
|
```
|
|
|
|
|
|
|
|
|
where all these names are now `Name`s.
|
|
|
|
|
|
- The top-level unqualifed `RdrName` "`f`" has become the `External``Name``M.f`.
|
|
|
- The occurrences "`f`" and "`M.f`" are both bound to this `Name`.
|
|
|
- The qualified `RdrName` "`Q.f`" becomes the `Name``K.f`, because the function is defined in module K.
|
|
|
- The lambda-bound "`f`" becomes an `Internal` name, here written `f_22`. (All the `External` names have uniques too, but we often do not print them.)
|
|
|
|
|
|
|
|
|
In addition, the renamer does the following things:
|
|
|
|
|
|
* Sort out fixities. The parser parses all infix applications as '''right-associative''', regardless of fixity. For example "{{{a * b + c}}}" is parsed as "{{{a * (b + c)}}}". The renamer re-associates such nested operator applications, using the fixities declared in the module.
|
|
|
- Sort out fixities. The parser parses all infix applications as **right-associative**, regardless of fixity. For example "`a * b + c`" is parsed as "`a * (b + c)`". The renamer re-associates such nested operator applications, using the fixities declared in the module.
|
|
|
|
|
|
- Dependency analysis for mutually-recursive groups of declarations. This divides the declarations into strongly-connected components.
|
|
|
|
|
|
- Lots of lexical error checking: variables out of scope, unused bindings, unused imports, patterns that use the same binder many times, etc.
|
|
|
|
|
|
|
|
|
The renamer sits between the parser and the typechecker. However, its operation is quite tightly interwoven with the typechecker. This is mainly due to support for Template Haskell, where spliced code has to be renamed and type checked. In particular, top-level splices lead to multiple rounds of renaming and type checking. It uses the \[wike:Commentary/Compiler/TcRnMonad same monad as the typechecker\].
|
|
|
|
|
|
## The global renamer environment, `GlobalRdrEnv`
|
|
|
|
|
|
|
|
|
A big part of the renamer's task is to build the **global rdr-env** for the module, of type `GlobalRdrEnv`. This environment allows us to take a qualified or un-qualified `RdrName` and figure out which `Name` it means. The global rdr-env is built by looking at all the imports, and the top-level declarations of the module.
|
|
|
|
|
|
|
|
|
You might think that the global rdr-env would be a mapping from `RdrName` to `Name`, but it isn't. Here is what it looks like, after at least three iterations (all in [compiler/basicTypes/RdrName.lhs](/trac/ghc/browser/ghc/compiler/basicTypes/RdrName.lhs)):
|
|
|
|
|
|
```wiki
|
|
|
type GlobalRdrEnv = OccEnv [GlobalRdrElt]
|
|
|
-- An (OccEnv a) is a mapping from OccName to a
|
|
|
|
|
|
* Dependency analysis for mutually-recursive groups of declarations. This divides the declarations into strongly-connected components.
|
|
|
data GlobalRdrElt = GRE { gre_name :: Name, gre_prov :: Provenance }
|
|
|
|
|
|
* Lots of lexical error checking: variables out of scope, unused bindings, unused imports, patterns that use the same binder many times, etc.
|
|
|
data Provenance = LocalDef | Imported [ImportSpec]
|
|
|
```
|
|
|
|
|
|
|
|
|
The environment maps an `OccName` to a list of all entities with that occurence name that are in scope (in any way). Each of these is represented by a `GlobalRdrElt`, which gives the entity's `Name` plus a specification of how it is in scope, its `Provenance`. Either it is in scope because it is defined in this module (`LocalDef`), or because it is imported. In the latter case, the `[ImportSpec]` describes all the import statements that bring it into scope. You can look in `RdrName.lhs` to see what an `ImportSpec` is, but among other things it says whether the import is qualified-only, and whether there is an "`as`" clause on the import statement.
|
|
|
|
|
|
|
|
|
With all that information, we can give good error messages, especially in the case where an occurrence "f" is ambiguous (i.e. different entities, both called "f", were imported by diffferent import statements).
|
|
|
|
|
|
|
|
|
The global rdr-env is created by [compiler/rename/RnNames.lhs](/trac/ghc/browser/ghc/compiler/rename/RnNames.lhs).
|
|
|
|
|
|
|
|
|
It is important to note that the global rdr-env is created *before* the renamer actually descends into the top=level bindings of a module. In other words, before `TcRnDriver.rnTopSrcDecls` performs the renaming of a module by way of `RnSource.rnSrcDecls`, it uses `RnNames.importsFromLocalDecls` to set up the global rdr-env environment, which contains `Names` for all imported and all locally defined toplevel binders. Hence, when the helpers of `rnSrcDecls` come across the defining occurences of a toplevel `RdrName`, they don't rename it by generating a new name, but they simply look up its name in the global rdr-env.
|
|
|
|
|
|
## Name Space Management
|
|
|
|
|
|
|
|
|
(too much detail?)
|
|
|
|
|
|
|
|
|
As anticipated by the variants `Orig` and `Exact` of `RdrName`, some names should not change during renaming, whereas others need to be turned into unique names. In this context, the two functions `RnEnv.newTopSrcBinder` and `RnEnv.newLocals` are important:
|
|
|
|
|
|
```wiki
|
|
|
newTopSrcBinder :: Module -> Maybe Name -> Located RdrName -> RnM Name
|
|
|
newLocalsRn :: [Located RdrName] -> RnM [Name]
|
|
|
```
|
|
|
|
|
|
|
|
|
The two functions introduces new toplevel and new local names, respectively, where the first two arguments to newTopSrcBinder determine the currently compiled module and the parent construct of the newly defined name. Both functions create new names only for RdrNames that are neither exact nor original.
|
|
|
|
|
|
## Rebindable syntax
|
|
|
|
|
|
|
|
|
(ToDo: Not fully proof-read.)
|
|
|
|
|
|
|
|
|
In Haskell when one writes "3" one gets "fromInteger 3", where "fromInteger" comes from the Prelude (regardless of whether the Prelude is in scope). If you want to completely redefine numbers, that becomes inconvenient. So GHC lets you say "-fno-implicit-prelude"; in that case, the "fromInteger" comes from whatever is in scope. (This is documented in the User Guide.)
|
|
|
|
|
|
|
|
|
This feature is implemented as follows (I always forget).
|
|
|
|
|
|
- Names that are implicitly bound by the Prelude, are marked by the type `HsExpr.SyntaxExpr`. Moreover, the association list `HsExpr.SyntaxTable` is set up by the renamer to map rebindable names to the value they are bound to.
|
|
|
- Currently, five constructs related to numerals (`HsExpr.NegApp`, `HsPat.NPat`, `HsPat.NPlusKPat`, `HsLit.HsIntegral`, and `HsLit.HsFractional`) and two constructs related to do-expressions (`HsExpr.BindStmt` and `HsExpr.ExprStmt`) have rebindable syntax.
|
|
|
- When the parser builds these constructs, it puts in the built-in Prelude Name (e.g. `PrelNum.fromInteger`).
|
|
|
- When the renamer encounters these constructs, it calls `RnEnv.lookupSyntaxName`. This checks for `-fno-implicit-prelude`; if not, it just returns the same Name; otherwise it takes the occurrence name of the Name, turns it into an unqualified `RdrName`, and looks it up in the environment. The returned name is plugged back into the construct.
|
|
|
- The typechecker uses the `Name` to generate the appropriate typing constraints. |