summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMichael Voronin <survivor.mail@gmail.com>2018-04-23 11:35:56 +0300
committerGitHub <noreply@github.com>2018-04-23 11:35:56 +0300
commit17d3c6f3f32649c7cc295e964e2fcc3af99eac20 (patch)
treed660abc250a7ded975908cac6e40a4c9a345efd9
parent04df7f147c6e08b28113173328d7e03fce381af9 (diff)
parenta8b70c550083e432f0028e6582c97d8310a48c8a (diff)
downloadNim-17d3c6f3f32649c7cc295e964e2fcc3af99eac20.tar.gz
Merge pull request #1 from nim-lang/devel
pull-23-04-18
-rw-r--r--changelog.md5
-rw-r--r--compiler/ast.nim10
-rw-r--r--compiler/bitsets.nim37
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/cgen.nim12
-rw-r--r--compiler/commands.nim14
-rw-r--r--compiler/docgen.nim10
-rw-r--r--compiler/evaltempl.nim5
-rw-r--r--compiler/filter_tmpl.nim6
-rw-r--r--compiler/hlo.nim2
-rw-r--r--compiler/jsgen.nim564
-rw-r--r--compiler/jstypes.nim19
-rw-r--r--compiler/lambdalifting.nim4
-rw-r--r--compiler/lexer.nim35
-rw-r--r--compiler/main.nim8
-rw-r--r--compiler/modulegraphs.nim40
-rw-r--r--compiler/modulepaths.nim2
-rw-r--r--compiler/modules.nim125
-rw-r--r--compiler/msgs.nim147
-rw-r--r--compiler/nim.nim8
-rw-r--r--compiler/nimfix/pretty.nim10
-rw-r--r--compiler/nimfix/prettybase.nim16
-rw-r--r--compiler/options.nim1
-rw-r--r--compiler/parampatterns.nim3
-rw-r--r--compiler/parser.nim10
-rw-r--r--compiler/passes.nim24
-rw-r--r--compiler/pbraces.nim2
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/procfind.nim7
-rw-r--r--compiler/renderer.nim17
-rw-r--r--compiler/reorder.nim20
-rw-r--r--compiler/rod.nim112
-rw-r--r--compiler/rodread.nim49
-rw-r--r--compiler/rodwrite.nim10
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/semexprs.nim16
-rw-r--r--compiler/semfold.nim19
-rw-r--r--compiler/semstmts.nim13
-rw-r--r--compiler/suggest.nim4
-rw-r--r--compiler/syntaxes.nim4
-rw-r--r--compiler/types.nim6
-rw-r--r--compiler/vm.nim32
-rw-r--r--doc/advopt.txt2
-rw-r--r--doc/basicopt.txt2
-rw-r--r--doc/manual.rst56
-rw-r--r--doc/manual/var_t_return.rst20
-rw-r--r--lib/core/macros.nim19
-rw-r--r--lib/deprecated/pure/asyncio.nim12
-rw-r--r--lib/deprecated/pure/sockets.nim8
-rw-r--r--lib/posix/posix_linux_amd64.nim4
-rw-r--r--lib/posix/posix_other.nim4
-rw-r--r--lib/pure/concurrency/threadpool.nim26
-rw-r--r--lib/pure/nativesockets.nim8
-rw-r--r--lib/pure/options.nim8
-rw-r--r--lib/pure/os.nim36
-rw-r--r--lib/pure/osproc.nim22
-rw-r--r--lib/pure/strutils.nim14
-rw-r--r--lib/pure/terminal.nim8
-rw-r--r--lib/pure/times.nim51
-rw-r--r--lib/system.nim30
-rw-r--r--lib/system/assign.nim10
-rw-r--r--lib/system/jssys.nim487
-rw-r--r--lib/windows/winlean.nim11
-rw-r--r--tests/cpp/tcovariancerules.nim16
-rw-r--r--tests/errmsgs/t1154.nim11
-rw-r--r--tests/errmsgs/tcant_overload_by_return_type.nim9
-rw-r--r--tests/macros/tmacro1.nim17
-rw-r--r--tests/objects/tinherentedvalues.nim16
-rw-r--r--tests/objects/tobj_asgn_dont_slice.nim24
-rw-r--r--tests/objects/tobjconstr.nim7
-rw-r--r--tests/osproc/tclose.nim24
-rw-r--r--tests/overload/toverprc.nim2
-rw-r--r--tests/parallel/twaitany.nim35
-rw-r--r--tests/pragmas/tcustom_pragma.nim10
-rw-r--r--tests/stdlib/ttimes.nim9
-rw-r--r--tests/template/i2416.nim1
-rw-r--r--tests/template/t2416.nim2
-rw-r--r--tests/varres/tnewseq_on_result_vart.nim9
-rw-r--r--tools/nimpretty.nim4
-rw-r--r--web/website.ini2
81 files changed, 1074 insertions, 1398 deletions
diff --git a/changelog.md b/changelog.md
index f39dc2678..a3332789a 100644
--- a/changelog.md
+++ b/changelog.md
@@ -11,6 +11,10 @@
   to deal with!
 - Indexing into a ``cstring`` for the JS target is now mapped
   to ``charCodeAt``.
+- Assignments that would "slice" an object into its supertype are not prevented
+  at runtime. Use ``ref object`` with inheritance rather than ``object`` with
+  inheritance to prevent this issue.
+
 
 #### Breaking changes in the standard library
 
@@ -27,6 +31,7 @@
 - ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type
   to ``times.Duration`` in order to support higher time resolutions.
   The proc is no longer deprecated.
+- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``.
 
 #### Breaking changes in the compiler
 
diff --git a/compiler/ast.nim b/compiler/ast.nim
index da7e828f2..4a0a9a20b 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1042,9 +1042,9 @@ proc newNode*(kind: TNodeKind): PNode =
   new(result)
   result.kind = kind
   #result.info = UnknownLineInfo() inlined:
-  result.info.fileIndex = int32(-1)
+  result.info.fileIndex = InvalidFileIdx
   result.info.col = int16(-1)
-  result.info.line = int16(-1)
+  result.info.line = uint16(0)
   when defined(useNodeIds):
     result.id = gNodeId
     if result.id == nodeIdToDebug:
@@ -1116,13 +1116,13 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
   s.typ = t
   result = s
 
-template fileIdx*(c: PSym): int32 =
+template fileIdx*(c: PSym): FileIndex =
   # XXX: this should be used only on module symbols
-  c.position.int32
+  c.position.FileIndex
 
 template filename*(c: PSym): string =
   # XXX: this should be used only on module symbols
-  c.position.int32.toFilename
+  c.position.FileIndex.toFilename
 
 proc appendToModule*(m: PSym, n: PNode) =
   ## The compiler will use this internally to add nodes that will be
diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim
index 6afd1bd78..e38732877 100644
--- a/compiler/bitsets.nim
+++ b/compiler/bitsets.nim
@@ -72,24 +72,25 @@ proc bitSetContains(x, y: TBitSet): bool =
   result = true
 
 # Number of set bits for all values of int8
-const populationCount: array[low(int8)..high(int8), int8] = [
-  1.int8, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
-  4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 
-  0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 
-  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
-  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
-  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7
-]
+const populationCount: array[low(int8)..high(int8), int8] = block:
+    var arr: array[low(int8)..high(int8), int8]
+
+    proc countSetBits(x: int8): int8 =
+      return
+        ( x and 0b00000001'i8) +
+        ((x and 0b00000010'i8) shr 1) +
+        ((x and 0b00000100'i8) shr 2) +
+        ((x and 0b00001000'i8) shr 3) +
+        ((x and 0b00010000'i8) shr 4) +
+        ((x and 0b00100000'i8) shr 5) +
+        ((x and 0b01000000'i8) shr 6) +
+        ((x and 0b10000000'i8) shr 7)
+        
+
+    for it in low(int8)..high(int8):
+      arr[it] = countSetBits(it)
+
+    arr
 
 proc bitSetCard(x: TBitSet): BiggestInt =
   for it in x:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 7e3c2632a..461a86298 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2023,7 +2023,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
         let theMacro = it[0].sym
         add p.s(cpsStmts), initFrameNoDebug(p, frameName,
            makeCString theMacro.name.s,
-           theMacro.info.quotedFilename, it.info.line)
+           theMacro.info.quotedFilename, it.info.line.int)
     else:
       genStmts(p, it)
   if n.len > 0: exprOrStmt
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 4d3cabd3a..9e1f9349f 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -223,7 +223,7 @@ proc genLineDir(p: BProc, t: PNode) =
               line.rope, makeCString(toFilename(tt.info)))
   elif ({optLineTrace, optStackTrace} * p.options ==
       {optLineTrace, optStackTrace}) and
-      (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex >= 0:
+      (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX:
     if freshLineInfo(p, tt.info):
       linefmt(p, cpsStmts, "nimln_($1, $2);$n",
               line.rope, tt.info.quotedFilename)
@@ -678,7 +678,7 @@ proc generateHeaders(m: BModule) =
 
 proc openNamespaceNim(): Rope =
   result.add("namespace Nim {" & tnl)
-  
+
 proc closeNamespaceNim(): Rope =
   result.add("}" & tnl)
 
@@ -1090,7 +1090,7 @@ proc genMainProc(m: BModule) =
   appcg(m, m.s[cfsProcs], nimMain,
         [m.g.mainModInit, initStackBottomCall, rope(m.labels)])
   if optNoMain notin gGlobalOptions:
-    if useNimNamespace: 
+    if useNimNamespace:
       m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl
 
     appcg(m, m.s[cfsProcs], otherMain, [])
@@ -1202,7 +1202,7 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
     add(result, genSectionStart(i))
     add(result, m.s[i])
     add(result, genSectionEnd(i))
-    if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()    
+    if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
   add(result, m.s[cfsInitProc])
   if useNimNamespace: result.add closeNamespaceNim()
 
@@ -1301,7 +1301,7 @@ proc resetCgenModules*(g: BModuleList) =
   for m in cgenModules(g): resetModule(m)
 
 proc rawNewModule(g: BModuleList; module: PSym): BModule =
-  result = rawNewModule(g, module, module.position.int32.toFullPath)
+  result = rawNewModule(g, module, module.position.FileIndex.toFullPath)
 
 proc newModule(g: BModuleList; module: PSym): BModule =
   # we should create only one cgen module for each module sym
@@ -1311,7 +1311,7 @@ proc newModule(g: BModuleList; module: PSym): BModule =
 
   if (optDeadCodeElim in gGlobalOptions):
     if (sfDeadCodeElim in module.flags):
-      internalError("added pending module twice: " & module.filename)
+      internalError("added pending module twice: " & toFilename(FileIndex module.position))
 
 template injectG(config) {.dirty.} =
   if graph.backend == nil:
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 820cb7e1a..e1dc1aacf 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -77,6 +77,14 @@ proc writeAdvancedUsage(pass: TCmdLinePass) =
                {msgStdout})
     msgQuit(0)
 
+proc writeFullhelp(pass: TCmdLinePass) =
+  if pass == passCmd1:
+    msgWriteln(`%`(HelpMessage, [VersionAsString,
+                                 platform.OS[platform.hostOS].name,
+                                 CPU[platform.hostCPU].name]) & Usage & AdvancedUsage,
+               {msgStdout})
+    msgQuit(0)
+
 proc writeVersionInfo(pass: TCmdLinePass) =
   if pass == passCmd1:
     msgWriteln(`%`(HelpMessage, [VersionAsString,
@@ -311,7 +319,7 @@ proc trackDirty(arg: string, info: TLineInfo) =
     localError(info, errInvalidNumber, a[2])
 
   let dirtyOriginalIdx = a[1].fileInfoIdx
-  if dirtyOriginalIdx >= 0:
+  if dirtyOriginalIdx.int32 >= 0:
     msgs.setDirtyFile(dirtyOriginalIdx, a[0])
 
   gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
@@ -611,6 +619,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
   of "advanced":
     expectNoArg(switch, arg, pass, info)
     writeAdvancedUsage(pass)
+  of "fullhelp":
+    expectNoArg(switch, arg, pass, info)
+    writeFullhelp(pass)
   of "help", "h":
     expectNoArg(switch, arg, pass, info)
     helpOnError(pass)
@@ -702,7 +713,6 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     expectNoArg(switch, arg, pass, info)
     useNimNamespace = true
     defineSymbol("cppCompileToNamespace")
-    
   else:
     if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
     else: invalidCmdLineOption(pass, switch, info)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 74fb305ac..6f3dcde8b 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -544,7 +544,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
 
   initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
 
-  result = %{ "name": %name, "type": %($k), "line": %n.info.line,
+  result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
                  "col": %n.info.col}
   if comm != nil and comm != "":
     result["description"] = %comm
@@ -618,7 +618,7 @@ proc generateJson*(d: PDoc, n: PNode) =
   of nkCommentStmt:
     if n.comment != nil and startsWith(n.comment, "##"):
       let stripped = n.comment.substr(2).strip
-      d.add %{ "comment": %stripped, "line": %n.info.line,
+      d.add %{ "comment": %stripped, "line": %n.info.line.int,
                "col": %n.info.col }
   of nkProcDef:
     when useEffectSystem: documentRaises(n)
@@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string,
       discard "fixme: error report"
 
 proc commandDoc*() =
-  var ast = parseFile(gProjectMainIdx, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
@@ -840,7 +840,7 @@ proc commandRst2TeX*() =
   commandRstAux(gProjectFull, TexExt)
 
 proc commandJson*() =
-  var ast = parseFile(gProjectMainIdx, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
@@ -855,7 +855,7 @@ proc commandJson*() =
     writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
 
 proc commandTags*() =
-  var ast = parseFile(gProjectMainIdx, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 704ff819c..fbb7eb2e6 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -106,8 +106,9 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
   for i in 1 .. genericParams:
     result.addSon n.sons[givenRegularParams + i]
 
+# to prevent endless recursion in template instantiation
+const evalTemplateLimit* = 1000
 var evalTemplateCounter* = 0
-  # to prevent endless recursion in templates instantiation
 
 proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
   when true:
@@ -133,7 +134,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
 
 proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
   inc(evalTemplateCounter)
-  if evalTemplateCounter > 100:
+  if evalTemplateCounter > evalTemplateLimit:
     globalError(n.info, errTemplateInstantiationTooNested)
     result = n
 
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index ca9a3a801..a1ba9113c 100644
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -35,7 +35,7 @@ const
 proc newLine(p: var TTmplParser) =
   llStreamWrite(p.outp, repeat(')', p.emitPar))
   p.emitPar = 0
-  if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
+  if p.info.line > uint16(1): llStreamWrite(p.outp, "\n")
   if p.pendingExprLine:
     llStreamWrite(p.outp, spaces(2))
     p.pendingExprLine = false
@@ -212,9 +212,9 @@ proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
   p.x = newStringOfCap(120)
   # do not process the first line which contains the directive:
   if llStreamReadLine(p.inp, p.x):
-    p.info.line = p.info.line + int16(1)
+    p.info.line = p.info.line + 1'u16
   while llStreamReadLine(p.inp, p.x):
-    p.info.line = p.info.line + int16(1)
+    p.info.line = p.info.line + 1'u16
     parseLine(p)
   newLine(p)
   result = p.outp
diff --git a/compiler/hlo.nim b/compiler/hlo.nim
index 2bffaa173..c4288c362 100644
--- a/compiler/hlo.nim
+++ b/compiler/hlo.nim
@@ -44,7 +44,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
         assert x.kind in {nkStmtList, nkCall}
         # better be safe than sorry, so check evalTemplateCounter too:
         inc(evalTemplateCounter)
-        if evalTemplateCounter > 100:
+        if evalTemplateCounter > evalTemplateLimit:
           globalError(n.info, errTemplateInstantiationTooNested)
         # deactivate this pattern:
         c.patterns[i] = nil
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index da5267b93..2ae3426ab 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -8,7 +8,6 @@
 #
 
 # This is the JavaScript code generator.
-# Also a PHP code generator. ;-)
 
 discard """
 The JS code generator contains only 2 tricks:
@@ -38,11 +37,8 @@ import
 from modulegraphs import ModuleGraph
 
 type
-  TTarget = enum
-    targetJS, targetPHP
   TJSGen = object of TPassContext
     module: PSym
-    target: TTarget
     sigConflicts: CountTable[SigHash]
 
   BModule = ref TJSGen
@@ -92,16 +88,12 @@ type
     module: BModule
     g: PGlobals
     beforeRetNeeded: bool
-    target: TTarget # duplicated here for faster dispatching
     unique: int    # for temp identifier generation
     blocks: seq[TBlock]
     extraIndent: int
     up: PProc     # up the call chain; required for closure support
     declaredGlobals: IntSet
 
-template `|`(a, b: untyped): untyped {.dirty.} =
-  (if p.target == targetJS: a else: b)
-
 var indent = "\t".rope
 
 proc indentLine(p: PProc, r: Rope): Rope =
@@ -157,11 +149,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
     module: module,
     procDef: procDef,
     g: globals,
-    target: module.target,
     extraIndent: int(procDef != nil))
   if procDef != nil: result.prc = procDef.sons[namePos].sym
-  if result.target == targetPHP:
-    result.declaredGlobals = initIntSet()
 
 proc declareGlobal(p: PProc; id: int; r: Rope) =
   if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
@@ -208,8 +197,7 @@ proc mapType(typ: PType): TJSTypeKind =
   of tyUnused, tyOptAsRef: internalError("mapType")
 
 proc mapType(p: PProc; typ: PType): TJSTypeKind =
-  if p.target == targetPHP: result = etyObject
-  else: result = mapType(typ)
+  result = mapType(typ)
 
 proc mangleName(m: BModule, s: PSym): Rope =
   proc validJsName(name: string): bool =
@@ -236,7 +224,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
   if result == nil:
     if s.kind == skField and s.name.s.validJsName:
       result = rope(s.name.s)
-    elif m.target == targetJS or s.kind == skTemp:
+    elif s.kind == skTemp:
       result = rope(mangle(s.name.s))
     else:
       var x = newStringOfCap(s.name.s.len)
@@ -314,7 +302,7 @@ proc useMagic(p: PProc, name: string) =
 proc isSimpleExpr(p: PProc; n: PNode): bool =
   # calls all the way down --> can stay expression based
   if n.kind in nkCallKinds+{nkBracketExpr, nkDotExpr, nkPar, nkTupleConstr} or
-      (p.target == targetJS and n.kind in {nkObjConstr, nkBracket, nkCurly}):
+      (n.kind in {nkObjConstr, nkBracket, nkCurly}):
     for c in n:
       if not p.isSimpleExpr(c): return false
     result = true
@@ -323,12 +311,9 @@ proc isSimpleExpr(p: PProc; n: PNode): bool =
 
 proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
   inc(p.unique)
-  if p.target == targetJS:
-    result = "Tmp$1" % [rope(p.unique)]
-    if defineInLocals:
-      add(p.locals, p.indentLine("var $1;$n" % [result]))
-  else:
-    result = "$$Tmp$1" % [rope(p.unique)]
+  result = "Tmp$1" % [rope(p.unique)]
+  if defineInLocals:
+    add(p.locals, p.indentLine("var $1;$n" % [result]))
 
 proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
   assert r.kind == resNone
@@ -477,15 +462,9 @@ proc unsignedTrimmerJS(size: BiggestInt): Rope =
   of 4: rope">>> 0"
   else: rope""
 
-proc unsignedTrimmerPHP(size: BiggestInt): Rope =
-  case size
-  of 1: rope"& 0xff"
-  of 2: rope"& 0xffff"
-  of 4: rope"& 0xffffffff"
-  else: rope""
 
 template unsignedTrimmer(size: BiggestInt): Rope =
-  size.unsignedTrimmerJS | size.unsignedTrimmerPHP
+  size.unsignedTrimmerJS
 
 proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
                     reassign = false) =
@@ -533,46 +512,18 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   of mMulU: binaryUintExpr(p, n, r, "*")
   of mDivU: binaryUintExpr(p, n, r, "/")
   of mDivI:
-    if p.target == targetPHP:
-      var x, y: TCompRes
-      gen(p, n.sons[1], x)
-      gen(p, n.sons[2], y)
-      r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
-    else:
-      arithAux(p, n, r, op)
+    arithAux(p, n, r, op)
   of mModI:
-    if p.target == targetPHP:
-      var x, y: TCompRes
-      gen(p, n.sons[1], x)
-      gen(p, n.sons[2], y)
-      r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
-    else:
-      arithAux(p, n, r, op)
+    arithAux(p, n, r, op)
   of mShrI:
     var x, y: TCompRes
     gen(p, n.sons[1], x)
     gen(p, n.sons[2], y)
     let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
-    if p.target == targetPHP:
-      # XXX prevent multi evaluations
-      r.res = "(($1 $2) >= 0) ? (($1 $2) >> $3) : ((($1 $2) & 0x7fffffff) >> $3) | (0x40000000 >> ($3 - 1))" % [x.rdLoc, trimmer, y.rdLoc]
-    else:
-      r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
+    r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
   of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
       mCStrToStr, mStrToStr, mEnumToStr:
-    if p.target == targetPHP:
-      if op == mEnumToStr:
-        var x: TCompRes
-        gen(p, n.sons[1], x)
-        r.res = "$#[$#]" % [genEnumInfoPHP(p, n.sons[1].typ), x.rdLoc]
-      elif op == mCharToStr:
-        var x: TCompRes
-        gen(p, n.sons[1], x)
-        r.res = "chr($#)" % [x.rdLoc]
-      else:
-        gen(p, n.sons[1], r)
-    else:
-      arithAux(p, n, r, op)
+    arithAux(p, n, r, op)
   else:
     arithAux(p, n, r, op)
   r.kind = resExpr
@@ -591,7 +542,7 @@ proc genLineDir(p: PProc, n: PNode) =
     useMagic(p, "endb")
     lineF(p, "endb($1);$n", [rope(line)])
   elif hasFrameInfo(p):
-    lineF(p, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
+    lineF(p, "F.line = $1;$n", [rope(line)])
 
 proc genWhileStmt(p: PProc, n: PNode) =
   var
@@ -604,12 +555,12 @@ proc genWhileStmt(p: PProc, n: PNode) =
   p.blocks[length].id = -p.unique
   p.blocks[length].isLoop = true
   let labl = p.unique.rope
-  lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl])
+  lineF(p, "L$1: while (true) {$n", [labl])
   p.nested: gen(p, n.sons[0], cond)
-  lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
+  lineF(p, "if (!$1) break L$2;$n",
        [cond.res, labl])
   p.nested: genStmt(p, n.sons[1])
-  lineF(p, "}$n" | "}L$#:;$n", [labl])
+  lineF(p, "}$n", [labl])
   setLen(p.blocks, length)
 
 proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
@@ -653,26 +604,22 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
   var i = 1
   var length = sonsLen(n)
   var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
-  if catchBranchesExist and p.target == targetJS:
+  if catchBranchesExist:
     add(p.body, "++excHandler;" & tnl)
   var tmpFramePtr = rope"F"
   if optStackTrace notin p.options:
     tmpFramePtr = p.getTemp(true)
     line(p, tmpFramePtr & " = framePtr;" & tnl)
   lineF(p, "try {$n", [])
-  if p.target == targetPHP and p.globals == nil:
-      p.globals = "global $lastJSError; global $prevJSError;".rope
   var a: TCompRes
   gen(p, n.sons[0], a)
   moveInto(p, a, r)
   var generalCatchBranchExists = false
-  let dollar = rope(if p.target == targetJS: "" else: "$")
-  if p.target == targetJS and catchBranchesExist:
+  let dollar = rope("")
+  if catchBranchesExist:
     addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
         " lastJSError = EXC;$n --excHandler;$n", [])
     line(p, "framePtr = $1;$n" % [tmpFramePtr])
-  elif p.target == targetPHP:
-    lineF(p, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", [])
   while i < length and n.sons[i].kind == nkExceptBranch:
     let blen = sonsLen(n.sons[i])
     if blen == 1:
@@ -704,19 +651,11 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
       line(p, indent & "reraiseException();" & tnl)
       line(p, "}" & tnl)
     addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
-  if p.target == targetJS:
-    line(p, "} finally {" & tnl)
-    line(p, "framePtr = $1;$n" % [tmpFramePtr])
-  if p.target == targetPHP:
-    # XXX ugly hack for PHP codegen
-    line(p, "}" & tnl)
+  line(p, "} finally {" & tnl)
+  line(p, "framePtr = $1;$n" % [tmpFramePtr])
   if i < length and n.sons[i].kind == nkFinally:
     genStmt(p, n.sons[i].sons[0])
-  if p.target == targetPHP:
-    # XXX ugly hack for PHP codegen
-    line(p, "if($lastJSError) throw($lastJSError);" & tnl)
-  if p.target == targetJS:
-    line(p, "}" & tnl)
+  line(p, "}" & tnl)
 
 proc genRaiseStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
@@ -737,7 +676,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
   genLineDir(p, n)
   gen(p, n.sons[0], cond)
   let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
-  if stringSwitch and p.target == targetJS:
+  if stringSwitch:
     useMagic(p, "toJSStr")
     lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
   else:
@@ -789,12 +728,12 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
     sym.loc.k = locOther
     sym.position = idx+1
   let labl = p.unique
-  lineF(p, "L$1: do {$n" | "", [labl.rope])
+  lineF(p, "L$1: do {$n", [labl.rope])
   setLen(p.blocks, idx + 1)
   p.blocks[idx].id = - p.unique # negative because it isn't used yet
   gen(p, n.sons[1], r)
   setLen(p.blocks, idx)
-  lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
+  lineF(p, "} while(false);$n", [labl.rope])
 
 proc genBreakStmt(p: PProc, n: PNode) =
   var idx: int
@@ -812,7 +751,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
     if idx < 0 or not p.blocks[idx].isLoop:
       internalError(n.info, "no loop to break")
   p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
-  lineF(p, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
+  lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)])
 
 proc genAsmOrEmitStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
@@ -826,7 +765,6 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
       let v = it.sym
       # for backwards compatibility we don't deref syms here :-(
       if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
-        if p.target == targetPHP: p.body.add "$"
         p.body.add mangleName(p.module, v)
       else:
         var r: TCompRes
@@ -869,24 +807,11 @@ proc generateHeader(p: PProc, typ: PType): Rope =
     if isCompileTimeOnly(param.typ): continue
     if result != nil: add(result, ", ")
     var name = mangleName(p.module, param)
-    if p.target == targetJS:
-      add(result, name)
-      if mapType(param.typ) == etyBaseIndex:
-        add(result, ", ")
-        add(result, name)
-        add(result, "_Idx")
-    elif not (i == 1 and param.name.s == "this"):
-      let k = param.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind
-      if k in {tyVar, tyRef, tyPtr, tyLent, tyPointer}:
-        add(result, "&")
-      add(result, "$")
+    add(result, name)
+    if mapType(param.typ) == etyBaseIndex:
+      add(result, ", ")
       add(result, name)
-      # XXX I think something like this is needed for PHP to really support
-      # ptr "inside" strings and seq
-      #if mapType(param.typ) == etyBaseIndex:
-      #  add(result, ", $")
-      #  add(result, name)
-      #  add(result, "_Idx")
+      add(result, "_Idx")
 
 proc countJsParams(typ: PType): int =
   for i in countup(1, sonsLen(typ.n) - 1):
@@ -906,21 +831,10 @@ const
 
 proc needsNoCopy(p: PProc; y: PNode): bool =
   result = (y.kind in nodeKindsNeedNoCopy) or
-      (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar}) or
-      p.target == targetPHP
+      (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar})
 
 proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   var a, b: TCompRes
-
-  if p.target == targetPHP and x.kind == nkBracketExpr and
-      x[0].typ.skipTypes(abstractVar).kind in {tyString, tyCString}:
-    var c: TCompRes
-    gen(p, x[0], a)
-    gen(p, x[1], b)
-    gen(p, y, c)
-    lineF(p, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
-    return
-
   var xtyp = mapType(p, x.typ)
 
   if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
@@ -968,7 +882,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
 
 proc genAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
-  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=p.target == targetPHP)
+  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
 
 proc genFastAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
@@ -991,12 +905,10 @@ proc genSwap(p: PProc, n: PNode) =
     let tmp2 = p.getTemp(false)
     if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       internalError(n.info, "genSwap")
-    lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" |
-             "$1 = $2; $2 = $3; $3 = $1;$n",
+    lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n",
              [tmp, a.address, b.address])
     tmp = tmp2
-  lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" |
-           "$1 = $2; $2 = $3; $3 = $1;",
+  lineF(p, "var $1 = $2; $2 = $3; $3 = $1;",
            [tmp, a.res, b.res])
 
 proc getFieldPosition(f: PNode): int =
@@ -1011,10 +923,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
   gen(p, b.sons[0], a)
   if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
-    if p.target == targetJS:
-      r.res = makeJSString( "Field" & $getFieldPosition(b.sons[1]) )
-    else:
-      r.res = getFieldPosition(b.sons[1]).rope
+    r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
   else:
     if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
     var f = b.sons[1].sym
@@ -1029,19 +938,13 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
   gen(p, n.sons[0], r)
   let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
   if otyp.kind == tyTuple:
-    r.res = ("$1.Field$2" | "$1[$2]") %
+    r.res = ("$1.Field$2") %
         [r.res, getFieldPosition(n.sons[1]).rope]
   else:
     if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
     var f = n.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
-    if p.target == targetJS:
-      r.res = "$1.$2" % [r.res, f.loc.r]
-    else:
-      if {sfImportc, sfExportc} * f.flags != {}:
-        r.res = "$1->$2" % [r.res, f.loc.r]
-      else:
-        r.res = "$1['$2']" % [r.res, f.loc.r]
+    r.res = "$1.$2" % [r.res, f.loc.r]
   r.kind = resExpr
 
 proc genAddr(p: PProc, n: PNode, r: var TCompRes)
@@ -1069,13 +972,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   else: first = 0
   if optBoundsCheck in p.options:
     useMagic(p, "chckIndx")
-    if p.target == targetPHP:
-      if typ.kind != tyString:
-        r.res = "chckIndx($1, $2, count($3)-1)-$2" % [b.res, rope(first), a.res]
-      else:
-        r.res = "chckIndx($1, $2, strlen($3))-$2" % [b.res, rope(first), a.res]
-    else:
-      r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res]
+    r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res]
   elif first != 0:
     r.res = "($1)-$2" % [b.res, rope(first)]
   else:
@@ -1089,27 +986,11 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
   of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs:
     genArrayAddr(p, n, r)
   of tyTuple:
-    if p.target == targetPHP:
-      genFieldAccess(p, n, r)
-      return
     genFieldAddr(p, n, r)
   else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
   r.typ = etyNone
   if r.res == nil: internalError(n.info, "genArrayAccess")
-  if p.target == targetPHP:
-    if n.sons[0].kind in nkCallKinds+{nkStrLit..nkTripleStrLit}:
-      useMagic(p, "nimAt")
-      if ty.kind in {tyString, tyCString}:
-        # XXX this needs to be more like substr($1,$2)
-        r.res = "ord(nimAt($1, $2))" % [r.address, r.res]
-      else:
-        r.res = "nimAt($1, $2)" % [r.address, r.res]
-    elif ty.kind in {tyString, tyCString}:
-      # XXX this needs to be more like substr($1,$2)
-      r.res = "ord(@$1[$2])" % [r.address, r.res]
-    else:
-      r.res = "$1[$2]" % [r.address, r.res]
-  elif ty.kind == tyCString:
+  if ty.kind == tyCString:
     r.res = "$1.charCodeAt($2)" % [r.address, r.res]
   else:
     r.res = "$1[$2]" % [r.address, r.res]
@@ -1122,7 +1003,7 @@ template isIndirect(x: PSym): bool =
     #(mapType(v.typ) != etyObject) and
     {sfImportc, sfVolatile, sfExportc} * v.flags == {} and
     v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
-                  skConst, skTemp, skLet} and p.target == targetJS)
+                  skConst, skTemp, skLet})
 
 proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
   case n.sons[0].kind
@@ -1138,8 +1019,6 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
         r.typ = etyNone
         if isIndirect(s):
           r.res = s.loc.r & "[0]"
-        elif p.target == targetPHP:
-          r.res = "&" & s.loc.r
         else:
           r.res = s.loc.r
         r.address = nil
@@ -1180,15 +1059,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
   else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
 
 proc thisParam(p: PProc; typ: PType): PType =
-  if p.target == targetPHP:
-    # XXX Might be very useful for the JS backend too?
-    let typ = skipTypes(typ, abstractInst)
-    assert(typ.kind == tyProc)
-    if 1 < sonsLen(typ.n):
-      assert(typ.n.sons[1].kind == nkSym)
-      let param = typ.n.sons[1].sym
-      if param.name.s == "this":
-        result = param.typ.skipTypes(abstractVar)
+  discard
 
 proc attachProc(p: PProc; content: Rope; s: PSym) =
   let otyp = thisParam(p, s.typ)
@@ -1220,39 +1091,27 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   of skVar, skLet, skParam, skTemp, skResult, skForVar:
     if s.loc.r == nil:
       internalError(n.info, "symbol has no generated name: " & s.name.s)
-    if p.target == targetJS:
-      let k = mapType(p, s.typ)
-      if k == etyBaseIndex:
-        r.typ = etyBaseIndex
-        if {sfAddrTaken, sfGlobal} * s.flags != {}:
-          r.address = "$1[0]" % [s.loc.r]
-          r.res = "$1[1]" % [s.loc.r]
-        else:
-          r.address = s.loc.r
-          r.res = s.loc.r & "_Idx"
-      elif isIndirect(s):
-        r.res = "$1[0]" % [s.loc.r]
+    let k = mapType(p, s.typ)
+    if k == etyBaseIndex:
+      r.typ = etyBaseIndex
+      if {sfAddrTaken, sfGlobal} * s.flags != {}:
+        r.address = "$1[0]" % [s.loc.r]
+        r.res = "$1[1]" % [s.loc.r]
       else:
-        r.res = s.loc.r
+        r.address = s.loc.r
+        r.res = s.loc.r & "_Idx"
+    elif isIndirect(s):
+      r.res = "$1[0]" % [s.loc.r]
     else:
-      r.res = "$" & s.loc.r
-      if sfGlobal in s.flags:
-        p.declareGlobal(s.id, r.res)
+      r.res = s.loc.r
   of skConst:
     genConstant(p, s)
     if s.loc.r == nil:
       internalError(n.info, "symbol has no generated name: " & s.name.s)
-    if p.target == targetJS:
-      r.res = s.loc.r
-    else:
-      r.res = "$" & s.loc.r
-      p.declareGlobal(s.id, r.res)
+    r.res = s.loc.r
   of skProc, skFunc, skConverter, skMethod:
     discard mangleName(p.module, s)
-    if p.target == targetPHP and r.kind != resCallee:
-      r.res = makeJsString($s.loc.r)
-    else:
-      r.res = s.loc.r
+    r.res = s.loc.r
     if lfNoDecl in s.loc.flags or s.magic != mNone or
        {sfImportc, sfInfixCall} * s.flags != {}:
       discard
@@ -1421,10 +1280,8 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
       r.res = "$1[$2]" % [r.address, r.res]
       r.address = nil
       r.typ = etyNone
-    add(r.res, "." | "->")
+    add(r.res, ".")
   var op: TCompRes
-  if p.target == targetPHP:
-    op.kind = resCallee
   gen(p, n.sons[0], op)
   add(r.res, op.res)
   genArgs(p, n, r, 2)
@@ -1433,28 +1290,21 @@ proc genCall(p: PProc, n: PNode, r: var TCompRes) =
   if n.sons[0].kind == nkSym and thisParam(p, n.sons[0].typ) != nil:
     genInfixCall(p, n, r)
     return
-  if p.target == targetPHP:
-    r.kind = resCallee
   gen(p, n.sons[0], r)
   genArgs(p, n, r)
 
 proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
   let n = n[1].skipConv
   internalAssert n.kind == nkBracket
-  if p.target == targetJS:
-    useMagic(p, "toJSStr") # Used in rawEcho
-    useMagic(p, "rawEcho")
-  elif n.len == 0:
-    r.kind = resExpr
-    add(r.res, """print("\n")""")
-    return
-  add(r.res, "rawEcho(" | "print(")
+  useMagic(p, "toJSStr") # Used in rawEcho
+  useMagic(p, "rawEcho")
+  add(r.res, "rawEcho(")
   for i in countup(0, sonsLen(n) - 1):
     let it = n.sons[i]
     if it.typ.isCompileTimeOnly: continue
-    if i > 0: add(r.res, ", " | ".")
+    if i > 0: add(r.res, ", ")
     genArgNoParam(p, it, r)
-  add(r.res, ")" | """."\n")""")
+  add(r.res, ")")
   r.kind = resExpr
 
 proc putToSeq(s: string, indirect: bool): Rope =
@@ -1474,10 +1324,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output:
   of nkSym:
     if rec.sym.id notin excludedFieldIDs:
       if output.len > 0: output.add(", ")
-      if p.target == targetJS:
-        output.addf("$#: ", [mangleName(p.module, rec.sym)])
-      else:
-        output.addf("'$#' => ", [mangleName(p.module, rec.sym)])
+      output.addf("$#: ", [mangleName(p.module, rec.sym)])
       output.add(createVar(p, rec.sym.typ, false))
   else: internalError(rec.info, "createRecordVarAux")
 
@@ -1485,7 +1332,7 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
   var t = typ
   if objHasTypeField(t):
     if output.len > 0: output.add(", ")
-    addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)])
+    addf(output, "m_type: $1", [genTypeInfo(p, t)])
   while t != nil:
     t = t.skipTypes(skipPtrs)
     createRecordVarAux(p, t.n, excludedFieldIDs, output)
@@ -1514,49 +1361,42 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
   of tyRange, tyGenericInst, tyAlias, tySink:
     result = createVar(p, lastSon(typ), indirect)
   of tySet:
-    result = putToSeq("{}" | "array()", indirect)
+    result = putToSeq("{}", indirect)
   of tyBool:
     result = putToSeq("false", indirect)
   of tyArray:
     let length = int(lengthOrd(t))
     let e = elemType(t)
     let jsTyp = arrayTypeForElemType(e)
-    if not jsTyp.isNil and p.target == targetJS:
+    if not jsTyp.isNil:
       result = "new $1($2)" % [rope(jsTyp), rope(length)]
     elif length > 32:
       useMagic(p, "arrayConstr")
       # XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
-      if p.target == targetJS: useMagic(p, "nimCopy")
+      useMagic(p, "nimCopy")
       result = "arrayConstr($1, $2, $3)" % [rope(length),
           createVar(p, e, false), genTypeInfo(p, e)]
     else:
-      result = rope("[" | "array(")
+      result = rope("[")
       var i = 0
       while i < length:
         if i > 0: add(result, ", ")
         add(result, createVar(p, e, false))
         inc(i)
-      add(result, "]" | ")")
+      add(result, "]")
     if indirect: result = "[$1]" % [result]
   of tyTuple:
-    if p.target == targetJS:
-      result = rope("{")
-      for i in 0..<t.sonsLen:
-        if i > 0: add(result, ", ")
-        addf(result, "Field$1: $2", [i.rope,
-             createVar(p, t.sons[i], false)])
-      add(result, "}")
-      if indirect: result = "[$1]" % [result]
-    else:
-      result = rope("array(")
-      for i in 0..<t.sonsLen:
-        if i > 0: add(result, ", ")
-        add(result, createVar(p, t.sons[i], false))
-      add(result, ")")
+    result = rope("{")
+    for i in 0..<t.sonsLen:
+      if i > 0: add(result, ", ")
+      addf(result, "Field$1: $2", [i.rope,
+            createVar(p, t.sons[i], false)])
+    add(result, "}")
+    if indirect: result = "[$1]" % [result]
   of tyObject:
     var initList: Rope
     createObjInitList(p, t, initIntSet(), initList)
-    result = ("{$1}" | "array($#)") % [initList]
+    result = ("{$1}") % [initList]
     if indirect: result = "[$1]" % [result]
   of tyVar, tyPtr, tyLent, tyRef:
     if mapType(p, t) == etyBaseIndex:
@@ -1597,7 +1437,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     varCode = v.constraint.strVal
 
   if n.kind == nkEmpty:
-    lineF(p, varCode & " = $3;$n" | "$$$2 = $3;$n",
+    lineF(p, varCode & " = $3;$n",
                [returnType, varName, createVar(p, v.typ, isIndirect(v))])
     if v.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(p, v.typ) == etyBaseIndex:
       lineF(p, "var $1_Idx = 0;$n", [varName])
@@ -1632,7 +1472,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     if isIndirect(v):
       lineF(p, varCode & " = [$3];$n", [returnType, v.loc.r, s])
     else:
-      lineF(p, varCode & " = $3;$n" | "$$$2 = $3;$n", [returnType, v.loc.r, s])
+      lineF(p, varCode & " = $3;$n", [returnType, v.loc.r, s])
 
   if useReloadingGuard:
     lineF(p, "}$n")
@@ -1665,18 +1505,14 @@ proc genNew(p: PProc, n: PNode) =
   var a: TCompRes
   gen(p, n.sons[1], a)
   var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  if p.target == targetJS:
-    lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
-  else:
-    lineF(p, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
+  lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
 
 proc genNewSeq(p: PProc, n: PNode) =
   var x, y: TCompRes
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
   let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
-           "$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
+  lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
     x.rdLoc, y.rdLoc, createVar(p, t, false)])
 
 proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
@@ -1708,21 +1544,6 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   else:
     r.res.add("$1)" % [a.res])
 
-proc genConStrStrPHP(p: PProc, n: PNode, r: var TCompRes) =
-  var a: TCompRes
-  gen(p, n.sons[1], a)
-  r.kind = resExpr
-  if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
-    r.res.add("chr($1)" % [a.res])
-  else:
-    r.res.add(a.res)
-  for i in countup(2, sonsLen(n) - 1):
-    gen(p, n.sons[i], a)
-    if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
-      r.res.add(".chr($1)" % [a.res])
-    else:
-      r.res.add(".$1" % [a.res])
-
 proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
   # we map mArray to PHP's array constructor, a mild hack:
   var a, b: TCompRes
@@ -1766,9 +1587,6 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope =
   add(r.res, ")")
 
 proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
-  if p.target == targetPHP:
-    localError(n.info, "'repr' not available for PHP backend")
-    return
   let t = skipTypes(n.sons[1].typ, abstractVarRange)
   case t.kind:
   of tyInt..tyInt64, tyUInt..tyUInt64:
@@ -1828,57 +1646,36 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
     else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
   of mAppendStrCh:
-    if p.target == targetJS:
-      binaryExpr(p, n, r, "addChar",
-          "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
-    else:
-      binaryExpr(p, n, r, "", "$1 .= chr($2)")
+    binaryExpr(p, n, r, "addChar",
+        "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
   of mAppendStrStr:
-    if p.target == targetJS:
-      if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
-          binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
-      else:
-        binaryExpr(p, n, r, "",
-          "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
-      # XXX: make a copy of $2, because of Javascript's sucking semantics
+    if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
+        binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
     else:
-      binaryExpr(p, n, r, "", "$1 .= $2;")
+      binaryExpr(p, n, r, "",
+        "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
+    # XXX: make a copy of $2, because of Javascript's sucking semantics
   of mAppendSeqElem:
-    if p.target == targetJS:
-      var x, y: TCompRes
-      gen(p, n.sons[1], x)
-      gen(p, n.sons[2], y)
-      if needsNoCopy(p, n[2]):
-        r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, y.rdLoc]
-      else:
-        useMagic(p, "nimCopy")
-        let c = getTemp(p, defineInLocals=false)
-        lineF(p, "var $1 = nimCopy(null, $2, $3);$n",
-             [c, y.rdLoc, genTypeInfo(p, n[2].typ)])
-        r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c]
-      r.kind = resExpr
+    var x, y: TCompRes
+    gen(p, n.sons[1], x)
+    gen(p, n.sons[2], y)
+    if needsNoCopy(p, n[2]):
+      r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, y.rdLoc]
     else:
-      binaryExpr(p, n, r, "", "$1[] = $2")
+      useMagic(p, "nimCopy")
+      let c = getTemp(p, defineInLocals=false)
+      lineF(p, "var $1 = nimCopy(null, $2, $3);$n",
+            [c, y.rdLoc, genTypeInfo(p, n[2].typ)])
+      r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c]
+    r.kind = resExpr
   of mConStrStr:
-    if p.target == targetJS:
-      genConStrStr(p, n, r)
-    else:
-      genConStrStrPHP(p, n, r)
+    genConStrStr(p, n, r)
   of mEqStr:
-    if p.target == targetJS:
-      binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
-    else:
-      binaryExpr(p, n, r, "", "($1 == $2)")
+    binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
   of mLeStr:
-    if p.target == targetJS:
-      binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
-    else:
-      binaryExpr(p, n, r, "", "($1 <= $2)")
+    binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
   of mLtStr:
-    if p.target == targetJS:
-      binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
-    else:
-      binaryExpr(p, n, r, "", "($1 < $2)")
+    binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
   of mIsNil: unaryExpr(p, n, r, "", "($1 === null)")
   of mEnumToStr: genRepr(p, n, r)
   of mNew, mNewFinalize: genNew(p, n)
@@ -1886,24 +1683,20 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
   of mOrd: genOrd(p, n, r)
   of mLengthStr:
-    if p.target == targetJS and n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
+    if n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
       unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
     else:
-      unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" |
-                             "strlen($1)")
-  of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1" | "strlen($1)")
+      unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
+  of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
   of mLengthSeq, mLengthOpenArray, mLengthArray:
-    unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)" |
-                           "count($1)")
+    unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
   of mXLenSeq:
-    unaryExpr(p, n, r, "", "$1.length" | "count($1)")
+    unaryExpr(p, n, r, "", "$1.length")
   of mHigh:
     if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
-      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)" |
-                             "(strlen($1)-1)")
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
     else:
-      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)" |
-                             "(count($1)-1)")
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
   of mInc:
     if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
       binaryUintExpr(p, n, r, "+", true)
@@ -1917,7 +1710,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
       if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
       else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
   of mSetLengthStr:
-    binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)")
+    binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0")
   of mSetLengthSeq:
     var x, y: TCompRes
     gen(p, n.sons[1], x)
@@ -1934,50 +1727,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)")
   of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
   of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
-  of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]")
+  of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]")
   of mInSet:
-    if p.target == targetJS:
-      binaryExpr(p, n, r, "", "($1[$2] != undefined)")
-    else:
-      let s = n.sons[1]
-      if s.kind == nkCurly:
-        var a, b, x: TCompRes
-        gen(p, n.sons[2], x)
-        r.res = rope("(")
-        r.kind = resExpr
-        for i in countup(0, sonsLen(s) - 1):
-          if i > 0: add(r.res, " || ")
-          var it = s.sons[i]
-          if it.kind == nkRange:
-            gen(p, it.sons[0], a)
-            gen(p, it.sons[1], b)
-            addf(r.res, "($1 >= $2 && $1 <= $3)", [x.res, a.res, b.res,])
-          else:
-            gen(p, it, a)
-            addf(r.res, "($1 == $2)", [x.res, a.res])
-        add(r.res, ")")
-      else:
-        binaryExpr(p, n, r, "", "isset($1[$2])")
+    binaryExpr(p, n, r, "", "($1[$2] != undefined)")
   of mNewSeq: genNewSeq(p, n)
-  of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()")
+  of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
   of mOf: genOf(p, n, r)
   of mReset: genReset(p, n)
   of mEcho: genEcho(p, n, r)
   of mNLen..mNError, mSlurp, mStaticExec:
     localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
   of mCopyStr:
-    binaryExpr(p, n, r, "", "($1.slice($2))" | "substr($1, $2)")
+    binaryExpr(p, n, r, "", "($1.slice($2))")
   of mCopyStrLast:
-    if p.target == targetJS:
-      ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
-    else:
-      ternaryExpr(p, n, r, "nimSubstr", "nimSubstr($#, $#, $#)")
+    ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
   of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
   of mNewStringOfCap:
-    if p.target == targetJS:
-      unaryExpr(p, n, r, "mnewString", "mnewString(0)")
-    else:
-      unaryExpr(p, n, r, "", "''")
+    unaryExpr(p, n, r, "mnewString", "mnewString(0)")
   of mDotDot:
     genProcForSymIfNeeded(p, n.sons[0].sym)
     genCall(p, n, r)
@@ -1985,8 +1751,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     useMagic(p, "nimParseBiggestFloat")
     genCall(p, n, r)
   of mArray:
-    if p.target == targetPHP: genToArray(p, n, r)
-    else: genCall(p, n, r)
+    genCall(p, n, r)
   else:
     genCall(p, n, r)
     #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
@@ -2003,13 +1768,13 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
     if it.kind == nkRange:
       gen(p, it.sons[0], a)
       gen(p, it.sons[1], b)
-      addf(r.res, "[$1, $2]" | "array($#,$#)", [a.res, b.res])
+      addf(r.res, "[$1, $2]", [a.res, b.res])
     else:
       gen(p, it, a)
       add(r.res, a.res)
   add(r.res, ")")
   # emit better code for constant sets:
-  if p.target == targetJS and isDeepConstExpr(n):
+  if isDeepConstExpr(n):
     inc(p.g.unique)
     let tmp = rope("ConstSet") & rope(p.g.unique)
     addf(p.g.constants, "var $1 = $2;$n", [tmp, r.res])
@@ -2017,25 +1782,25 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
 
 proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
-  r.res = rope("[" | "array(")
+  r.res = rope("[")
   r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1):
     if i > 0: add(r.res, ", ")
     gen(p, n.sons[i], a)
     add(r.res, a.res)
-  add(r.res, "]" | ")")
+  add(r.res, "]")
 
 proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
-  r.res = rope("{" | "array(")
+  r.res = rope("{")
   r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1):
     if i > 0: add(r.res, ", ")
     var it = n.sons[i]
     if it.kind == nkExprColonExpr: it = it.sons[1]
     gen(p, it, a)
-    addf(r.res, "Field$#: $#" | "$2", [i.rope, a.res])
-  r.res.add("}" | ")")
+    addf(r.res, "Field$#: $#", [i.rope, a.res])
+  r.res.add("}")
 
 proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
@@ -2059,10 +1824,10 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
     else:
       useMagic(p, "nimCopy")
       a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
-    addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res])
+    addf(initList, "$#: $#", [f.loc.r, a.res])
   let t = skipTypes(n.typ, abstractInst + skipPtrs)
   createObjInitList(p, t, fieldIDs, initList)
-  r.res = ("{$1}" | "array($#)") % [initList]
+  r.res = ("{$1}") % [initList]
 
 proc genConv(p: PProc, n: PNode, r: var TCompRes) =
   var dest = skipTypes(n.typ, abstractVarRange)
@@ -2125,18 +1890,17 @@ proc genReturnStmt(p: PProc, n: PNode) =
     genStmt(p, n.sons[0])
   else:
     genLineDir(p, n)
-  lineF(p, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
+  lineF(p, "break BeforeRet;$n", [])
 
 proc frameCreate(p: PProc; procname, filename: Rope): Rope =
   let frameFmt =
-    "var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
-    "global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n"
+    "var F={procname:$1,prev:framePtr,filename:$2,line:0};$n"
 
   result = p.indentLine(frameFmt % [procname, filename])
-  result.add p.indentLine(ropes.`%`("framePtr = F;$n" | "$$framePtr = &$$F;$n", []))
+  result.add p.indentLine(ropes.`%`("framePtr = F;$n", []))
 
 proc frameDestroy(p: PProc): Rope =
-  result = p.indentLine rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
+  result = p.indentLine rope(("framePtr = F.prev;") & tnl)
 
 proc genProcBody(p: PProc, prc: PSym): Rope =
   if hasFrameInfo(p):
@@ -2146,15 +1910,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
   else:
     result = nil
   if p.beforeRetNeeded:
-    if p.target == targetJS:
-      result.add p.indentLine(~"BeforeRet: do {$n")
-      result.add p.body
-      result.add p.indentLine(~"} while (false);$n")
-    else:
-      addF(result, "$# BeforeRet:;$n", [p.body])
+    result.add p.indentLine(~"BeforeRet: do {$n")
+    result.add p.body
+    result.add p.indentLine(~"} while (false);$n")
   else:
     add(result, p.body)
-  if prc.typ.callConv == ccSysCall and p.target == targetJS:
+  if prc.typ.callConv == ccSysCall:
     result = ("try {$n$1} catch (e) {$n" &
       " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
   if hasFrameInfo(p):
@@ -2182,7 +1943,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
     resultSym = prc.ast.sons[resultPos].sym
     let mname = mangleName(p.module, resultSym)
     let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
-    resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar])
+    resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
     if resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and
         mapType(p, resultSym.typ) == etyBaseIndex:
       resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
@@ -2267,8 +2028,7 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
     elif fromUint:
       if src.size == 4 and dest.size == 4:
         # XXX prevent multi evaluations
-        r.res = "($1|0)" % [r.res] |
-          "($1>(float)2147483647?(int)$1-4294967296:$1)" % [r.res]
+        r.res = "($1|0)" % [r.res]
       else:
         let trimmer = unsignedTrimmer(dest.size)
         let minuend = case dest.size
@@ -2304,8 +2064,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
       r.res = rope"null"
       r.kind = resExpr
   of nkStrLit..nkTripleStrLit:
-    if skipTypes(n.typ, abstractVarRange).kind == tyString and
-       p.target == targetJS:
+    if skipTypes(n.typ, abstractVarRange).kind == tyString:
       useMagic(p, "makeNimstrLit")
       r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
     else:
@@ -2342,10 +2101,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkObjConstr: genObjConstr(p, n, r)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
   of nkAddr, nkHiddenAddr:
-    if p.target == targetJS:
-      genAddr(p, n, r)
-    else:
-      gen(p, n.sons[0], r)
+    genAddr(p, n, r)
   of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
   of nkBracketExpr: genArrayAccess(p, n, r)
   of nkDotExpr: genFieldAccess(p, n, r)
@@ -2422,31 +2178,22 @@ proc newModule(module: PSym): BModule =
   if globals == nil:
     globals = newGlobals()
 
-proc genHeader(target: TTarget): Rope =
-  if target == targetJS:
-    result = (
-      "/* Generated by the Nim Compiler v$1 */$n" &
-      "/*   (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
-      "var framePtr = null;$n" &
-      "var excHandler = 0;$n" &
-      "var lastJSError = null;$n" &
-      "if (typeof Int8Array === 'undefined') Int8Array = Array;$n" &
-      "if (typeof Int16Array === 'undefined') Int16Array = Array;$n" &
-      "if (typeof Int32Array === 'undefined') Int32Array = Array;$n" &
-      "if (typeof Uint8Array === 'undefined') Uint8Array = Array;$n" &
-      "if (typeof Uint16Array === 'undefined') Uint16Array = Array;$n" &
-      "if (typeof Uint32Array === 'undefined') Uint32Array = Array;$n" &
-      "if (typeof Float32Array === 'undefined') Float32Array = Array;$n" &
-      "if (typeof Float64Array === 'undefined') Float64Array = Array;$n") %
-      [rope(VersionAsString)]
-  else:
-    result = ("<?php$n" &
-              "/* Generated by the Nim Compiler v$1 */$n" &
-              "/*   (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
-              "$$framePtr = null;$n" &
-              "$$excHandler = 0;$n" &
-              "$$lastJSError = null;$n") %
-             [rope(VersionAsString)]
+proc genHeader(): Rope =
+  result = (
+    "/* Generated by the Nim Compiler v$1 */$n" &
+    "/*   (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
+    "var framePtr = null;$n" &
+    "var excHandler = 0;$n" &
+    "var lastJSError = null;$n" &
+    "if (typeof Int8Array === 'undefined') Int8Array = Array;$n" &
+    "if (typeof Int16Array === 'undefined') Int16Array = Array;$n" &
+    "if (typeof Int32Array === 'undefined') Int32Array = Array;$n" &
+    "if (typeof Uint8Array === 'undefined') Uint8Array = Array;$n" &
+    "if (typeof Uint16Array === 'undefined') Uint16Array = Array;$n" &
+    "if (typeof Uint32Array === 'undefined') Uint32Array = Array;$n" &
+    "if (typeof Float32Array === 'undefined') Float32Array = Array;$n" &
+    "if (typeof Float64Array === 'undefined') Float64Array = Array;$n") %
+    [rope(VersionAsString)]
 
 proc genModule(p: PProc, n: PNode) =
   if optStackTrace in p.options:
@@ -2513,8 +2260,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
   result = myProcess(b, n)
   var m = BModule(b)
   if sfMainModule in m.module.flags:
-    let ext = if m.target == targetJS: "js" else: "php"
-    let f = if globals.classes.len == 0: m.module.filename
+    let ext = "js"
+    let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position)
             else: "nimsystem"
     let code = wholeCode(graph, m)
     let outfile =
@@ -2523,7 +2270,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
         else: getCurrentDir() / options.outFile
       else:
         changeFileExt(completeCFilePath(f), ext)
-    discard writeRopeIfNotEqual(genHeader(m.target) & code, outfile)
+    discard writeRopeIfNotEqual(genHeader() & code, outfile)
     for obj, content in items(globals.classes):
       genClass(obj, content, ext)
 
@@ -2533,7 +2280,6 @@ proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext =
 
 proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
   var r = newModule(s)
-  r.target = if gCmd == cmdCompileToPHP: targetPHP else: targetJS
   result = r
 
 const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index 8bd963a65..f440ee7da 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -121,26 +121,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
     addf(p.g.typeInfo, "$1.base = $2;$n",
          [name, genTypeInfo(p, typ.sons[0])])
 
-proc genEnumInfoPHP(p: PProc; t: PType): Rope =
-  let t = t.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink})
-  result = "$$NTI$1" % [rope(t.id)]
-  p.declareGlobal(t.id, result)
-  if containsOrIncl(p.g.typeInfoGenerated, t.id): return
-
-  let length = sonsLen(t.n)
-  var s: Rope = nil
-  for i in countup(0, length - 1):
-    if (t.n.sons[i].kind != nkSym): internalError(t.n.info, "genEnumInfo")
-    let field = t.n.sons[i].sym
-    if i > 0: add(s, ", " & tnl)
-    let extName = if field.ast == nil: field.name.s else: field.ast.strVal
-    addf(s, "$# => $#$n",
-         [rope(field.position), makeJSString(extName)])
-  prepend(p.g.typeInfo, "$$$# = $#;$n" % [result, s])
-
 proc genTypeInfo(p: PProc, typ: PType): Rope =
-  if p.target == targetPHP:
-    return makeJSString(typeToString(typ, preferModuleInfo))
   let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink})
   result = "NTI$1" % [rope(t.id)]
   if containsOrIncl(p.g.typeInfoGenerated, t.id): return
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index d881df5e9..775748425 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -230,7 +230,7 @@ template isIterator*(owner: PSym): bool =
 proc liftingHarmful(owner: PSym): bool {.inline.} =
   ## lambda lifting can be harmful for JS-like code generators.
   let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
-  result = gCmd in {cmdCompileToPHP, cmdCompileToJS} and not isCompileTime
+  result = gCmd == cmdCompileToJS and not isCompileTime
 
 proc liftIterSym*(n: PNode; owner: PSym): PNode =
   # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env))
@@ -813,7 +813,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
   let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
 
   if body.kind == nkEmpty or (
-      gCmd in {cmdCompileToPHP, cmdCompileToJS} and not isCompileTime) or
+      gCmd == cmdCompileToJS and not isCompileTime) or
       fn.skipGenericOwner.kind != skModule:
     # ignore forward declaration:
     result = body
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index e55da2f35..0b1090bb1 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -133,7 +133,7 @@ type
 
   TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
   TLexer* = object of TBaseLexer
-    fileIdx*: int32
+    fileIdx*: FileIndex
     indentAhead*: int         # if > 0 an indendation has already been read
                               # this is needed because scanning comments
                               # needs so much look-ahead
@@ -222,7 +222,7 @@ proc fillToken(L: var TToken) =
     L.commentOffsetA = 0
     L.commentOffsetB = 0
 
-proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream;
+proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
                  cache: IdentCache) =
   openBaseLexer(lex, inputstream)
   lex.fileIdx = fileidx
@@ -274,7 +274,7 @@ template tokenEnd(tok, pos) {.dirty.} =
   when defined(nimsuggest):
     let colB = getColNumber(L, pos)+1
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
       L.cursor = CursorPosition.InToken
       gTrackPos.col = colA.int16
     colA = 0
@@ -285,9 +285,9 @@ template tokenEndIgnore(tok, pos) =
   when defined(nimsuggest):
     let colB = getColNumber(L, pos)
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
       gTrackPos.fileIndex = trackPosInvalidFileIdx
-      gTrackPos.line = -1
+      gTrackPos.line = 0'u16
     colA = 0
   when defined(nimpretty):
     tok.offsetB = L.offsetBase + pos
@@ -299,7 +299,7 @@ template tokenEndPrevious(tok, pos) =
     # the cursor in a string literal or comment:
     let colB = getColNumber(L, pos)
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
       L.cursor = CursorPosition.BeforeToken
       gTrackPos = L.previousToken
       gTrackPosAttached = true
@@ -1003,6 +1003,10 @@ proc skip(L: var TLexer, tok: var TToken) =
   var buf = L.buf
   tokenBegin(tok, pos)
   tok.strongSpaceA = 0
+  when defined(nimpretty):
+    var hasComment = false
+    tok.commentOffsetA = L.offsetBase + pos
+    tok.commentOffsetB = tok.commentOffsetA
   while true:
     case buf[pos]
     of ' ':
@@ -1021,6 +1025,7 @@ proc skip(L: var TLexer, tok: var TToken) =
           inc(pos)
           inc(indent)
         elif buf[pos] == '#' and buf[pos+1] == '[':
+          when defined(nimpretty): hasComment = true
           skipMultiLineComment(L, tok, pos+2, false)
           pos = L.bufpos
           buf = L.buf
@@ -1034,14 +1039,11 @@ proc skip(L: var TLexer, tok: var TToken) =
     of '#':
       # do not skip documentation comment:
       if buf[pos+1] == '#': break
-      when defined(nimpretty):
-        tok.commentOffsetA = L.offsetBase + pos
+      when defined(nimpretty): hasComment = true
       if buf[pos+1] == '[':
         skipMultiLineComment(L, tok, pos+2, false)
         pos = L.bufpos
         buf = L.buf
-        when defined(nimpretty):
-          tok.commentOffsetB = L.offsetBase + pos
       else:
         tokenBegin(tok, pos)
         while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
@@ -1053,6 +1055,9 @@ proc skip(L: var TLexer, tok: var TToken) =
   tokenEndPrevious(tok, pos-1)
   L.bufpos = pos
   when defined(nimpretty):
+    if hasComment:
+      tok.commentOffsetB = L.offsetBase + pos
+      tok.tokType = tkComment
     if gIndentationWidth <= 0:
       gIndentationWidth = tok.indent
 
@@ -1061,7 +1066,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
     when defined(nimsuggest):
       # we attach the cursor to the last *strong* token
       if tok.tokType notin weakTokens:
-        L.previousToken.line = tok.line.int16
+        L.previousToken.line = tok.line.uint16
         L.previousToken.col = tok.col.int16
 
   when defined(nimsuggest):
@@ -1074,6 +1079,10 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
   else:
     tok.indent = -1
   skip(L, tok)
+  when defined(nimpretty):
+    if tok.tokType == tkComment:
+      L.indentAhead = L.currLineIndent
+      return
   var c = L.buf[L.bufpos]
   tok.line = L.lineNumber
   tok.col = getColNumber(L, L.bufpos)
@@ -1109,7 +1118,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
         tok.tokType = tkParLe
         when defined(nimsuggest):
           if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
-                    tok.line == gTrackPos.line and gIdeCmd == ideCon:
+                    tok.line == gTrackPos.line.int and gIdeCmd == ideCon:
             gTrackPos.col = tok.col.int16
     of ')':
       tok.tokType = tkParRi
@@ -1130,7 +1139,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
     of '.':
       when defined(nimsuggest):
         if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
-            tok.line == gTrackPos.line and gIdeCmd == ideSug:
+            tok.line == gTrackPos.line.int and gIdeCmd == ideSug:
           tok.tokType = tkDot
           L.cursor = CursorPosition.InToken
           gTrackPos.col = tok.col.int16
diff --git a/compiler/main.nim b/compiler/main.nim
index 20a715886..401099fc3 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -35,7 +35,7 @@ proc writeDepsFile(g: ModuleGraph; project: string) =
   let f = open(changeFileExt(project, "deps"), fmWrite)
   for m in g.modules:
     if m != nil:
-      f.writeLine(toFullPath(m.position.int32))
+      f.writeLine(toFullPath(m.position.FileIndex))
   for k in g.inclToMod.keys:
     if g.getModule(k).isNil:  # don't repeat includes which are also modules
       f.writeLine(k.toFullPath)
@@ -94,7 +94,6 @@ proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
   defineSymbol("nimrod") # 'nimrod' is always defined
   defineSymbol("ecmascript") # For backward compatibility
   defineSymbol("js")
-  if gCmd == cmdCompileToPHP: defineSymbol("nimphp")
   semanticPasses()
   registerPass(JSgenPass)
   compileProject(graph, cache)
@@ -189,9 +188,6 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
   of "js", "compiletojs":
     gCmd = cmdCompileToJS
     commandCompileToJS(graph, cache)
-  of "php":
-    gCmd = cmdCompileToPHP
-    commandCompileToJS(graph, cache)
   of "doc0":
     wantMainModule()
     gCmd = cmdDoc
@@ -269,7 +265,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
   of "parse":
     gCmd = cmdParse
     wantMainModule()
-    discard parseFile(gProjectMainIdx, cache)
+    discard parseFile(FileIndex gProjectMainIdx, cache)
   of "scan":
     gCmd = cmdScan
     wantMainModule()
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 2c59a9097..6c14a46e8 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -25,7 +25,7 @@
 ## - Its dependent module stays the same.
 ##
 
-import ast, intsets, tables, options, rod
+import ast, intsets, tables, options, rod, msgs, hashes
 
 type
   ModuleGraph* = ref object
@@ -34,10 +34,10 @@ type
     deps*: IntSet # the dependency graph or potentially its transitive closure.
     suggestMode*: bool # whether we are in nimsuggest mode or not.
     invalidTransitiveClosure: bool
-    inclToMod*: Table[int32, int32] # mapping of include file to the
-                                    # first module that included it
-    importStack*: seq[int32]  # The current import stack. Used for detecting recursive
-                              # module dependencies.
+    inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
+                                            # first module that included it
+    importStack*: seq[FileIndex]  # The current import stack. Used for detecting recursive
+                                  # module dependencies.
     backend*: RootRef # minor hack so that a backend can extend this easily
     config*: ConfigRef
     doStopCompile*: proc(): bool {.closure.}
@@ -45,6 +45,8 @@ type
     owners*: seq[PSym]
     methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
 
+proc hash*(x: FileIndex): Hash {.borrow.}
+
 {.this: g.}
 
 proc stopCompile*(g: ModuleGraph): bool {.inline.} =
@@ -56,7 +58,7 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
   result.deps = initIntSet()
   result.modules = @[]
   result.importStack = @[]
-  result.inclToMod = initTable[int32, int32]()
+  result.inclToMod = initTable[FileIndex, FileIndex]()
   if config.isNil:
     result.config = newConfigRef()
   else:
@@ -69,35 +71,35 @@ proc resetAllModules*(g: ModuleGraph) =
   deps = initIntSet()
   modules = @[]
   importStack = @[]
-  inclToMod = initTable[int32, int32]()
+  inclToMod = initTable[FileIndex, FileIndex]()
   usageSym = nil
   owners = @[]
   methods = @[]
 
-proc getModule*(g: ModuleGraph; fileIdx: int32): PSym =
-  if fileIdx >= 0 and fileIdx < modules.len:
-    result = modules[fileIdx]
+proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
+  if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:
+    result = modules[fileIdx.int32]
 
 proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
 
-proc addDep*(g: ModuleGraph; m: PSym, dep: int32) =
-  assert m.position == m.info.fileIndex
+proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
+  assert m.position == m.info.fileIndex.int32
   addModuleDep(m.info.fileIndex, dep, isIncludeFile = false)
   if suggestMode:
-    deps.incl m.position.dependsOn(dep)
+    deps.incl m.position.dependsOn(dep.int)
     # we compute the transitive closure later when quering the graph lazily.
     # this improve efficiency quite a lot:
     #invalidTransitiveClosure = true
 
-proc addIncludeDep*(g: ModuleGraph; module, includeFile: int32) =
+proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
   addModuleDep(module, includeFile, isIncludeFile = true)
   discard hasKeyOrPut(inclToMod, includeFile, module)
 
-proc parentModule*(g: ModuleGraph; fileIdx: int32): int32 =
+proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =
   ## returns 'fileIdx' if the file belonging to this index is
   ## directly used as a module or else the module that first
   ## references this include file.
-  if fileIdx >= 0 and fileIdx < modules.len and modules[fileIdx] != nil:
+  if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil:
     result = fileIdx
   else:
     result = inclToMod.getOrDefault(fileIdx)
@@ -111,11 +113,11 @@ proc transitiveClosure(g: var IntSet; n: int) =
           if g.contains(i.dependsOn(k)) and g.contains(k.dependsOn(j)):
             g.incl i.dependsOn(j)
 
-proc markDirty*(g: ModuleGraph; fileIdx: int32) =
+proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
   let m = getModule fileIdx
   if m != nil: incl m.flags, sfDirty
 
-proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) =
+proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
   # we need to mark its dependent modules D as dirty right away because after
   # nimsuggest is done with this module, the module's dirty flag will be
   # cleared but D still needs to be remembered as 'dirty'.
@@ -126,7 +128,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) =
   # every module that *depends* on this file is also dirty:
   for i in 0i32..<modules.len.int32:
     let m = modules[i]
-    if m != nil and deps.contains(i.dependsOn(fileIdx)):
+    if m != nil and deps.contains(i.dependsOn(fileIdx.int)):
       incl m.flags, sfDirty
 
 proc isDirty*(g: ModuleGraph; m: PSym): bool =
diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim
index 878c22cf8..1318b67a7 100644
--- a/compiler/modulepaths.nim
+++ b/compiler/modulepaths.nim
@@ -174,7 +174,7 @@ proc getModuleName*(n: PNode): string =
     localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
     result = ""
 
-proc checkModuleName*(n: PNode; doLocalError=true): int32 =
+proc checkModuleName*(n: PNode; doLocalError=true): FileIndex =
   # This returns the full canonical path for a given module import
   let modulename = n.getModuleName
   let fullPath = findModule(modulename, n.info.toFullPath)
diff --git a/compiler/modules.nim b/compiler/modules.nim
index a3be5a518..56bfdf662 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -13,115 +13,10 @@ import
   ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options,
   idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod
 
-when false:
-  type
-    TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
-    THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged
-
-    TModuleInMemory* = object
-      hash*: SecureHash
-      deps*: seq[int32] ## XXX: slurped files are currently not tracked
-
-      needsRecompile*: TNeedRecompile
-      hashStatus*: THashStatus
-
-  var
-    gCompiledModules: seq[PSym] = @[]
-    gMemCacheData*: seq[TModuleInMemory] = @[]
-      ## XXX: we should implement recycling of file IDs
-      ## if the user keeps renaming modules, the file IDs will keep growing
-    gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
-
-  proc hashChanged(fileIdx: int32): bool =
-    internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
-
-    template updateStatus =
-      gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged
-                                         else: hashNotChanged
-      # echo "TESTING Hash: ", fileIdx.toFilename, " ", result
-
-    case gMemCacheData[fileIdx].hashStatus
-    of hashHasChanged:
-      result = true
-    of hashNotChanged:
-      result = false
-    of hashCached:
-      let newHash = secureHashFile(fileIdx.toFullPath)
-      result = newHash != gMemCacheData[fileIdx].hash
-      gMemCacheData[fileIdx].hash = newHash
-      updateStatus()
-    of hashNotTaken:
-      gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
-      result = true
-      updateStatus()
-
-  proc doHash(fileIdx: int32) =
-    if gMemCacheData[fileIdx].hashStatus == hashNotTaken:
-      # echo "FIRST Hash: ", fileIdx.ToFilename
-      gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
-
-  proc resetModule*(fileIdx: int32) =
-    # echo "HARD RESETTING ", fileIdx.toFilename
-    if fileIdx <% gMemCacheData.len:
-      gMemCacheData[fileIdx].needsRecompile = Yes
-    if fileIdx <% gCompiledModules.len:
-      gCompiledModules[fileIdx] = nil
-    if fileIdx <% cgendata.gModules.len:
-      cgendata.gModules[fileIdx] = nil
-
-  proc resetModule*(module: PSym) =
-    let conflict = getModule(module.position.int32)
-    if conflict == nil: return
-    doAssert conflict == module
-    resetModule(module.position.int32)
-    initStrTable(module.tab)
-
-  proc resetAllModules* =
-    for i in 0..gCompiledModules.high:
-      if gCompiledModules[i] != nil:
-        resetModule(i.int32)
-    resetPackageCache()
-    # for m in cgenModules(): echo "CGEN MODULE FOUND"
-
-  proc resetAllModulesHard* =
-    resetPackageCache()
-    gCompiledModules.setLen 0
-    gMemCacheData.setLen 0
-    magicsys.resetSysTypes()
-    # XXX
-    #gOwners = @[]
-
-  proc checkDepMem(fileIdx: int32): TNeedRecompile =
-    template markDirty =
-      resetModule(fileIdx)
-      return Yes
-
-    if gFuzzyGraphChecking:
-      if gMemCacheData[fileIdx].needsRecompile != Maybe:
-        return gMemCacheData[fileIdx].needsRecompile
-    else:
-      # cycle detection: We claim that a cycle does no harm.
-      if gMemCacheData[fileIdx].needsRecompile == Probing:
-        return No
-
-    if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
-      markDirty()
-
-    if gMemCacheData[fileIdx].deps != nil:
-      gMemCacheData[fileIdx].needsRecompile = Probing
-      for dep in gMemCacheData[fileIdx].deps:
-        let d = checkDepMem(dep)
-        if d in {Yes, Recompiled}:
-          # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
-          markDirty()
-
-    gMemCacheData[fileIdx].needsRecompile = No
-    return No
-
 proc resetSystemArtifacts*() =
   magicsys.resetSysTypes()
 
-proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
+proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
   # We cannot call ``newSym`` here, because we have to circumvent the ID
   # mechanism, which we do in order to assign each module a persistent ID.
   new(result)
@@ -144,9 +39,9 @@ proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
     graph.packageSyms.strTableAdd(packSym)
 
   result.owner = packSym
-  result.position = fileIdx
+  result.position = int fileIdx
 
-  growCache graph.modules, fileIdx
+  growCache graph.modules, int fileIdx
   graph.modules[result.position] = result
 
   incl(result.flags, sfUsed)
@@ -158,7 +53,7 @@ proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
   # strTableIncl() for error corrections:
   discard strTableIncl(packSym.tab, result)
 
-proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym =
+proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, flags: TSymFlags): PSym =
   result = graph.getModule(fileIdx)
   if result == nil:
     #growCache gMemCacheData, fileIdx
@@ -199,7 +94,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags
       else:
         result = gCompiledModules[fileIdx]
 
-proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                    cache: IdentCache): PSym {.procvar.} =
   # this is called by the semantic checking phase
   result = compileModule(graph, fileIdx, cache, {})
@@ -210,11 +105,11 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
   gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
            else: ForeignPackageNotes
 
-proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                     cache: IdentCache): PNode {.procvar.} =
   result = syntaxes.parseFile(fileIdx, cache)
   graph.addDep(s, fileIdx)
-  graph.addIncludeDep(s.position.int32, fileIdx)
+  graph.addIncludeDep(s.position.FileIndex, fileIdx)
 
 proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
   if magicsys.systemModule == nil:
@@ -224,16 +119,16 @@ proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
 proc wantMainModule* =
   if gProjectFull.len == 0:
     fatal(gCmdLineInfo, errCommandExpectsFilename)
-  gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
+  gProjectMainIdx = int32 addFileExt(gProjectFull, NimExt).fileInfoIdx
 
 passes.gIncludeFile = includeModule
 passes.gImportModule = importModule
 
 proc compileProject*(graph: ModuleGraph; cache: IdentCache;
-                     projectFileIdx = -1'i32) =
+                     projectFileIdx = InvalidFileIDX) =
   wantMainModule()
   let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
-  let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
+  let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(gProjectMainIdx) else: projectFileIdx
   graph.importStack.add projectFile
   if projectFile == systemFileIdx:
     discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 70504cfc9..5ae2c4970 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -10,21 +10,24 @@
 import
   options, strutils, os, tables, ropes, platform, terminal, macros
 
+const
+  explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
+
 type
   TMsgKind* = enum
     errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
-    errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
+    errStringLiteralExpected,
     errIntLiteralExpected, errInvalidCharacterConstant,
     errClosingTripleQuoteExpected, errClosingQuoteExpected,
-    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
+    errTabulatorsAreNotAllowed, errInvalidToken,
     errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
     errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
     errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
-    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
+    errOperatorExpected, errTokenExpected,
     errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
     errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
     errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
-    errExceptionExpected, errExceptionAlreadyHandled,
+    errExceptionAlreadyHandled,
     errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
     errInvalidNumberOfYieldExpr, errCannotReturnExpr,
     errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
@@ -68,7 +71,7 @@ type
     errWrongNumberOfArgumentsInCall,
     errMissingGenericParamsForTemplate,
     errXCannotBePassedToProcVar,
-    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
+    errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
     errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
     errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
     errInvalidOrderInArrayConstructor,
@@ -87,7 +90,8 @@ type
     errNoReturnTypeDeclared,
     errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
     errXNeedsParamObjectType,
-    errTemplateInstantiationTooNested, errInstantiationFrom,
+    errTemplateInstantiationTooNested, errMacroInstantiationTooNested,
+    errInstantiationFrom,
     errInvalidIndexValueForTuple, errCommandExpectsFilename,
     errMainModuleMustBeSpecified,
     errXExpected,
@@ -144,7 +148,6 @@ const
     errIllFormedAstX: "illformed AST: $1",
     errCannotOpenFile: "cannot open \'$1\'",
     errGenerated: "$1",
-    errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
     errStringLiteralExpected: "string literal expected",
     errIntLiteralExpected: "integer literal expected",
     errInvalidCharacterConstant: "invalid character constant",
@@ -152,7 +155,6 @@ const
     errClosingQuoteExpected: "closing \" expected",
     errTabulatorsAreNotAllowed: "tabulators are not allowed",
     errInvalidToken: "invalid token: $1",
-    errLineTooLong: "line too long",
     errInvalidNumber: "$1 is not a valid number",
     errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
     errNumberOutOfRange: "number $1 out of valid range",
@@ -164,7 +166,6 @@ const
     errInvalidModuleName: "invalid module name: '$1'",
     errOperatorExpected: "operator expected, but found \'$1\'",
     errTokenExpected: "\'$1\' expected",
-    errStringAfterIncludeExpected: "string after \'include\' expected",
     errRecursiveDependencyX: "recursive dependency: \'$1\'",
     errOnOrOffExpected: "\'on\' or \'off\' expected",
     errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
@@ -174,7 +175,6 @@ const
     errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
     errEmptyAsm: "empty asm statement",
     errInvalidIndentation: "invalid indentation",
-    errExceptionExpected: "exception expected",
     errExceptionAlreadyHandled: "exception already handled",
     errYieldNotAllowedHere: "'yield' only allowed in an iterator",
     errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
@@ -280,7 +280,6 @@ const
     errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
     errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
     errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
-    errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
     errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
     errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
     errImplOfXexpected: "implementation of \'$1\' expected",
@@ -329,7 +328,8 @@ const
     errInvalidCommandX: "invalid command: \'$1\'",
     errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
     errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
-    errTemplateInstantiationTooNested: "template/macro instantiation too nested",
+    errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
+    errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
     errInstantiationFrom: "template/generic instantiation from here",
     errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
     errCommandExpectsFilename: "command expects a filename argument",
@@ -495,15 +495,18 @@ type
                                # and parsed; usually 'nil' but is used
                                # for 'nimsuggest'
     hash*: string              # the checksum of the file
-
+    when defined(nimpretty):
+      fullContent*: string
+  FileIndex* = distinct int32
   TLineInfo* = object          # This is designed to be as small as possible,
                                # because it is used
                                # in syntax nodes. We save space here by using
                                # two int16 and an int32.
                                # On 64 bit and on 32 bit systems this is
                                # only 8 bytes.
-    line*, col*: int16
-    fileIndex*: int32
+    line*: uint16
+    col*: int16
+    fileIndex*: FileIndex
     when defined(nimpretty):
       offsetA*, offsetB*: int
       commentOffsetA*, commentOffsetB*: int
@@ -517,6 +520,8 @@ type
   ERecoverableError* = object of ValueError
   ESuggestDone* = object of Exception
 
+proc `==`*(a, b: FileIndex): bool {.borrow.}
+
 const
   NotesVerbosity*: array[0..3, TNoteKinds] = [
     {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
@@ -541,14 +546,14 @@ const
     {low(TNoteKind)..high(TNoteKind)}]
 
 const
-  InvalidFileIDX* = int32(-1)
+  InvalidFileIDX* = FileIndex(-1)
 
 var
   ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
     hintQuitCalled, hintExecuting}
-  filenameToIndexTbl = initTable[string, int32]()
+  filenameToIndexTbl = initTable[string, FileIndex]()
   fileInfos*: seq[TFileInfo] = @[]
-  systemFileIdx*: int32
+  systemFileIdx*: FileIndex
 
 proc toCChar*(c: char): string =
   case c
@@ -583,6 +588,18 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
   result.quotedFullName = fullPath.makeCString
   if optEmbedOrigSrc in gGlobalOptions or true:
     result.lines = @[]
+  when defined(nimpretty):
+    if result.fullPath.len > 0:
+      try:
+        result.fullContent = readFile(result.fullPath)
+      except IOError:
+        #rawMessage(errCannotOpenFile, result.fullPath)
+        # XXX fixme
+        result.fullContent = ""
+
+when defined(nimpretty):
+  proc fileSection*(fid: FileIndex; a, b: int): string =
+    substr(fileInfos[fid.int].fullContent, a, b)
 
 proc fileInfoKnown*(filename: string): bool =
   var
@@ -593,7 +610,7 @@ proc fileInfoKnown*(filename: string): bool =
     canon = filename
   result = filenameToIndexTbl.hasKey(canon)
 
-proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
+proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
   var
     canon: string
     pseudoPath = false
@@ -611,28 +628,28 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
     result = filenameToIndexTbl[canon]
   else:
     isKnownFile = false
-    result = fileInfos.len.int32
+    result = fileInfos.len.FileIndex
     fileInfos.add(newFileInfo(canon, if pseudoPath: filename
                                      else: canon.shortenDir))
     filenameToIndexTbl[canon] = result
 
-proc fileInfoIdx*(filename: string): int32 =
+proc fileInfoIdx*(filename: string): FileIndex =
   var dummy: bool
   result = fileInfoIdx(filename, dummy)
 
-proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
+proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
   result.fileIndex = fileInfoIdx
-  result.line = int16(line)
+  result.line = uint16(line)
   result.col = int16(col)
 
 proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
   result = newLineInfo(filename.fileInfoIdx, line, col)
 
 fileInfos.add(newFileInfo("", "command line"))
-var gCmdLineInfo* = newLineInfo(int32(0), 1, 1)
+var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
 
 fileInfos.add(newFileInfo("", "compilation artifact"))
-var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
+var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
 
 proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
   raise newException(ERecoverableError, msg)
@@ -648,9 +665,9 @@ var
   gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
 
 proc unknownLineInfo*(): TLineInfo =
-  result.line = int16(-1)
+  result.line = uint16(0)
   result.col = int16(-1)
-  result.fileIndex = -1
+  result.fileIndex = InvalidFileIDX
 
 type
   Severity* {.pure.} = enum ## VS Code only supports these three
@@ -712,32 +729,32 @@ proc getInfoContext*(index: int): TLineInfo =
   if i >=% L: result = unknownLineInfo()
   else: result = msgContext[i]
 
-template toFilename*(fileIdx: int32): string =
-  (if fileIdx < 0: "???" else: fileInfos[fileIdx].projPath)
+template toFilename*(fileIdx: FileIndex): string =
+  (if fileIdx.int32 < 0: "???" else: fileInfos[fileIdx.int32].projPath)
 
-proc toFullPath*(fileIdx: int32): string =
-  if fileIdx < 0: result = "???"
-  else: result = fileInfos[fileIdx].fullPath
+proc toFullPath*(fileIdx: FileIndex): string =
+  if fileIdx.int32 < 0: result = "???"
+  else: result = fileInfos[fileIdx.int32].fullPath
 
-proc setDirtyFile*(fileIdx: int32; filename: string) =
-  assert fileIdx >= 0
-  fileInfos[fileIdx].dirtyFile = filename
+proc setDirtyFile*(fileIdx: FileIndex; filename: string) =
+  assert fileIdx.int32 >= 0
+  fileInfos[fileIdx.int32].dirtyFile = filename
 
-proc setHash*(fileIdx: int32; hash: string) =
-  assert fileIdx >= 0
-  shallowCopy(fileInfos[fileIdx].hash, hash)
+proc setHash*(fileIdx: FileIndex; hash: string) =
+  assert fileIdx.int32 >= 0
+  shallowCopy(fileInfos[fileIdx.int32].hash, hash)
 
-proc getHash*(fileIdx: int32): string =
-  assert fileIdx >= 0
-  shallowCopy(result, fileInfos[fileIdx].hash)
+proc getHash*(fileIdx: FileIndex): string =
+  assert fileIdx.int32 >= 0
+  shallowCopy(result, fileInfos[fileIdx.int32].hash)
 
-proc toFullPathConsiderDirty*(fileIdx: int32): string =
-  if fileIdx < 0:
+proc toFullPathConsiderDirty*(fileIdx: FileIndex): string =
+  if fileIdx.int32 < 0:
     result = "???"
-  elif not fileInfos[fileIdx].dirtyFile.isNil:
-    result = fileInfos[fileIdx].dirtyFile
+  elif not fileInfos[fileIdx.int32].dirtyFile.isNil:
+    result = fileInfos[fileIdx.int32].dirtyFile
   else:
-    result = fileInfos[fileIdx].fullPath
+    result = fileInfos[fileIdx.int32].fullPath
 
 template toFilename*(info: TLineInfo): string =
   info.fileIndex.toFilename
@@ -746,15 +763,15 @@ template toFullPath*(info: TLineInfo): string =
   info.fileIndex.toFullPath
 
 proc toMsgFilename*(info: TLineInfo): string =
-  if info.fileIndex < 0:
+  if info.fileIndex.int32 < 0:
     result = "???"
   elif gListFullPaths:
-    result = fileInfos[info.fileIndex].fullPath
+    result = fileInfos[info.fileIndex.int32].fullPath
   else:
-    result = fileInfos[info.fileIndex].projPath
+    result = fileInfos[info.fileIndex.int32].projPath
 
 proc toLinenumber*(info: TLineInfo): int {.inline.} =
-  result = info.line
+  result = int info.line
 
 proc toColumn*(info: TLineInfo): int {.inline.} =
   result = info.col
@@ -771,7 +788,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
   # only for debugging purposes
   result = filename in info.toFilename
 
-const trackPosInvalidFileIdx* = -2 # special marker so that no suggestions
+const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
                                    # are produced within comments and string literals
 var gTrackPos*: TLineInfo
 var gTrackPosAttached*: bool ## whether the tracking position was attached to some
@@ -910,7 +927,7 @@ proc writeContext(lastinfo: TLineInfo) =
       else:
         styledMsgWriteln(styleBright,
                          PosFormat % [toMsgFilename(msgContext[i]),
-                                      coordToStr(msgContext[i].line),
+                                      coordToStr(msgContext[i].line.int),
                                       coordToStr(msgContext[i].col+1)],
                          resetStyle,
                          getMessageStr(errInstantiationFrom, ""))
@@ -978,7 +995,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
               of warnMin..warnMax: WarningTitle
               of hintMin..hintMax: HintTitle
               else: ErrorTitle
-  result = PosFormat % [toMsgFilename(info), coordToStr(info.line),
+  result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
                         coordToStr(info.col+1)] &
            title &
            getMessageStr(msg, arg)
@@ -1019,7 +1036,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
   # NOTE: currently line info line numbers start with 1,
   # but column numbers start with 0, however most editors expect
   # first column to be 1, so we need to +1 here
-  let x = PosFormat % [toMsgFilename(info), coordToStr(info.line),
+  let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
                        coordToStr(info.col+1)]
   let s = getMessageStr(msg, arg)
 
@@ -1032,7 +1049,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
                          KindColor, `%`(KindFormat, kind))
       else:
         styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
-      if msg in errMin..errMax and hintSource in gNotes:
+      if hintSource in gNotes:
         info.writeSurroundingSrc
   handleError(msg, eh, s)
 
@@ -1077,30 +1094,30 @@ template assertNotNil*(e): untyped =
 template internalAssert*(e: bool) =
   if not e: internalError($instantiationInfo())
 
-proc addSourceLine*(fileIdx: int32, line: string) =
-  fileInfos[fileIdx].lines.add line.rope
+proc addSourceLine*(fileIdx: FileIndex, line: string) =
+  fileInfos[fileIdx.int32].lines.add line.rope
 
 proc sourceLine*(i: TLineInfo): Rope =
-  if i.fileIndex < 0: return nil
+  if i.fileIndex.int32 < 0: return nil
 
-  if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
+  if not optPreserveOrigSource and fileInfos[i.fileIndex.int32].lines.len == 0:
     try:
       for line in lines(i.toFullPath):
         addSourceLine i.fileIndex, line.string
     except IOError:
       discard
-  internalAssert i.fileIndex < fileInfos.len
+  internalAssert i.fileIndex.int32 < fileInfos.len
   # can happen if the error points to EOF:
-  if i.line > fileInfos[i.fileIndex].lines.len: return nil
+  if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
 
-  result = fileInfos[i.fileIndex].lines[i.line-1]
+  result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
 
 proc quotedFilename*(i: TLineInfo): Rope =
-  internalAssert i.fileIndex >= 0
+  internalAssert i.fileIndex.int32 >= 0
   if optExcessiveStackTrace in gGlobalOptions:
-    result = fileInfos[i.fileIndex].quotedFullName
+    result = fileInfos[i.fileIndex.int32].quotedFullName
   else:
-    result = fileInfos[i.fileIndex].quotedName
+    result = fileInfos[i.fileIndex.int32].quotedName
 
 ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
   case err
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 89225a5e0..8f3463be9 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -90,14 +90,6 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
             ex = quoteShell(
               completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
           execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments)
-        elif gCmd == cmdCompileToPHP:
-          var ex: string
-          if options.outFile.len > 0:
-            ex = options.outFile.prependCurDir.quoteShell
-          else:
-            ex = quoteShell(
-              completeCFilePath(changeFileExt(gProjectFull, "php").prependCurDir))
-          execExternalProgram("php " & ex & ' ' & commands.arguments)
         else:
           var binPath: string
           if options.outFile.len > 0:
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
index 55603f4cd..4627264dc 100644
--- a/compiler/nimfix/pretty.nim
+++ b/compiler/nimfix/pretty.nim
@@ -28,7 +28,7 @@ proc overwriteFiles*() =
   let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
   for i in 0 .. high(gSourceFiles):
     if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
-        (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx):
+        (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex):
       let newFile = if gOverWrite: gSourceFiles[i].fullpath
                     else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
       try:
@@ -95,7 +95,7 @@ proc beautifyName(s: string, k: TSymKind): string =
 proc replaceInFile(info: TLineInfo; newName: string) =
   loadFile(info)
 
-  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  let line = gSourceFiles[info.fileIndex.int].lines[info.line.int-1]
   var first = min(info.col.int, line.len)
   if first < 0: return
   #inc first, skipIgnoreCase(line, "proc ", first)
@@ -107,8 +107,8 @@ proc replaceInFile(info: TLineInfo; newName: string) =
   if differ(line, first, last, newName):
     # last-first+1 != newName.len or
     var x = line.substr(0, first-1) & newName & line.substr(last+1)
-    system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
-    gSourceFiles[info.fileIndex].dirty = true
+    system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x)
+    gSourceFiles[info.fileIndex.int].dirty = true
 
 proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
   let beau = beautifyName(s, k)
@@ -136,7 +136,7 @@ template styleCheckDef*(s: PSym) =
   styleCheckDef(s.info, s, s.kind)
 
 proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
-  if info.fileIndex < 0: return
+  if info.fileIndex.int < 0: return
   # we simply convert it to what it looks like in the definition
   # for consistency
 
diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim
index f1d24183b..ecb4b0093 100644
--- a/compiler/nimfix/prettybase.nim
+++ b/compiler/nimfix/prettybase.nim
@@ -16,13 +16,13 @@ type
     lines*: seq[string]
     dirty*, isNimfixFile*: bool
     fullpath*, newline*: string
-    fileIdx*: int32
+    fileIdx*: FileIndex
 
 var
   gSourceFiles*: seq[TSourceFile] = @[]
 
 proc loadFile*(info: TLineInfo) =
-  let i = info.fileIndex
+  let i = info.fileIndex.int
   if i >= gSourceFiles.len:
     gSourceFiles.setLen(i+1)
   if gSourceFiles[i].lines.isNil:
@@ -64,7 +64,7 @@ proc differ*(line: string, a, b: int, x: string): bool =
 proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
   loadFile(info)
 
-  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
   var first = min(info.col.int, line.len)
   if first < 0: return
   #inc first, skipIgnoreCase(line, "proc ", first)
@@ -75,8 +75,8 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
   let last = first+identLen(line, first)-1
   if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
     var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
-    system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
-    gSourceFiles[info.fileIndex].dirty = true
+    system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x)
+    gSourceFiles[info.fileIndex.int32].dirty = true
     #if newSym.s == "File": writeStackTrace()
 
 proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
@@ -85,10 +85,10 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
 proc replaceComment*(info: TLineInfo) =
   loadFile(info)
 
-  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
   var first = info.col.int
   if line[first] != '#': inc first
 
   var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
-  system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
-  gSourceFiles[info.fileIndex].dirty = true
+  system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x)
+  gSourceFiles[info.fileIndex.int32].dirty = true
diff --git a/compiler/options.nim b/compiler/options.nim
index 69a555b3f..93a3f1796 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -81,7 +81,6 @@ type
                               # **keep binary compatible**
     cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
     cmdCompileToJS,
-    cmdCompileToPHP,
     cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
     cmdGenDepend, cmdDump,
     cmdCheck,                 # semantic checking for whole project
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 8540f1b32..02c48c16d 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -235,7 +235,8 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
       result = arLValue
     else:
       result = isAssignable(owner, n.sons[0], isUnsafeAddr)
-    if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
+    if result != arNone and n[1].kind == nkSym and
+        sfDiscriminant in n[1].sym.flags:
       result = arDiscriminant
   of nkBracketExpr:
     if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 0019b7acb..ac0a57770 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -83,7 +83,7 @@ proc getTok(p: var TParser) =
   rawGetTok(p.lex, p.tok)
   p.hasProgress = true
 
-proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
+proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
                  cache: IdentCache;
                  strongSpaces=false) =
   ## Open a parser, using the given arguments to set up its internal state.
@@ -125,7 +125,13 @@ proc rawSkipComment(p: var TParser, node: PNode) =
   if p.tok.tokType == tkComment:
     if node != nil:
       if node.comment == nil: node.comment = ""
-      add(node.comment, p.tok.literal)
+      when defined(nimpretty):
+        if p.tok.commentOffsetB > p.tok.commentOffsetA:
+          add node.comment, fileSection(p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)
+        else:
+          add node.comment, p.tok.literal
+      else:
+        add(node.comment, p.tok.literal)
     else:
       parMessage(p, errInternal, "skipComment")
     getTok(p)
diff --git a/compiler/passes.nim b/compiler/passes.nim
index f079100ea..d7c181676 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -52,8 +52,8 @@ proc makePass*(open: TPassOpen = nil,
 
 # the semantic checker needs these:
 var
-  gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.}
-  gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.}
+  gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PSym {.nimcall.}
+  gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.nimcall.}
 
 # implementation
 
@@ -63,20 +63,6 @@ proc skipCodegen*(n: PNode): bool {.inline.} =
   # error count instead.
   result = msgs.gErrorCounter > 0
 
-proc astNeeded*(s: PSym): bool =
-  # The ``rodwrite`` module uses this to determine if the body of a proc
-  # needs to be stored. The passes manager frees s.sons[codePos] when
-  # appropriate to free the procedure body's memory. This is important
-  # to keep memory usage down.
-  if (s.kind in {skMethod, skProc, skFunc}) and
-      ({sfCompilerProc, sfCompileTime} * s.flags == {}) and
-      (s.typ.callConv != ccInline) and
-      (s.ast.sons[genericParamsPos].kind == nkEmpty):
-    result = false
-    # XXX this doesn't really make sense with excessive CTFE
-  else:
-    result = true
-
 const
   maxPasses = 10
 
@@ -153,7 +139,7 @@ proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) =
       m = gPasses[i].close(graph, a[i], m)
     a[i] = nil                # free the memory here
 
-proc resolveMod(module, relativeTo: string): int32 =
+proc resolveMod(module, relativeTo: string): FileIndex =
   let fullPath = findModule(module, relativeTo)
   if fullPath.len == 0:
     result = InvalidFileIDX
@@ -166,7 +152,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
   let relativeTo = m.info.toFullPath
   for module in items(implicits):
     # implicit imports should not lead to a module importing itself
-    if m.position != resolveMod(module, relativeTo):
+    if m.position != resolveMod(module, relativeTo).int32:
       var importStmt = newNodeI(nodeKind, gCmdLineInfo)
       var str = newStrNode(nkStrLit, module)
       str.info = gCmdLineInfo
@@ -180,7 +166,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
     p: TParsers
     a: TPassContextArray
     s: PLLStream
-    fileIdx = module.fileIdx
+    fileIdx = FileIndex module.fileIdx
   if module.id < 0:
     # new module caching mechanism:
     for i in 0..<gPassesLen:
diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim
index eba6f0b62..fe438d58b 100644
--- a/compiler/pbraces.nim
+++ b/compiler/pbraces.nim
@@ -19,7 +19,7 @@ proc getTok(p: var TParser) =
   ## `tok` member.
   rawGetTok(p.lex, p.tok)
 
-proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream;
+proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream;
                  cache: IdentCache) =
   ## Open a parser, using the given arguments to set up its internal state.
   ##
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index bb7801f6f..cb11564a4 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -543,7 +543,7 @@ proc pragmaLine(c: PContext, n: PNode) =
       else:
         # XXX this produces weird paths which are not properly resolved:
         n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
-        n.info.line = int16(y.intVal)
+        n.info.line = uint16(y.intVal)
     else:
       localError(n.info, errXExpected, "tuple")
   else:
diff --git a/compiler/procfind.nim b/compiler/procfind.nim
index 137765ddb..f7d86aaef 100644
--- a/compiler/procfind.nim
+++ b/compiler/procfind.nim
@@ -66,12 +66,10 @@ proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
 proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
   const flags = {ExactGenericParams, ExactTypeDescValues,
                  ExactConstraints, IgnoreCC}
-
   var it: TIdentIter
-
   result = initIdentIter(it, scope.symbols, fn.name)
   while result != nil:
-    if result.kind == fn.kind and sameType(result.typ, fn.typ, flags):
+    if result.kind == fn.kind: #and sameType(result.typ, fn.typ, flags):
       case equalParams(result.typ.n, fn.typ.n)
       of paramsEqual:
         if (sfExported notin result.flags) and (sfExported in fn.flags):
@@ -85,11 +83,8 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
         return
       of paramsNotEqual:
         discard
-
     result = nextIdentIter(it, scope.symbols)
 
-  return nil
-
 proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
   result = searchForProcNew(c, scope, fn)
   when false:
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 7d513afb1..0e631a898 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -39,8 +39,7 @@ type
     inPragma: int
     when defined(nimpretty):
       pendingNewlineCount: int
-      origContent: string
-
+    fid*: FileIndex
 
 # We render the source code in a two phases: The first
 # determines how long the subtree will likely be, the second
@@ -354,13 +353,13 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
 proc atom(g: TSrcGen; n: PNode): string =
   when defined(nimpretty):
     let comment = if n.info.commentOffsetA < n.info.commentOffsetB:
-                    " " & substr(g.origContent, n.info.commentOffsetA, n.info.commentOffsetB)
+                    " " & fileSection(g.fid, n.info.commentOffsetA, n.info.commentOffsetB)
                   else:
                     ""
     if n.info.offsetA <= n.info.offsetB:
       # for some constructed tokens this can not be the case and we're better
       # off to not mess with the offset then.
-      return substr(g.origContent, n.info.offsetA, n.info.offsetB) & comment
+      return fileSection(g.fid, n.info.offsetA, n.info.offsetB) & comment
   var f: float32
   case n.kind
   of nkEmpty: result = ""
@@ -1460,17 +1459,13 @@ proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
 proc `$`*(n: PNode): string = n.renderTree
 
 proc renderModule*(n: PNode, infile, outfile: string,
-                   renderFlags: TRenderFlags = {}) =
+                   renderFlags: TRenderFlags = {};
+                   fid = FileIndex(-1)) =
   var
     f: File
     g: TSrcGen
   initSrcGen(g, renderFlags)
-  when defined(nimpretty):
-    try:
-      g.origContent = readFile(infile)
-    except IOError:
-      rawMessage(errCannotOpenFile, infile)
-
+  g.fid = fid
   for i in countup(0, sonsLen(n) - 1):
     gsub(g, n.sons[i])
     optNL(g)
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index cde5b3a9f..878e3b11e 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -1,6 +1,6 @@
 
-import 
-  intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils, 
+import
+  intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
   sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables
 
 type
@@ -135,13 +135,13 @@ proc hasIncludes(n:PNode): bool =
     if a.kind == nkIncludeStmt:
       return true
 
-proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                     cache: IdentCache): PNode {.procvar.} =
   result = syntaxes.parseFile(fileIdx, cache)
   graph.addDep(s, fileIdx)
-  graph.addIncludeDep(s.position.int32, fileIdx)
+  graph.addIncludeDep(FileIndex s.position, fileIdx)
 
-proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode, 
+proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
                     modulePath: string, includedFiles: var IntSet,
                     cache: IdentCache): PNode =
   # Parses includes and injects them in the current tree
@@ -153,13 +153,13 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
       for i in 0..<a.len:
         var f = checkModuleName(a.sons[i])
         if f != InvalidFileIDX:
-          if containsOrIncl(includedFiles, f):
+          if containsOrIncl(includedFiles, f.int):
             localError(a.info, errRecursiveDependencyX, f.toFilename)
           else:
             let nn = includeModule(graph, module, f, cache)
-            let nnn = expandIncludes(graph, module, nn, modulePath, 
+            let nnn = expandIncludes(graph, module, nn, modulePath,
                                       includedFiles, cache)
-            excl(includedFiles, f)
+            excl(includedFiles, f.int)
             for b in nnn:
               result.add b
     else:
@@ -429,8 +429,8 @@ proc reorder*(graph: ModuleGraph, n: PNode, module: PSym, cache: IdentCache): PN
   if n.hasForbiddenPragma:
     return n
   var includedFiles = initIntSet()
-  let mpath = module.fileIdx.toFullPath
-  let n = expandIncludes(graph, module, n, mpath, 
+  let mpath = module.fileIdx.FileIndex.toFullPath
+  let n = expandIncludes(graph, module, n, mpath,
                           includedFiles, cache).splitSections
   result = newNodeI(nkStmtList, n.info)
   var deps = newSeq[(IntSet, IntSet)](n.len)
diff --git a/compiler/rod.nim b/compiler/rod.nim
index bc2f3931e..c144f15ef 100644
--- a/compiler/rod.nim
+++ b/compiler/rod.nim
@@ -9,124 +9,18 @@
 
 ## This module implements the canonalization for the various caching mechanisms.
 
-import ast, idgen
+import ast, idgen, msgs
 
 when not defined(nimSymbolfiles):
   template setupModuleCache* = discard
   template storeNode*(module: PSym; n: PNode) = discard
   template loadNode*(module: PSym; index: var int): PNode = PNode(nil)
 
-  template getModuleId*(fileIdx: int32; fullpath: string): int = getID()
+  template getModuleId*(fileIdx: FileIndex; fullpath: string): int = getID()
 
-  template addModuleDep*(module, fileIdx: int32; isIncludeFile: bool) = discard
+  template addModuleDep*(module, fileIdx: FileIndex; isIncludeFile: bool) = discard
 
   template storeRemaining*(module: PSym) = discard
 
 else:
   include rodimpl
-
-when false:
-  type
-    BlobWriter* = object
-      buf: string
-      pos: int
-
-    SerializationAction = enum acRead, acWrite
-
-  # Varint implementation inspired by SQLite.
-  proc rdVaruint64(z: ptr UncheckedArray[byte]; n: int; pResult: var uint64): int =
-    if z[0] <= 240:
-      pResult = z[0]
-      return 1
-    if z[0] <= 248:
-      if n < 2: return 0
-      pResult = (z[0] - 241) * 256 + z[1] + 240
-      return 2
-    if n < z[0]-246: return 0
-    if z[0] == 249:
-      pResult = 2288 + 256*z[1] + z[2]
-      return 3
-    if z[0] == 250:
-      pResult = (z[1] shl 16u64) + (z[2] shl 8u64) + z[3]
-      return 4
-    let x = (z[1] shl 24) + (z[2] shl 16) + (z[3] shl 8) + z[4]
-    if z[0] == 251:
-      pResult = x
-      return 5
-    if z[0] == 252:
-      pResult = (((uint64)x) shl 8) + z[5]
-      return 6
-    if z[0] == 253:
-      pResult = (((uint64)x) shl 16) + (z[5] shl 8) + z[6]
-      return 7
-    if z[0] == 254:
-      pResult = (((uint64)x) shl 24) + (z[5] shl 16) + (z[6] shl 8) + z[7]
-      return 8
-    pResult = (((uint64)x) shl 32) +
-                (0xffffffff & ((z[5] shl 24) + (z[6] shl 16) + (z[7] shl 8) + z[8]))
-    return 9
-
-  proc varintWrite32(z: ptr UncheckedArray[byte]; y: uint32) =
-    z[0] = uint8(y shr 24)
-    z[1] = uint8(y shr 16)
-    z[2] = uint8(y shr 8)
-    z[3] = uint8(y)
-
-  proc sqlite4PutVarint64(z: ptr UncheckedArray[byte], x: uint64): int =
-    ## Write a varint into z. The buffer z must be at least 9 characters
-    ## long to accommodate the largest possible varint. Returns the number of
-    ## bytes used.
-    if x <= 240:
-      z[0] = uint8 x
-      return 1
-    if x <= 2287:
-      y = uint32(x - 240)
-      z[0] = uint8(y shr 8 + 241)
-      z[1] = uint8(y and 255)
-      return 2
-    if x <= 67823:
-      y = uint32(x - 2288)
-      z[0] = 249
-      z[1] = uint8(y shr 8)
-      z[2] = uint8(y and 255)
-      return 3
-    let y = uint32 x
-    let w = uint32(x shr 32)
-    if w == 0:
-      if y <= 16777215:
-        z[0] = 250
-        z[1] = uint8(y shr 16)
-        z[2] = uint8(y shr 8)
-        z[3] = uint8(y)
-        return 4
-      z[0] = 251
-      varintWrite32(z+1, y)
-      return 5
-    if w <= 255:
-      z[0] = 252
-      z[1] = uint8 w
-      varintWrite32(z+2, y)
-      return 6
-    if w <= 65535:
-      z[0] = 253
-      z[1] = uint8(w shr 8)
-      z[2] = uint8 w
-      varintWrite32(z+3, y)
-      return 7
-    if w <= 16777215:
-      z[0] = 254
-      z[1] = uint8(w shr 16)
-      z[2] = uint8(w shr 8)
-      z[3] = uint8 w
-      varintWrite32(z+4, y)
-      return 8
-    z[0] = 255
-    varintWrite32(z+1, w)
-    varintWrite32(z+5, y)
-    return 9
-
-  template field(x: BiggestInt; action: SerializationAction) =
-    when action == acRead:
-      readBiggestInt(x)
-    else:
-      writeBiggestInt()
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 84f175cb5..aa699e337 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -126,8 +126,8 @@ type
     s: cstring               # mmap'ed file contents
     options: TOptions
     reason: TReasonForRecompile
-    modDeps: seq[int32]
-    files: seq[int32]
+    modDeps: seq[FileIndex]
+    files: seq[FileIndex]
     dataIdx: int             # offset of start of data section
     convertersIdx: int       # offset of start of converters section
     initIdx, interfIdx, compilerProcsIdx, methodsIdx: int
@@ -163,11 +163,11 @@ proc decodeLineInfo(r: PRodReader, info: var TLineInfo) =
     else: info.col = int16(decodeVInt(r.s, r.pos))
     if r.s[r.pos] == ',':
       inc(r.pos)
-      if r.s[r.pos] == ',': info.line = -1'i16
-      else: info.line = int16(decodeVInt(r.s, r.pos))
+      if r.s[r.pos] == ',': info.line = 0'u16
+      else: info.line = uint16(decodeVInt(r.s, r.pos))
       if r.s[r.pos] == ',':
         inc(r.pos)
-        info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], info.line, info.col)
+        info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], int info.line, info.col)
 
 proc skipNode(r: PRodReader) =
   assert r.s[r.pos] == '('
@@ -586,7 +586,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
   # new command forces us to consider it here :-)
   case old
   of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
-      cmdCompileToJS, cmdCompileToPHP, cmdCompileToLLVM:
+      cmdCompileToJS, cmdCompileToLLVM:
     if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef,
                cmdInteractive}:
       return false
@@ -861,29 +861,29 @@ proc loadMethods(r: PRodReader) =
     r.methods.add(rrGetSym(r, d, unknownLineInfo()))
     if r.s[r.pos] == ' ': inc(r.pos)
 
-proc getHash*(fileIdx: int32): SecureHash =
-  if fileIdx <% gMods.len and gMods[fileIdx].hashDone:
-    return gMods[fileIdx].hash
+proc getHash*(fileIdx: FileIndex): SecureHash =
+  if fileIdx.int32 <% gMods.len and gMods[fileIdx.int32].hashDone:
+    return gMods[fileIdx.int32].hash
 
   result = secureHashFile(fileIdx.toFullPath)
-  if fileIdx >= gMods.len: setLen(gMods, fileIdx+1)
-  gMods[fileIdx].hash = result
+  if fileIdx.int32 >= gMods.len: setLen(gMods, fileIdx.int32+1)
+  gMods[fileIdx.int32].hash = result
 
 template growCache*(cache, pos) =
   if cache.len <= pos: cache.setLen(pos+1)
 
-proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile =
+proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
   assert fileIdx != InvalidFileIDX
-  growCache gMods, fileIdx
-  if gMods[fileIdx].reason != rrEmpty:
+  growCache gMods, fileIdx.int32
+  if gMods[fileIdx.int32].reason != rrEmpty:
     # reason has already been computed for this module:
-    return gMods[fileIdx].reason
+    return gMods[fileIdx.int32].reason
   let filename = fileIdx.toFilename
   var hash = getHash(fileIdx)
-  gMods[fileIdx].reason = rrNone  # we need to set it here to avoid cycles
+  gMods[fileIdx.int32].reason = rrNone  # we need to set it here to avoid cycles
   result = rrNone
   var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
-  var r = newRodReader(rodfile, hash, fileIdx, cache)
+  var r = newRodReader(rodfile, hash, fileIdx.int32, cache)
   if r == nil:
     result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
   else:
@@ -907,19 +907,18 @@ proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile =
     # recompilation is necessary:
     if r != nil: memfiles.close(r.memfile)
     r = nil
-  gMods[fileIdx].rd = r
-  gMods[fileIdx].reason = result  # now we know better
+  gMods[fileIdx.int32].rd = r
+  gMods[fileIdx.int32].reason = result  # now we know better
 
 proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
-  let fileIdx = module.fileIdx
   if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}:
     module.id = getID()
     return nil
   idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
-
+  let fileIdx = FileIndex module.fileIdx
   discard checkDep(fileIdx, cache)
-  if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile")
-  result = gMods[fileIdx].rd
+  if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
+  result = gMods[fileIdx.int32].rd
   if result != nil:
     module.id = result.moduleID
     result.syms[module.id] = module
@@ -1153,7 +1152,7 @@ proc viewFile(rodfile: string) =
         if r.s[r.pos] == '\x0A':
           inc(r.pos)
           inc(r.line)
-        outf.write(w, " ", inclHash, "\n")
+        outf.write(w.int32, " ", inclHash, "\n")
       if r.s[r.pos] == ')': inc(r.pos)
       outf.write(")\n")
     of "DEPS":
@@ -1163,7 +1162,7 @@ proc viewFile(rodfile: string) =
         let v = int32(decodeVInt(r.s, r.pos))
         r.modDeps.add(r.files[v])
         if r.s[r.pos] == ' ': inc(r.pos)
-        outf.write(" ", r.files[v])
+        outf.write(" ", r.files[v].int32)
       outf.write("\n")
     of "INTERF",  "COMPILERPROCS":
       inc r.pos, 2
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 96deb1d5a..0ae687268 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -55,7 +55,7 @@ proc fileIdx(w: PRodWriter, filename: string): int =
   w.files[result] = filename
 
 template filename*(w: PRodWriter): string =
-  w.module.filename
+  toFilename(FileIndex w.module.position)
 
 proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter =
   new(result)
@@ -125,14 +125,14 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
     result.add('?')
     encodeVInt(n.info.col, result)
     result.add(',')
-    encodeVInt(n.info.line, result)
+    encodeVInt(int n.info.line, result)
     result.add(',')
     encodeVInt(fileIdx(w, toFullPath(n.info)), result)
   elif fInfo.line != n.info.line:
     result.add('?')
     encodeVInt(n.info.col, result)
     result.add(',')
-    encodeVInt(n.info.line, result)
+    encodeVInt(int n.info.line, result)
   elif fInfo.col != n.info.col:
     result.add('?')
     encodeVInt(n.info.col, result)
@@ -303,7 +303,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
   result.add('?')
   if s.info.col != -1'i16: encodeVInt(s.info.col, result)
   result.add(',')
-  if s.info.line != -1'i16: encodeVInt(s.info.line, result)
+  if s.info.line != 0'u16: encodeVInt(int s.info.line, result)
   result.add(',')
   encodeVInt(fileIdx(w, toFullPath(s.info)), result)
   if s.owner != nil:
@@ -642,7 +642,7 @@ proc process(c: PPassContext, n: PNode): PNode =
 
 proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   if module.id < 0: internalError("rodwrite: module ID not set")
-  var w = newRodWriter(rodread.getHash module.fileIdx, module, cache)
+  var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache)
   rawAddInterfaceSym(w, module)
   result = w
 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 4fef1bc60..041f2e127 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -377,7 +377,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
   ## reassigned, and binding the unbound identifiers that the macro output
   ## contains.
   inc(evalTemplateCounter)
-  if evalTemplateCounter > 100:
+  if evalTemplateCounter > evalTemplateLimit:
     globalError(s.info, errTemplateInstantiationTooNested)
   c.friendModules.add(s.owner.getModule)
 
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 3996188dc..bcc1bba15 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -144,7 +144,7 @@ proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
 
 proc filename*(c: PContext): string =
   # the module's filename
-  return c.module.filename
+  return toFilename(FileIndex c.module.position)
 
 proc scopeDepth*(c: PContext): int {.inline.} =
   result = if c.currentScope != nil: c.currentScope.depthLevel
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 4256e0aa6..279b6cc57 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -526,6 +526,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
         if isAssignable(c, it) notin {arLValue, arLocalLValue}:
           if it.kind != nkHiddenAddr:
             localError(it.info, errVarForOutParamNeededX, $it)
+    # bug #5113: disallow newSeq(result) where result is a 'var T':
+    if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}:
+      var arg = n[1] #.skipAddr
+      if arg.kind == nkHiddenDeref: arg = arg[0]
+      if arg.kind == nkSym and arg.sym.kind == skResult and
+          arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}:
+        localError(n.info, errXStackEscape, renderTree(n[1], {renderNoComments}))
+
     return
   for i in countup(1, sonsLen(n) - 1):
     if n.sons[i].kind == nkHiddenCallConv:
@@ -1334,11 +1342,11 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
   let root = exprRoot(n)
   if root != nil and root.owner == c.p.owner:
     if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags:
-      localError(n.info, "'$1' escapes its stack frame; context: '$2'" % [
-        root.name.s, renderTree(n, {renderNoComments})])
+      localError(n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [
+        root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
     elif root.kind == skParam and root.position != 0:
-      localError(n.info, "'$1' is not the first parameter; context: '$2'" % [
-        root.name.s, renderTree(n, {renderNoComments})])
+      localError(n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [
+        root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
   case n.kind
   of nkHiddenAddr, nkAddr: return n
   of nkHiddenDeref, nkDerefExpr: return n.sons[0]
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 096fc19e0..6fcc9a0a4 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -483,6 +483,19 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
 
 proc getConstExpr(m: PSym, n: PNode): PNode =
   result = nil
+
+  proc getSrcTimestamp(): DateTime =
+    try:
+      result = utc(fromUnix(parseInt(getEnv("SOURCE_DATE_EPOCH",
+                                            "not a number"))))
+    except ValueError:
+      # Environment variable malformed.
+      # https://reproducible-builds.org/specs/source-date-epoch/: "If the
+      # value is malformed, the build process SHOULD exit with a non-zero
+      # error code", which this doesn't do. This uses local time, because
+      # that maintains compatibility with existing usage.
+      result = local(getTime())
+
   case n.kind
   of nkSym:
     var s = n.sym
@@ -492,8 +505,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
     of skConst:
       case s.magic
       of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
-      of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
-      of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
+      of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(),
+                                                   "yyyy-MM-dd"), n)
+      of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
+                                                   "HH:mm:ss"), n)
       of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
       of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
       of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index f90e5c5f9..8d7747fb4 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -779,20 +779,15 @@ proc semRaise(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
   if n[0].kind != nkEmpty:
-
     n[0] = semExprWithType(c, n[0])
     let typ = n[0].typ
-
     if not isImportedException(typ):
-
       if typ.kind != tyRef or typ.lastSon.kind != tyObject:
         localError(n.info, errExprCannotBeRaised)
-
       if not isException(typ.lastSon):
         localError(n.info, "raised object of type $1 does not inherit from Exception",
                           [typeToString(typ)])
 
-
 proc addGenericParamListToScope(c: PContext, n: PNode) =
   if n.kind != nkGenericParams: illFormedAst(n)
   for i in countup(0, sonsLen(n)-1):
@@ -1100,12 +1095,12 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
       for i in 0..<n.len:
         var f = checkModuleName(n.sons[i])
         if f != InvalidFileIDX:
-          if containsOrIncl(c.includedFiles, f):
+          if containsOrIncl(c.includedFiles, f.int):
             localError(n.info, errRecursiveDependencyX, f.toFilename)
           else:
             let code = gIncludeFile(c.graph, c.module, f, c.cache)
             gatherStmts c, code, result
-            excl(c.includedFiles, f)
+            excl(c.includedFiles, f.int)
     of nkStmtList:
       for i in 0 ..< n.len:
         gatherStmts(c, n.sons[i], result)
@@ -1789,11 +1784,11 @@ proc evalInclude(c: PContext, n: PNode): PNode =
   for i in countup(0, sonsLen(n) - 1):
     var f = checkModuleName(n.sons[i])
     if f != InvalidFileIDX:
-      if containsOrIncl(c.includedFiles, f):
+      if containsOrIncl(c.includedFiles, f.int):
         localError(n.info, errRecursiveDependencyX, f.toFilename)
       else:
         addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache)))
-        excl(c.includedFiles, f)
+        excl(c.includedFiles, f.int)
 
 proc setLine(n: PNode, info: TLineInfo) =
   for i in 0 ..< safeLen(n): setLine(n.sons[i], info)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index af31495aa..555ec9867 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -415,7 +415,7 @@ when defined(nimsuggest):
   # Since TLineInfo defined a == operator that doesn't include the column,
   # we map TLineInfo to a unique int here for this lookup table:
   proc infoToInt(info: TLineInfo): int64 =
-    info.fileIndex + info.line.int64 shl 32 + info.col.int64 shl 48
+    info.fileIndex.int64 + info.line.int64 shl 32 + info.col.int64 shl 48
 
   proc addNoDup(s: PSym; info: TLineInfo) =
     # ensure nothing gets too slow:
@@ -574,7 +574,7 @@ proc suggestEnum*(c: PContext; n: PNode; t: PType) =
   if outputs.len > 0: suggestQuit()
 
 proc suggestSentinel*(c: PContext) =
-  if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex: return
+  if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return
   if c.compilesContextId > 0: return
   inc(c.compilesContextId)
   var outputs: Suggestions = @[]
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index 4745b1ac7..4014d4c58 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -138,7 +138,7 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
   else:
     result = applyFilter(p, n, filename, result)
 
-proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream;
+proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
                   cache: IdentCache) =
   var s: PLLStream
   p.skin = skinStandard
@@ -155,7 +155,7 @@ proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream;
 proc closeParsers*(p: var TParsers) =
   parser.closeParser(p.parser)
 
-proc parseFile*(fileIdx: int32; cache: IdentCache): PNode {.procvar.} =
+proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} =
   var
     p: TParsers
     f: File
diff --git a/compiler/types.nim b/compiler/types.nim
index a930779bf..5d60fa9b4 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -777,8 +777,8 @@ proc equalParams(a, b: PNode): TParamsEquality =
         return paramsNotEqual # paramsIncompatible;
       # continue traversal! If not equal, we can return immediately; else
       # it stays incompatible
-    if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}):
-      if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
+    if not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}):
+      if (a.typ == nil) or (b.typ == nil):
         result = paramsNotEqual # one proc has a result, the other not is OK
       else:
         result = paramsIncompatible # overloading by different
@@ -970,7 +970,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       result = sameFlags(a, b)
   of tyGenericParam:
     result = sameChildrenAux(a, b, c) and sameFlags(a, b)
-    if result and ExactGenericParams in c.flags:
+    if result and {ExactGenericParams, ExactTypeDescValues} * c.flags != {}:
       result = a.sym.position == b.sym.position
   of tyGenericInvocation, tyGenericBody, tySequence,
      tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyLent, tySink,
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 09226988a..32db8f378 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1381,7 +1381,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNGetLine:
       decodeB(rkNode)
       let n = regs[rb].node
-      regs[ra].node = newIntNode(nkIntLit, n.info.line)
+      regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
       regs[ra].node.info = n.info
       regs[ra].node.typ = n.typ
     of opcNGetColumn:
@@ -1397,8 +1397,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let bNode = regs[rc].node
       # these are cstring to prevent string copy, and cmpIgnoreStyle from
       # takes cstring arguments
-      var aStrVal: cstring
-      var bStrVal: cstring
+      var aStrVal: cstring = nil
+      var bStrVal: cstring = nil
       # extract strVal from argument ``a``
       case aNode.kind
       of {nkStrLit..nkTripleStrLit}:
@@ -1407,8 +1407,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         aStrVal = aNode.ident.s.cstring
       of nkSym:
         aStrVal = aNode.sym.name.s.cstring
+      of nkOpenSymChoice, nkClosedSymChoice:
+        aStrVal = aNode[0].sym.name.s.cstring
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+        discard
       # extract strVal from argument ``b``
       case bNode.kind
       of {nkStrLit..nkTripleStrLit}:
@@ -1417,11 +1419,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         bStrVal = bNode.ident.s.cstring
       of nkSym:
         bStrVal = bNode.sym.name.s.cstring
+      of nkOpenSymChoice, nkClosedSymChoice:
+        bStrVal = bNode[0].sym.name.s.cstring
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+        discard
       # set result
       regs[ra].intVal =
-        ord(idents.cmpIgnoreStyle(aStrVal,bStrVal,high(int)) == 0)
+        if aStrVal != nil and bStrVal != nil:
+          ord(idents.cmpIgnoreStyle(aStrVal,bStrVal,high(int)) == 0)
+        else:
+          0
+
     of opcStrToIdent:
       decodeB(rkNode)
       if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
@@ -1513,7 +1521,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let x = newNodeI(TNodeKind(int(k)),
         if cc.kind != nkNilLit:
           cc.info
-        elif c.comesFromHeuristic.line > -1:
+        elif c.comesFromHeuristic.line != 0'u16:
           c.comesFromHeuristic
         elif c.callsite != nil and c.callsite.safeLen > 1:
           c.callsite[1].info
@@ -1685,7 +1693,7 @@ proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode,
   newSeq(tos.slots, c.prc.maxSlots)
   #for i in 0 ..< c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
   result = rawExecute(c, start, tos).regToNode
-  if result.info.line < 0: result.info = n.info
+  if result.info.col < 0: result.info = n.info
 
 proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode =
   result = evalConstExprAux(module, cache, nil, e, emConst)
@@ -1721,14 +1729,16 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
     let posInCall = macroSym.typ.len + i
     yield (genericParam, call[posInCall])
 
+# to prevent endless recursion in macro instantiation
+const evalMacroLimit = 1000
 var evalMacroCounter: int
 
 proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
                     sym: PSym): PNode =
   # XXX globalError() is ugly here, but I don't know a better solution for now
   inc(evalMacroCounter)
-  if evalMacroCounter > 100:
-    globalError(n.info, errTemplateInstantiationTooNested)
+  if evalMacroCounter > evalMacroLimit:
+    globalError(n.info, errMacroInstantiationTooNested)
 
   # immediate macros can bypass any type and arity checking so we check the
   # arity here too:
@@ -1738,7 +1748,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
 
   setupGlobalCtx(module, cache)
   var c = globalCtx
-  c.comesFromHeuristic.line = -1
+  c.comesFromHeuristic.line = 0'u16
 
   c.callsite = nOrig
   let start = genProc(c, sym)
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 214ac8dd2..bf7dd7fb4 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -76,7 +76,7 @@ Advanced options:
   --NimblePath:PATH         add a path for Nimble support
   --noNimblePath            deactivate the Nimble path
   --noCppExceptions         use default exception handling with C++ backend
-  --cppCompileToNamespace   use namespace "Nim" for the generated C++ code 
+  --cppCompileToNamespace   use namespace "Nim" for the generated C++ code
   --excludePath:PATH        exclude a path from the list of search paths
   --dynlibOverride:SYMBOL   marks SYMBOL so that dynlib:SYMBOL
                             has no effect and can be statically linked instead;
diff --git a/doc/basicopt.txt b/doc/basicopt.txt
index 4db2d5af7..4c11cc767 100644
--- a/doc/basicopt.txt
+++ b/doc/basicopt.txt
@@ -36,7 +36,7 @@ Options:
   --app:console|gui|lib|staticlib
                             generate a console app|GUI app|DLL|static library
   -r, --run                 run the compiled program with given arguments
-  --advanced                show advanced command line switches
+  --fullhelp                show all command line switches
   -h, --help                show this help
 
 Note, single letter options that take an argument require a colon. E.g. -p:PATH.
diff --git a/doc/manual.rst b/doc/manual.rst
index b114f0a8a..fbd043020 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -3487,17 +3487,17 @@ returned value is an l-value and can be modified by the caller:
 .. code-block:: nim
   var g = 0
 
-  proc WriteAccessToG(): var int =
+  proc writeAccessToG(): var int =
     result = g
 
-  WriteAccessToG() = 6
+  writeAccessToG() = 6
   assert g == 6
 
 It is a compile time error if the implicitly introduced pointer could be
 used to access a location beyond its lifetime:
 
 .. code-block:: nim
-  proc WriteAccessToG(): var int =
+  proc writeAccessToG(): var int =
     var g = 0
     result = g # Error!
 
@@ -3512,6 +3512,24 @@ In the standard library every name of a routine that returns a ``var`` type
 starts with the prefix ``m`` per convention.
 
 
+.. include:: manual/var_t_return.rst
+
+Future directions
+~~~~~~~~~~~~~~~~~
+
+Later versions of Nim can be more precise about the borrowing rule with
+a syntax like:
+
+.. code-block:: nim
+  proc foo(other: Y; container: var X): var T from container
+
+Here ``var T from container`` explicitly exposes that the
+location is deviated from the second parameter (called
+'container' in this case). The syntax ``var T from p`` specifies a type
+``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``.
+
+
+
 Overloading of the subscript operator
 -------------------------------------
 
@@ -5241,15 +5259,21 @@ chance to convert it into a sequence.
 Macros
 ======
 
-A macro is a special kind of low level template. Macros can be used
-to implement `domain specific languages`:idx:.
+A macro is a special function that is executed at compile-time.
+Normally the input for a macro is an abstract syntax
+tree (AST) of the code that is passed to it. The macro can then do
+transformations on it and return the transformed AST. The
+transformed AST is then passed to the compiler as if the macro
+invocation would have been replaced by its result in the source
+code. This can be used to implement `domain specific
+languages`:idx:.
 
 While macros enable advanced compile-time code transformations, they
 cannot change Nim's syntax. However, this is no real restriction because
 Nim's syntax is flexible enough anyway.
 
 To write macros, one needs to know how the Nim concrete syntax is converted
-to an abstract syntax tree.
+to an AST.
 
 There are two ways to invoke a macro:
 (1) invoking a macro like a procedure call (`expression macros`)
@@ -5269,19 +5293,21 @@ variable number of arguments:
   # ``macros`` module:
   import macros
 
-  macro debug(n: varargs[untyped]): untyped =
-    # `n` is a Nim AST that contains the whole macro invocation
-    # this macro returns a list of statements:
-    result = newNimNode(nnkStmtList, n)
+  macro debug(args: varargs[untyped]): untyped =
+    # `args` is a collection of `NimNode` values that each contain the
+    # AST for an argument of the macro. A macro always has to
+    # return a `NimNode`. A node of kind `nnkStmtList` is suitable for
+    # this use case.
+    result = nnkStmtList.newTree()
     # iterate over any argument that is passed to this macro:
-    for i in 0..n.len-1:
+    for n in args:
       # add a call to the statement list that writes the expression;
       # `toStrLit` converts an AST to its string representation:
-      add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+      result.add newCall("write", newIdentNode("stdout"), newLit(n.repr))
       # add a call to the statement list that writes ": "
-      add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+      result.add newCall("write", newIdentNode("stdout"), newLit(": "))
       # add a call to the statement list that writes the expressions value:
-      add(result, newCall("writeLine", newIdentNode("stdout"), n[i]))
+      result.add newCall("writeLine", newIdentNode("stdout"), n)
 
   var
     a: array[0..10, int]
@@ -8187,5 +8213,3 @@ validation errors:
 
 If the taint mode is turned off, ``TaintedString`` is simply an alias for
 ``string``.
-
-
diff --git a/doc/manual/var_t_return.rst b/doc/manual/var_t_return.rst
new file mode 100644
index 000000000..b9ff1d892
--- /dev/null
+++ b/doc/manual/var_t_return.rst
@@ -0,0 +1,20 @@
+Memory safety for returning by ``var T`` is ensured by a simple borrowing
+rule: If ``result`` does not refer to a location pointing to the heap
+(that is in ``result = X`` the ``X`` involves a ``ptr`` or ``ref`` access)
+then it has to be deviated by the routine's first parameter:
+
+.. code-block:: nim
+  proc forward[T](x: var T): var T =
+    result = x # ok, deviated from the first parameter.
+
+  proc p(param: var int): var int =
+    var x: int
+    # we know 'forward' provides a view into the location deviated by
+    # its first argument 'x'.
+    result = forward(x) # Error: location is derived from ``x``
+                        # which is not p's first parameter and lives
+                        # on the stack.
+
+In other words, the lifetime of what ``result`` points to is attached to the
+lifetime of the first parameter and that is enough knowledge to verify
+memory safety at the callsite.
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 993756b28..1dc067e1a 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -706,8 +706,7 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
     res.add(($n.kind).substr(3))
 
     case n.kind
-    of nnkEmpty: discard # same as nil node in this representation
-    of nnkNilLit: res.add(" nil")
+    of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
     of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
     of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
     of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym:
@@ -730,8 +729,7 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
   add(result, "(")
 
   case n.kind
-  of nnkEmpty: discard # same as nil node in this representation
-  of nnkNilLit: add(result, "nil")
+  of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
   of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
   of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
   of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym:
@@ -766,7 +764,7 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
   ## See also `repr`, `treeRepr`, and `lispRepr`.
 
   const
-    NodeKinds = {nnkEmpty, nnkNilLit, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
+    NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
     LitKinds = {nnkCharLit..nnkInt64Lit, nnkFloatLit..nnkFloat64Lit, nnkStrLit..nnkTripleStrLit}
 
   proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
@@ -775,12 +773,13 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
       res.add("new" & ($n.kind).substr(3) & "Node(")
     elif n.kind in LitKinds:
       res.add("newLit(")
+    elif n.kind == nnkNilLit:
+      res.add("newNilLit()")
     else:
       res.add($n.kind)
 
     case n.kind
-    of nnkEmpty: discard
-    of nnkNilLit: res.add("nil")
+    of nnkEmpty, nnkNilLit: discard
     of nnkCharLit: res.add("'" & $chr(n.intVal) & "'")
     of nnkIntLit..nnkInt64Lit: res.add($n.intVal)
     of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal)
@@ -1289,7 +1288,11 @@ proc customPragmaNode(n: NimNode): NimNode =
     typ = n.getTypeInst()
 
   if typ.typeKind == ntyTypeDesc:
-    return typ[1].getImpl()[0][1]
+    let impl = typ[1].getImpl()
+    if impl[0].kind == nnkPragmaExpr:
+      return impl[0][1]
+    else:
+      return impl[0] # handle types which don't have macro at all
 
   if n.kind == nnkSym: # either an variable or a proc
     let impl = n.getImpl()
diff --git a/lib/deprecated/pure/asyncio.nim b/lib/deprecated/pure/asyncio.nim
index 5fd45b215..34cabefb0 100644
--- a/lib/deprecated/pure/asyncio.nim
+++ b/lib/deprecated/pure/asyncio.nim
@@ -101,8 +101,8 @@ when defined(windows):
   from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
     FD_ISSET, select
 else:
-  from posix import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
-    FD_ISSET, select
+  from posix import TimeVal, Time, Suseconds, SocketHandle, FD_SET, FD_ZERO,
+    TFdSet, FD_ISSET, select
 
 type
   DelegateObj* = object
@@ -556,8 +556,12 @@ proc send*(sock: AsyncSocket, data: string) =
 proc timeValFromMilliseconds(timeout = 500): Timeval =
   if timeout != -1:
     var seconds = timeout div 1000
-    result.tv_sec = seconds.int32
-    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+    when defined(posix):
+      result.tv_sec = seconds.Time
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds
+    else:
+      result.tv_sec = seconds.int32
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
 
 proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) =
   FD_ZERO(fd)
diff --git a/lib/deprecated/pure/sockets.nim b/lib/deprecated/pure/sockets.nim
index f068c7d56..f0568366a 100644
--- a/lib/deprecated/pure/sockets.nim
+++ b/lib/deprecated/pure/sockets.nim
@@ -953,8 +953,12 @@ when defined(ssl):
 proc timeValFromMilliseconds(timeout = 500): Timeval =
   if timeout != -1:
     var seconds = timeout div 1000
-    result.tv_sec = seconds.int32
-    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+    when defined(posix):
+      result.tv_sec = seconds.Time
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds
+    else:
+      result.tv_sec = seconds.int32
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
 
 proc createFdSet(fd: var TFdSet, s: seq[Socket], m: var int) =
   FD_ZERO(fd)
diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim
index 9e6211b63..4f114d394 100644
--- a/lib/posix/posix_linux_amd64.nim
+++ b/lib/posix/posix_linux_amd64.nim
@@ -351,8 +351,8 @@ type
 
   Timeval* {.importc: "struct timeval", header: "<sys/select.h>",
              final, pure.} = object ## struct timeval
-    tv_sec*: clong       ## Seconds.
-    tv_usec*: clong ## Microseconds.
+    tv_sec*: Time       ## Seconds.
+    tv_usec*: Suseconds ## Microseconds.
   TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
            final, pure.} = object
     abi: array[1024 div (8 * sizeof(clong)), clong]
diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim
index 01bc1c1e5..ae41263e8 100644
--- a/lib/posix/posix_other.nim
+++ b/lib/posix/posix_other.nim
@@ -335,8 +335,8 @@ type
 
   Timeval* {.importc: "struct timeval", header: "<sys/select.h>",
              final, pure.} = object ## struct timeval
-    tv_sec*: int       ## Seconds.
-    tv_usec*: int ## Microseconds.
+    tv_sec*: Time ## Seconds.
+    tv_usec*: Suseconds ## Microseconds.
   TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
            final, pure.} = object
   Mcontext* {.importc: "mcontext_t", header: "<ucontext.h>",
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index a5eaec86e..ca4f80f2a 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -168,6 +168,15 @@ proc wakeupWorkerToProcessQueue(w: ptr Worker) =
     signal(w.q.empty)
   signal(w.taskArrived)
 
+proc attach(fv: FlowVarBase; i: int): bool =
+  acquire(fv.cv.L)
+  if fv.cv.counter <= 0:
+    fv.idx = i
+    result = true
+  else:
+    result = false
+  release(fv.cv.L)
+
 proc finished(fv: FlowVarBase) =
   doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'"
   # we have to protect against the rare cases where the owner of the flowVar
@@ -245,26 +254,27 @@ proc `^`*[T](fv: FlowVar[T]): T =
 proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
   ## awaits any of the given flowVars. Returns the index of one flowVar for
   ## which a value arrived. A flowVar only supports one call to 'awaitAny' at
-  ## the same time. That means if you await([a,b]) and await([b,c]) the second
+  ## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second
   ## call will only await 'c'. If there is no flowVar left to be able to wait
   ## on, -1 is returned.
-  ## **Note**: This results in non-deterministic behaviour and so should be
-  ## avoided.
+  ## **Note**: This results in non-deterministic behaviour and should be avoided.
   var ai: AwaitInfo
   ai.cv.initSemaphore()
   var conflicts = 0
+  result = -1
   for i in 0 .. flowVars.high:
     if cas(addr flowVars[i].ai, nil, addr ai):
-      flowVars[i].idx = i
+      if not attach(flowVars[i], i):
+        result = i
+        break
     else:
       inc conflicts
   if conflicts < flowVars.len:
-    await(ai.cv)
-    result = ai.idx
+    if result < 0:
+      await(ai.cv)
+      result = ai.idx
     for i in 0 .. flowVars.high:
       discard cas(addr flowVars[i].ai, addr ai, nil)
-  else:
-    result = -1
   destroySemaphore(ai.cv)
 
 proc isReady*(fv: FlowVarBase): bool =
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index 74b2c9741..09fa253f1 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -616,8 +616,12 @@ proc setBlocking*(s: SocketHandle, blocking: bool) =
 proc timeValFromMilliseconds(timeout = 500): Timeval =
   if timeout != -1:
     var seconds = timeout div 1000
-    result.tv_sec = seconds.int32
-    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+    when useWinVersion:
+      result.tv_sec = seconds.int32
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+    else:
+      result.tv_sec = seconds.Time
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds
 
 proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) =
   FD_ZERO(fd)
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index 8a771be71..aaffb57ca 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -104,6 +104,10 @@ proc none*(T: typedesc): Option[T] =
   # the default is the none type
   discard
 
+proc none*[T]: Option[T] =
+  ## Alias for ``none(T)``.
+  none(T)
+
 proc isSome*[T](self: Option[T]): bool {.inline.} =
   when T is SomePointer:
     self.val != nil
@@ -290,3 +294,7 @@ when isMainModule:
 
       let tmp = option(intref)
       check(sizeof(tmp) == sizeof(ptr int))
+
+    test "none[T]":
+      check(none[int]().isNone)
+      check(none(int) == none[int]())
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index a77bee99d..ddeee2c6b 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -188,7 +188,7 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1".}
     var f: WIN32_FIND_DATA
     var h = findFirstFile(file, f)
     if h == -1'i32: raiseOSError(osLastError())
-    result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastWriteTime)).int64)
+    result = fromWinTime(rdFileTime(f.ftLastWriteTime))
     findClose(h)
 
 proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
@@ -201,7 +201,7 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
     var f: WIN32_FIND_DATA
     var h = findFirstFile(file, f)
     if h == -1'i32: raiseOSError(osLastError())
-    result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastAccessTime)).int64)
+    result = fromWinTime(rdFileTime(f.ftLastAccessTime))
     findClose(h)
 
 proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
@@ -218,7 +218,7 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
     var f: WIN32_FIND_DATA
     var h = findFirstFile(file, f)
     if h == -1'i32: raiseOSError(osLastError())
-    result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftCreationTime)).int64)
+    result = fromWinTime(rdFileTime(f.ftCreationTime))
     findClose(h)
 
 proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
@@ -329,20 +329,21 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
       c_free(cast[pointer](r))
 
 when defined(Windows):
-  proc openHandle(path: string, followSymlink=true): Handle =
+  proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
     var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
     if not followSymlink:
       flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
+    let access = if writeAccess: GENERIC_WRITE else: 0'i32
 
     when useWinUnicode:
       result = createFileW(
-        newWideCString(path), 0'i32,
+        newWideCString(path), access,
         FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
         nil, OPEN_EXISTING, flags, 0
         )
     else:
       result = createFileA(
-        path, 0'i32,
+        path, access,
         FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
         nil, OPEN_EXISTING, flags, 0
         )
@@ -1511,16 +1512,14 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
   ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
   ## or a 'Stat' structure on posix
   when defined(Windows):
-    template toTime(e: FILETIME): untyped {.gensym.} =
-      fromUnix(winTimeToUnixTime(rdFileTime(e)).int64) # local templates default to bind semantics
     template merge(a, b): untyped = a or (b shl 32)
     formalInfo.id.device = rawInfo.dwVolumeSerialNumber
     formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
     formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
     formalInfo.linkCount = rawInfo.nNumberOfLinks
-    formalInfo.lastAccessTime = toTime(rawInfo.ftLastAccessTime)
-    formalInfo.lastWriteTime = toTime(rawInfo.ftLastWriteTime)
-    formalInfo.creationTime = toTime(rawInfo.ftCreationTime)
+    formalInfo.lastAccessTime = fromWinTime(rdFileTime(rawInfo.ftLastAccessTime))
+    formalInfo.lastWriteTime = fromWinTime(rdFileTime(rawInfo.ftLastWriteTime))
+    formalInfo.creationTime = fromWinTime(rdFileTime(rawInfo.ftCreationTime))
 
     # Retrieve basic permissions
     if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
@@ -1654,3 +1653,18 @@ proc isHidden*(path: string): bool =
         result = (fileName[0] == '.') and (fileName[3] != '.')
 
 {.pop.}
+
+proc setLastModificationTime*(file: string, t: times.Time) =
+  ## Sets the `file`'s last modification time. `OSError` is raised in case of
+  ## an error.
+  when defined(posix):
+    let unixt = posix.Time(t.toUnix)
+    var timevals = [Timeval(tv_sec: unixt), Timeval(tv_sec: unixt)] # [last access, last modification]
+    if utimes(file, timevals.addr) != 0: raiseOSError(osLastError())
+  else:
+    let h = openHandle(path = file, writeAccess = true)
+    if h == INVALID_HANDLE_VALUE: raiseOSError(osLastError())
+    var ft = t.toWinTime.toFILETIME
+    let res = setFileTime(h, nil, nil, ft.addr)
+    discard h.closeHandle
+    if res == 0'i32: raiseOSError(osLastError())
\ No newline at end of file
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 555626514..bcab5ad3a 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -1001,13 +1001,21 @@ elif not defined(useNimRtl):
   {.pop}
 
   proc close(p: Process) =
-    if p.inStream != nil: close(p.inStream)
-    if p.outStream != nil: close(p.outStream)
-    if p.errStream != nil: close(p.errStream)
     if poParentStreams notin p.options:
-      discard close(p.inHandle)
-      discard close(p.outHandle)
-      discard close(p.errHandle)
+      if p.inStream != nil:
+        close(p.inStream)
+      else:
+        discard close(p.inHandle)
+
+      if p.outStream != nil:
+        close(p.outStream)
+      else:
+        discard close(p.outHandle)
+
+      if p.errStream != nil:
+        close(p.errStream)
+      else:
+        discard close(p.errHandle)
 
   proc suspend(p: Process) =
     if kill(p.id, SIGSTOP) != 0'i32: raiseOsError(osLastError())
@@ -1281,7 +1289,7 @@ elif not defined(useNimRtl):
 
   proc select(readfds: var seq[Process], timeout = 500): int =
     var tv: Timeval
-    tv.tv_sec = 0
+    tv.tv_sec = posix.Time(0)
     tv.tv_usec = timeout * 1000
 
     var rd: TFdSet
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index d772b066c..54fdcb4d0 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -1647,11 +1647,15 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
   let last = s.high
   var i = 0
   while true:
-    var j = find(a, s, sub, i, last)
+    let j = find(a, s, sub, i, last)
     if j < 0: break
     add result, substr(s, i, j - 1)
     add result, by
-    i = j + len(sub)
+    if sub.len == 0:
+      if i < s.len: add result, s[i]
+      i = j + 1
+    else:
+      i = j + sub.len
   # copy the rest:
   add result, substr(s, i)
 
@@ -1680,6 +1684,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
   initSkipTable(a, sub)
   var i = 0
   let last = s.high
+  let sublen = max(sub.len, 1)
   while true:
     var j = find(a, s, sub, i, last)
     if j < 0: break
@@ -1688,7 +1693,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
         (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
       add result, substr(s, i, j - 1)
       add result, by
-      i = j + len(sub)
+      i = j + sublen
     else:
       add result, substr(s, i, j)
       i = j + 1
@@ -2546,6 +2551,9 @@ when isMainModule:
   doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
   doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
 
+  doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc"
+  doAssert "oo".replace("", "abc") == "abcoabcoabc"
+
   type MyEnum = enum enA, enB, enC, enuD, enE
   doAssert parseEnum[MyEnum]("enu_D") == enuD
 
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 4f2f73ba7..002181a6f 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -557,8 +557,8 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) =
   when defined(windows):
     let h = conHandle(f)
     var old = getAttributes(h) and not FOREGROUND_RGB
-    if bright:
-      old = old or FOREGROUND_INTENSITY
+    old = if bright: old or FOREGROUND_INTENSITY
+          else:      old and not(FOREGROUND_INTENSITY)
     const lookup: array[ForegroundColor, int] = [
       0,
       (FOREGROUND_RED),
@@ -579,8 +579,8 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
   when defined(windows):
     let h = conHandle(f)
     var old = getAttributes(h) and not BACKGROUND_RGB
-    if bright:
-      old = old or BACKGROUND_INTENSITY
+    old = if bright: old or BACKGROUND_INTENSITY
+          else:      old and not(BACKGROUND_INTENSITY)
     const lookup: array[BackgroundColor, int] = [
       0,
       (BACKGROUND_RED),
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index dc216477b..bf63ed344 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -191,6 +191,7 @@ const
   secondsInHour = 60*60
   secondsInDay = 60*60*24
   minutesInHour = 60
+  rateDiff = 10000000'i64 # 100 nsecs
   # The number of hectonanoseconds between 1601/01/01 (windows epoch)
   # and 1970/01/01 (unix epoch).
   epochDiff = 116444736000000000'i64
@@ -352,7 +353,9 @@ proc `$`*(dur: Duration): string =
       parts.add $quantity & " " & unitStrings[unit] & "s"
 
   result = ""
-  if parts.len == 1:
+  if parts.len == 0:
+    result.add "0 nanoseconds"
+  elif parts.len == 1:
     result = parts[0]
   elif parts.len == 2:
     result = parts[0] & " and " & parts[1]
@@ -371,6 +374,21 @@ proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} =
   ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``).
   t.seconds
 
+proc fromWinTime*(win: int64): Time =
+  ## Convert a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``)
+  ## to a ``Time``.
+  let hnsecsSinceEpoch = (win - epochDiff)
+  var seconds = hnsecsSinceEpoch div rateDiff
+  var nanos = ((hnsecsSinceEpoch mod rateDiff) * 100).int
+  if nanos < 0:
+    nanos += convert(Seconds, Nanoseconds, 1)
+    seconds -= 1
+  result = initTime(seconds, nanos)
+
+proc toWinTime*(t: Time): int64 =
+  ## Convert ``t`` to a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``).
+  result = t.seconds * rateDiff + epochDiff + t.nanoseconds div 100
+
 proc isLeapYear*(year: int): bool =
   ## Returns true if ``year`` is a leap year.
   year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0)
@@ -853,10 +871,7 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} =
   elif defined(windows):
     var f: FILETIME
     getSystemTimeAsFileTime(f)
-    let nanosSinceEpoch = (rdFileTime(f) - epochDiff) * 100
-    let seconds = convert(Nanoseconds, Seconds, nanosSinceEpoch)
-    let nanos = (nanosSinceEpoch mod convert(Seconds, Nanoseconds, 1)).int
-    result = initTime(seconds, nanos)
+    result = fromWinTime(rdFileTime(f))
 
 proc now*(): DateTime {.tags: [TimeEffect], benign.} =
   ## Get the current time as a  ``DateTime`` in the local timezone.
@@ -1713,17 +1728,6 @@ when not defined(JS):
   var
     clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
 
-  const
-    rateDiff = 10000000'i64 # 100 nsecs
-
-  proc unixTimeToWinTime*(time: CTime): int64 =
-    ## converts a UNIX `Time` (``time_t``) to a Windows file time
-    result = int64(time) * rateDiff + epochDiff
-
-  proc winTimeToUnixTime*(time: int64): CTime =
-    ## converts a Windows time to a UNIX `Time` (``time_t``)
-    result = CTime((time - epochDiff) div rateDiff)
-
   when not defined(useNimRtl):
     proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} =
       ## gets time spent that the CPU spent to run the current process in
@@ -1748,7 +1752,7 @@ when not defined(JS):
       when defined(posix):
         var a: Timeval
         gettimeofday(a)
-        result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
+        result = toBiggestFloat(a.tv_sec.int64) + toFloat(a.tv_usec)*0.00_0001
       elif defined(windows):
         var f: winlean.FILETIME
         getSystemTimeAsFileTime(f)
@@ -1765,6 +1769,19 @@ when defined(JS):
 
 # Deprecated procs
 
+when not defined(JS):
+  proc unixTimeToWinTime*(time: CTime): int64 {.deprecated: "Use toWinTime instead".} =
+    ## Converts a UNIX `Time` (``time_t``) to a Windows file time
+    ##
+    ## **Deprecated:** use ``toWinTime`` instead.
+    result = int64(time) * rateDiff + epochDiff
+
+  proc winTimeToUnixTime*(time: int64): CTime {.deprecated: "Use fromWinTime instead".} =
+    ## Converts a Windows time to a UNIX `Time` (``time_t``)
+    ##
+    ## **Deprecated:** use ``fromWinTime`` instead.
+    result = CTime((time - epochDiff) div rateDiff)
+
 proc initInterval*(seconds, minutes, hours, days, months,
                    years: int = 0): TimeInterval {.deprecated.} =
   ## **Deprecated since v0.18.0:** use ``initTimeInterval`` instead.
diff --git a/lib/system.nim b/lib/system.nim
index 3761a35f8..5e08dadc0 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2404,7 +2404,7 @@ proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
     if x.isNil and y.isNil:
       return true
   else:
-    when not defined(JS) or defined(nimphp):
+    when not defined(JS):
       proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
         result = cast[pointer](x)
     else:
@@ -2766,17 +2766,14 @@ type
 
 when defined(JS):
   proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
-    when defined(nimphp):
-      asm """`x` .= `y`;"""
-    else:
-      asm """
-        var len = `x`[0].length-1;
-        for (var i = 0; i < `y`.length; ++i) {
-          `x`[0][len] = `y`.charCodeAt(i);
-          ++len;
-        }
-        `x`[0][len] = 0
-      """
+    asm """
+      var len = `x`[0].length-1;
+      for (var i = 0; i < `y`.length; ++i) {
+        `x`[0][len] = `y`.charCodeAt(i);
+        ++len;
+      }
+      `x`[0][len] = 0
+    """
   proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
 
 elif hasAlloc:
@@ -4139,17 +4136,18 @@ template doAssertRaises*(exception, code: untyped): typed =
   runnableExamples:
     doAssertRaises(ValueError):
       raise newException(ValueError, "Hello World")
-
+  var wrong = false
   try:
-    block:
-      code
-    raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
+    code
+    wrong = true
   except exception:
     discard
   except Exception as exc:
     raiseAssert(astToStr(exception) &
                 " wasn't raised, another error was raised instead by:\n"&
                 astToStr(code))
+  if wrong:
+    raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
 
 when defined(cpp) and appType != "lib" and not defined(js) and
     not defined(nimscript) and hostOS != "standalone":
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
index f061c89cf..ff1ef31d2 100644
--- a/lib/system/assign.nim
+++ b/lib/system/assign.nim
@@ -79,8 +79,12 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
                       GenericSeqSize),
           mt.base, shallow)
   of tyObject:
-    if mt.base != nil:
-      genericAssignAux(dest, src, mt.base, shallow)
+    var it = mt.base
+    # don't use recursion here on the PNimType because the subtype
+    # check should only be done at the very end:
+    while it != nil:
+      genericAssignAux(dest, src, it.node, shallow)
+      it = it.base
     genericAssignAux(dest, src, mt.node, shallow)
     # we need to copy m_type field for tyObject, as it could be empty for
     # sequence reallocations:
@@ -89,6 +93,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
     #   if p of TB:
     #     var tbObj = TB(p)
     #     tbObj of TC # needs to be false!
+    #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name)
+    chckObjAsgn(cast[ptr PNimType](src)[], mt)
     pint[] = mt # cast[ptr PNimType](src)[]
   of tyTuple:
     genericAssignAux(dest, src, mt.node, shallow)
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 8c3175eac..56a9f6575 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -48,10 +48,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
   result[0] = x
 
 proc isNimException(): bool {.asmNoStackFrame.} =
-  when defined(nimphp):
-    asm "return isset(`lastJSError`['m_type']);"
-  else:
-    asm "return `lastJSError`.m_type;"
+  asm "return `lastJSError`.m_type;"
 
 proc getCurrentException*(): ref Exception {.compilerRtl, benign.} =
   if isNimException(): result = cast[ref Exception](lastJSError)
@@ -61,15 +58,14 @@ proc getCurrentExceptionMsg*(): string =
     if isNimException():
       return cast[Exception](lastJSError).msg
     else:
-      when not defined(nimphp):
-        var msg: cstring
-        {.emit: """
-        if (`lastJSError`.message !== undefined) {
-          `msg` = `lastJSError`.message;
-        }
-        """.}
-        if not msg.isNil:
-          return $msg
+      var msg: cstring
+      {.emit: """
+      if (`lastJSError`.message !== undefined) {
+        `msg` = `lastJSError`.message;
+      }
+      """.}
+      if not msg.isNil:
+        return $msg
   return ""
 
 proc auxWriteStackTrace(f: PCallFrame): string =
@@ -140,12 +136,9 @@ proc raiseException(e: ref Exception, ename: cstring) {.
   e.name = ename
   if excHandler == 0:
     unhandledException(e)
-  when defined(nimphp):
-    asm """throw new Exception($`e`["message"]);"""
-  else:
-    when NimStackTrace:
-      e.trace = rawWriteStackTrace()
-    asm "throw `e`;"
+  when NimStackTrace:
+    e.trace = rawWriteStackTrace()
+  asm "throw `e`;"
 
 proc reraiseException() {.compilerproc, asmNoStackFrame.} =
   if lastJSError == nil:
@@ -173,57 +166,35 @@ proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
   raise newException(FieldError, f & " is not accessible")
 
 proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      $args = func_get_args();
-      $result = array();
-      foreach ($args as $x) {
-        if (is_array($x)) {
-          for ($j = $x[0]; $j <= $x[1]; $j++) {
-            $result[$j] = true;
-          }
-        } else {
-          $result[$x] = true;
-        }
-      }
-      return $result;
-    """
-  else:
-    asm """
-      var result = {};
-      for (var i = 0; i < arguments.length; ++i) {
-        var x = arguments[i];
-        if (typeof(x) == "object") {
-          for (var j = x[0]; j <= x[1]; ++j) {
-            result[j] = true;
-          }
-        } else {
-          result[x] = true;
+  asm """
+    var result = {};
+    for (var i = 0; i < arguments.length; ++i) {
+      var x = arguments[i];
+      if (typeof(x) == "object") {
+        for (var j = x[0]; j <= x[1]; ++j) {
+          result[j] = true;
         }
+      } else {
+        result[x] = true;
       }
-      return result;
-    """
-
-proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    {.emit: """return `c`;""".}
-  else:
-    {.emit: """
-    var ln = `c`.length;
-    var result = new Array(ln + 1);
-    var i = 0;
-    for (; i < ln; ++i) {
-      result[i] = `c`.charCodeAt(i);
     }
-    result[i] = 0; // terminating zero
     return result;
-    """.}
+  """
+
+proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
+  {.emit: """
+  var ln = `c`.length;
+  var result = new Array(ln + 1);
+  var i = 0;
+  for (; i < ln; ++i) {
+    result[i] = `c`.charCodeAt(i);
+  }
+  result[i] = 0; // terminating zero
+  return result;
+  """.}
 
 proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    {.emit: """return `c`;""".}
-  else:
-    {.emit: """
+  {.emit: """
   var ln = `c`.length;
   var result = new Array(ln);
   var r = 0;
@@ -261,156 +232,93 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
   """.}
 
 proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    {.emit: """return `s`;""".}
-  else:
-    asm """
-    var len = `s`.length-1;
-    var asciiPart = new Array(len);
-    var fcc = String.fromCharCode;
-    var nonAsciiPart = null;
-    var nonAsciiOffset = 0;
-    for (var i = 0; i < len; ++i) {
-      if (nonAsciiPart !== null) {
-        var offset = (i - nonAsciiOffset) * 2;
-        var code = `s`[i].toString(16);
-        if (code.length == 1) {
-          code = "0"+code;
-        }
-        nonAsciiPart[offset] = "%";
-        nonAsciiPart[offset + 1] = code;
-      }
-      else if (`s`[i] < 128)
-        asciiPart[i] = fcc(`s`[i]);
-      else {
-        asciiPart.length = i;
-        nonAsciiOffset = i;
-        nonAsciiPart = new Array((len - i) * 2);
-        --i;
+  asm """
+  var len = `s`.length-1;
+  var asciiPart = new Array(len);
+  var fcc = String.fromCharCode;
+  var nonAsciiPart = null;
+  var nonAsciiOffset = 0;
+  for (var i = 0; i < len; ++i) {
+    if (nonAsciiPart !== null) {
+      var offset = (i - nonAsciiOffset) * 2;
+      var code = `s`[i].toString(16);
+      if (code.length == 1) {
+        code = "0"+code;
       }
+      nonAsciiPart[offset] = "%";
+      nonAsciiPart[offset + 1] = code;
     }
-    asciiPart = asciiPart.join("");
-    return (nonAsciiPart === null) ?
-        asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join(""));
+    else if (`s`[i] < 128)
+      asciiPart[i] = fcc(`s`[i]);
+    else {
+      asciiPart.length = i;
+      nonAsciiOffset = i;
+      nonAsciiPart = new Array((len - i) * 2);
+      --i;
+    }
+  }
+  asciiPart = asciiPart.join("");
+  return (nonAsciiPart === null) ?
+      asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join(""));
   """
 
 proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return str_repeat(chr(0),`len`);
-    """
-  else:
-    asm """
-      var result = new Array(`len`+1);
-      result[0] = 0;
-      result[`len`] = 0;
-      return result;
-    """
-
-when defined(nimphp):
-  proc nimAt(x: string; i: int): string {.asmNoStackFrame, compilerproc.} =
-    asm """
-      return `x`[`i`];
-    """
-
-when defined(nimphp):
-  proc nimSubstr(s: string; a, b: int): string {.
-      asmNoStackFrame, compilerproc.} =
-    asm """return substr(`s`,`a`,`b`-`a`+1);"""
+  asm """
+    var result = new Array(`len`+1);
+    result[0] = 0;
+    result[`len`] = 0;
+    return result;
+  """
 
 proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
   # argument type is a fake
-  when defined(nimphp):
-    asm """
-      return count(`a`);
-    """
-  else:
-    asm """
-      var result = 0;
-      for (var elem in `a`) { ++result; }
-      return result;
-    """
+  asm """
+    var result = 0;
+    for (var elem in `a`) { ++result; }
+    return result;
+  """
 
 proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
-  when defined(nimphp):
-    asm """
-      foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; }
-      foreach (`b` as $elem=>$_) { if (!isset(`a`[$elem])) return false; }
-      return true;
-    """
-  else:
-    asm """
-      for (var elem in `a`) { if (!`b`[elem]) return false; }
-      for (var elem in `b`) { if (!`a`[elem]) return false; }
-      return true;
-    """
+  asm """
+    for (var elem in `a`) { if (!`b`[elem]) return false; }
+    for (var elem in `b`) { if (!`a`[elem]) return false; }
+    return true;
+  """
 
 proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
-  when defined(nimphp):
-    asm """
-      foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; }
-      return true;
-    """
-  else:
-    asm """
-      for (var elem in `a`) { if (!`b`[elem]) return false; }
-      return true;
-    """
+  asm """
+    for (var elem in `a`) { if (!`b`[elem]) return false; }
+    return true;
+  """
 
 proc SetLt(a, b: int): bool {.compilerproc.} =
   result = SetLe(a, b) and not SetEq(a, b)
 
 proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
-  when defined(nimphp):
-    asm """
-      var $result = array();
-      foreach (`a` as $elem=>$_) {
-        if (isset(`b`[$elem])) { $result[$elem] = true; }
-      }
-      return $result;
-    """
-  else:
-    asm """
-      var result = {};
-      for (var elem in `a`) {
-        if (`b`[elem]) { result[elem] = true; }
-      }
-      return result;
-    """
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
 
 proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
-  when defined(nimphp):
-    asm """
-      var $result = array();
-      foreach (`a` as $elem=>$_) { $result[$elem] = true; }
-      foreach (`b` as $elem=>$_) { $result[$elem] = true; }
-      return $result;
-    """
-  else:
-    asm """
-      var result = {};
-      for (var elem in `a`) { result[elem] = true; }
-      for (var elem in `b`) { result[elem] = true; }
-      return result;
-    """
+  asm """
+    var result = {};
+    for (var elem in `a`) { result[elem] = true; }
+    for (var elem in `b`) { result[elem] = true; }
+    return result;
+  """
 
 proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
-  when defined(nimphp):
-    asm """
-      $result = array();
-      foreach (`a` as $elem=>$_) {
-        if (!isset(`b`[$elem])) { $result[$elem] = true; }
-      }
-      return $result;
-    """
-  else:
-    asm """
-      var result = {};
-      for (var elem in `a`) {
-        if (!`b`[elem]) { result[elem] = true; }
-      }
-      return result;
-    """
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (!`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
 
 proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
   asm """
@@ -424,15 +332,8 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
     return `a`.length - `b`.length;
   """
 
-proc cmp(x, y: string): int =
-  when defined(nimphp):
-    asm """
-      if(`x` < `y`) `result` = -1;
-      elseif (`x` > `y`) `result` = 1;
-      else `result` = 0;
-    """
-  else:
-    return cmpStrings(x, y)
+proc cmp(x, y: string): int = 
+  return cmpStrings(x, y)
 
 proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
   asm """
@@ -467,7 +368,7 @@ elif not defined(nimOldEcho):
       console.log(buf);
     """
 
-elif not defined(nimphp):
+else:
   proc ewriteln(x: cstring) =
     var node : JSRef
     {.emit: "`node` = document.getElementsByTagName('body')[0];".}
@@ -493,127 +394,77 @@ elif not defined(nimphp):
 
 # Arithmetic:
 proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` + `b`;
-    """
-  else:
-    asm """
-      var result = `a` + `b`;
-      if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
-      return result;
-    """
+  asm """
+    var result = `a` + `b`;
+    if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
+    return result;
+  """
 
 proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` - `b`;
-    """
-  else:
-    asm """
-      var result = `a` - `b`;
-      if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
-      return result;
-    """
+  asm """
+    var result = `a` - `b`;
+    if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
+    return result;
+  """
 
 proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` * `b`;
-    """
-  else:
-    asm """
-      var result = `a` * `b`;
-      if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
-      return result;
-    """
+  asm """
+    var result = `a` * `b`;
+    if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
+    return result;
+  """
 
 proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return trunc(`a` / `b`);
-    """
-  else:
-    asm """
-      if (`b` == 0) `raiseDivByZero`();
-      if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
-      return Math.trunc(`a` / `b`);
-    """
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
+    return Math.trunc(`a` / `b`);
+  """
 
 proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` % `b`;
-    """
-  else:
-    asm """
-      if (`b` == 0) `raiseDivByZero`();
-      if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
-      return Math.trunc(`a` % `b`);
-    """
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
+    return Math.trunc(`a` % `b`);
+  """
 
 proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` + `b`;
-    """
-  else:
-    asm """
-      var result = `a` + `b`;
-      if (result > 9223372036854775807
-      || result < -9223372036854775808) `raiseOverflow`();
-      return result;
-    """
+  asm """
+    var result = `a` + `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) `raiseOverflow`();
+    return result;
+  """
 
 proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` - `b`;
-    """
-  else:
-    asm """
-      var result = `a` - `b`;
-      if (result > 9223372036854775807
-      || result < -9223372036854775808) `raiseOverflow`();
-      return result;
-    """
+  asm """
+    var result = `a` - `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) `raiseOverflow`();
+    return result;
+  """
 
 proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` * `b`;
-    """
-  else:
-    asm """
-      var result = `a` * `b`;
-      if (result > 9223372036854775807
-      || result < -9223372036854775808) `raiseOverflow`();
-      return result;
-    """
+  asm """
+    var result = `a` * `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) `raiseOverflow`();
+    return result;
+  """
 
 proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return trunc(`a` / `b`);
-    """
-  else:
-    asm """
-      if (`b` == 0) `raiseDivByZero`();
-      if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
-      return Math.trunc(`a` / `b`);
-    """
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
+    return Math.trunc(`a` / `b`);
+  """
 
 proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
-  when defined(nimphp):
-    asm """
-      return `a` % `b`;
-    """
-  else:
-    asm """
-      if (`b` == 0) `raiseDivByZero`();
-      if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
-      return Math.trunc(`a` % `b`);
-    """
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
+    return Math.trunc(`a` % `b`);
+  """
 
 proc negInt(a: int): int {.compilerproc.} =
   result = a*(-1)
@@ -767,24 +618,14 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} =
   else:
     discard
 
-when defined(nimphp):
-  proc arrayConstr(len: int, value: string, typ: string): JSRef {.
-                  asmNoStackFrame, compilerproc.} =
-    # types are fake
-    asm """
-      $result = array();
-      for ($i = 0; $i < `len`; $i++) $result[] = `value`;
-      return $result;
-    """
-else:
-  proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
-                  asmNoStackFrame, compilerproc.} =
+proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
+                asmNoStackFrame, compilerproc.} =
   # types are fake
-    asm """
-      var result = new Array(`len`);
-      for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`);
-      return result;
-    """
+  asm """
+    var result = new Array(`len`);
+    for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`);
+    return result;
+  """
 
 proc chckIndx(i, a, b: int): int {.compilerproc.} =
   if i >= a and i <= b: return i
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index f40344396..62bc38da9 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -1086,3 +1086,14 @@ proc ConvertThreadToFiberEx*(param: pointer, flags: int32): pointer {.stdcall, d
 proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
 proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
 proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "Windows.h".}
+
+proc toFILETIME*(t: int64): FILETIME =
+  ## Convert the Windows file time timestamp ``t`` to ``FILETIME``.
+  result = FILETIME(dwLowDateTime: cast[DWORD](t), dwHighDateTime: DWORD(t shr 32))
+
+type
+  LPFILETIME* = ptr FILETIME
+
+proc setFileTime*(hFile: HANDLE, lpCreationTime: LPFILETIME,
+                 lpLastAccessTime: LPFILETIME, lpLastWriteTime: LPFILETIME): WINBOOL
+     {.stdcall, dynlib: "kernel32", importc: "SetFileTime".}
diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim
index f81d67a50..acde1b288 100644
--- a/tests/cpp/tcovariancerules.nim
+++ b/tests/cpp/tcovariancerules.nim
@@ -13,14 +13,8 @@ cat
 cat
 dog
 dog
-dog value
-cat value
-dog value
-cat value
 dog
 dog
-dog value
-cat value
 dog 1
 dog 2
 '''
@@ -243,11 +237,12 @@ reject modifiesCovariantArray(dogRefsArray.addr)
 
 var dogValues = @[vdog, vdog]
 var dogValuesArray = [vdog, vdog]
-var animalValues = @[Animal(vdog), Animal(vcat)]
-var animalValuesArray = [Animal(vdog), Animal(vcat)]
+when false:
+  var animalValues = @[Animal(vdog), Animal(vcat)]
+  var animalValuesArray = [Animal(vdog), Animal(vcat)]
 
-wantsNonCovariantSeq animalValues
-wantsNonCovariantArray animalValuesArray
+  wantsNonCovariantSeq animalValues
+  wantsNonCovariantArray animalValuesArray
 
 reject wantsNonCovariantSeq(dogRefs)
 reject modifiesCovariantOperArray(dogRefs)
@@ -260,7 +255,6 @@ modifiesDerivedOperArray dogRefs
 reject modifiesDerivedOperArray(dogValues)
 reject modifiesDerivedOperArray(animalRefs)
 
-wantsNonCovariantOperArray animalValues
 reject wantsNonCovariantOperArray(animalRefs)
 reject wantsNonCovariantOperArray(dogRefs)
 reject wantsNonCovariantOperArray(dogValues)
diff --git a/tests/errmsgs/t1154.nim b/tests/errmsgs/t1154.nim
new file mode 100644
index 000000000..7fcbf8a27
--- /dev/null
+++ b/tests/errmsgs/t1154.nim
@@ -0,0 +1,11 @@
+discard """
+errormsg: "invalid type: 'expr' in this context: 'proc (a: varargs[expr])' for proc"
+line: 8
+"""
+
+import typetraits
+
+proc foo(a:varargs[expr]) =
+  echo a[0].type.name
+
+foo(1)
diff --git a/tests/errmsgs/tcant_overload_by_return_type.nim b/tests/errmsgs/tcant_overload_by_return_type.nim
new file mode 100644
index 000000000..613a896b4
--- /dev/null
+++ b/tests/errmsgs/tcant_overload_by_return_type.nim
@@ -0,0 +1,9 @@
+discard """
+errormsg: "overloaded 'x' leads to ambiguous calls"
+line: 9
+"""
+
+# bug #6393
+
+proc x(): int = 7
+proc x(): string = "strange"
diff --git a/tests/macros/tmacro1.nim b/tests/macros/tmacro1.nim
index 0b83345a1..ac2bf9094 100644
--- a/tests/macros/tmacro1.nim
+++ b/tests/macros/tmacro1.nim
@@ -27,11 +27,19 @@ import strutils
 template assertNot(arg: untyped): untyped =
   assert(not(arg))
 
+
+proc foo(arg: int): void =
+  discard
+
+proc foo(arg: float): void =
+  discard
+
 static:
   ## test eqIdent
   let a = "abc_def"
   let b = "abcDef"
   let c = "AbcDef"
+  let d = nnkBracketExpr.newTree() # not an identifier at all
 
   assert eqIdent(             a ,              b )
   assert eqIdent(newIdentNode(a),              b )
@@ -62,3 +70,12 @@ static:
   assertNot eqIdent(genSym(nskLet, c), newIdentNode(  b))
   assertNot eqIdent(newIdentNode(  c), genSym(nskLet, b))
   assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
+
+  # eqIdent on non identifier at all
+  assertNot eqIdent(a,d)
+
+  # eqIdent on sym choice
+  let fooSym = bindSym"foo"
+  assert fooSym.kind in {nnkOpenSymChoice, nnkClosedSymChoice}
+  assert    fooSym.eqIdent("fOO")
+  assertNot fooSym.eqIdent("bar")
diff --git a/tests/objects/tinherentedvalues.nim b/tests/objects/tinherentedvalues.nim
index c96a0fd6d..ad7b5f326 100644
--- a/tests/objects/tinherentedvalues.nim
+++ b/tests/objects/tinherentedvalues.nim
@@ -1,9 +1,7 @@
 discard """
-  output: '''tbObj of TC false
-false
+  output: '''tbObj of TC true
 true
-5
-false'''
+5'''
 """
 
 # bug #1053
@@ -20,10 +18,10 @@ type
 proc test(p: TA) =
   #echo "p of TB ", p of TB
   if p of TB:
-    var tbObj = TB(p)
+    #var tbObj = TB(p)
 
     # tbObj is actually no longer compatible with TC:
-    echo "tbObj of TC ", tbObj of TC
+    echo "tbObj of TC ", p of TC
 
 var v = TC()
 v.a = 1
@@ -48,8 +46,8 @@ proc isMyObject(obj: TObject) =
 
 asd.x = 5
 
-var asdCopy = TObject(asd)
-echo asdCopy of MyObject
+#var asdCopy = TObject(asd)
+#echo asdCopy of MyObject
 
 isMyObject(asd)
-isMyObject(asdCopy)
+#isMyObject(asdCopy)
diff --git a/tests/objects/tobj_asgn_dont_slice.nim b/tests/objects/tobj_asgn_dont_slice.nim
new file mode 100644
index 000000000..866b5aecc
--- /dev/null
+++ b/tests/objects/tobj_asgn_dont_slice.nim
@@ -0,0 +1,24 @@
+discard """
+  outputsub: '''ObjectAssignmentError'''
+  exitcode: "1"
+"""
+
+# bug #7637
+type
+  Fruit = object of RootObj
+    name*: string
+  Apple = object of Fruit
+  Pear = object of Fruit
+
+method eat(f: Fruit) {.base.} =
+  raise newException(Exception, "PURE VIRTUAL CALL")
+
+method eat(f: Apple) =
+  echo "fruity"
+
+method eat(f: Pear) =
+  echo "juicy"
+
+let basket = [Apple(name:"a"), Pear(name:"b")]
+
+eat(basket[0])
diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim
index d1f3c8bdb..7238d10c7 100644
--- a/tests/objects/tobjconstr.nim
+++ b/tests/objects/tobjconstr.nim
@@ -9,8 +9,8 @@ discard """
 (k: kindA, a: (x: "abc", z: [1, 8, 3]), method: ())
 (k: kindA, a: (x: "abc", z: [1, 9, 3]), method: ())
 (k: kindA, a: (x: "abc", z: [1, 10, 3]), method: ())
-(x: 123)
-(x: 123)
+(y: 0, x: 123)
+(y: 678, x: 123)
 (z: 89, y: 0, x: 128)
 (y: 678, x: 123)
 (y: 678, x: 123)
@@ -33,7 +33,6 @@ type
       `method`: TEmpty # bug #1791
 
 proc `$`[T](s: seq[T]): string =
-  # XXX why is that not in the stdlib?
   result = "["
   for i, x in s:
     if i > 0: result.add(", ")
@@ -59,7 +58,7 @@ type
 # inherited fields are ignored, so no fields are set
 when true:
   var
-    o: A
+    o: B
   o = B(x: 123)
   echo o
   o = B(y: 678, x: 123)
diff --git a/tests/osproc/tclose.nim b/tests/osproc/tclose.nim
new file mode 100644
index 000000000..d466b466a
--- /dev/null
+++ b/tests/osproc/tclose.nim
@@ -0,0 +1,24 @@
+discard """
+  exitcode: 0
+"""
+
+when defined(linux):
+  import osproc, os
+
+  proc countFds(): int =
+    result = 0
+    for i in walkDir("/proc/self/fd"):
+      result += 1
+
+  let initCount = countFds()
+
+  let p = osproc.startProcess("echo", options={poUsePath})
+  assert countFds() == initCount + 3
+  p.close
+  assert countFds() == initCount
+
+  let p1 = osproc.startProcess("echo", options={poUsePath})
+  discard p1.inputStream
+  assert countFds() == initCount + 3
+  p.close
+  assert countFds() == initCount
diff --git a/tests/overload/toverprc.nim b/tests/overload/toverprc.nim
index 112eae096..9be2203f6 100644
--- a/tests/overload/toverprc.nim
+++ b/tests/overload/toverprc.nim
@@ -11,7 +11,7 @@ proc parseInt(x: float): int {.noSideEffect.} = discard
 proc parseInt(x: bool): int {.noSideEffect.} = discard
 proc parseInt(x: float32): int {.noSideEffect.} = discard
 proc parseInt(x: int8): int {.noSideEffect.} = discard
-proc parseInt(x: TFile): int {.noSideEffect.} = discard
+proc parseInt(x: File): int {.noSideEffect.} = discard
 proc parseInt(x: char): int {.noSideEffect.} = discard
 proc parseInt(x: int16): int {.noSideEffect.} = discard
 
diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim
new file mode 100644
index 000000000..69136a3b6
--- /dev/null
+++ b/tests/parallel/twaitany.nim
@@ -0,0 +1,35 @@
+discard """
+  output: '''true'''
+"""
+
+# bug #7638
+import threadpool, os, strformat
+
+proc timer(d: int): int =
+  #echo fmt"sleeping {d}"
+  sleep(d)
+  #echo fmt"done {d}"
+  return d
+
+var durations = [1000, 2000, 3000, 4000, 5000]
+var tasks: seq[FlowVarBase] = @[]
+var results: seq[int] = @[]
+
+for i in 0 .. durations.high:
+  tasks.add spawn timer(durations[i])
+
+var index = awaitAny(tasks)
+while index != -1:
+  results.add ^cast[FlowVar[int]](tasks[index])
+  tasks.del(index)
+  #echo repr results
+  index = awaitAny(tasks)
+
+doAssert results.len == 5
+doAssert 1000 in results
+doAssert 2000 in results
+doAssert 3000 in results
+doAssert 4000 in results
+doAssert 5000 in results
+sync()
+echo "true"
diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim
index 28a8713ce..33a4a7e65 100644
--- a/tests/pragmas/tcustom_pragma.nim
+++ b/tests/pragmas/tcustom_pragma.nim
@@ -51,6 +51,9 @@ block: # A bit more advanced case
 
   static: assert(hasCustomPragma(myproc, alternativeKey))
 
+  const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue)
+  static: assert(hasFieldCustomPragma == false)
+
   # pragma on an object
   static:
     assert Subfield.hasCustomPragma(defaultValue)
@@ -71,6 +74,8 @@ block: # ref types
     MyFile {.defaultValue: "closed".} = ref object
       path {.defaultValue: "invalid".}: string
 
+    TypeWithoutPragma = object
+
   var s = NodeRef()
 
   const
@@ -91,7 +96,7 @@ block: # ref types
 
   var ptrS = NodePtr(nil)
   const
-    ptrRightSerKey = getCustomPragmaVal(s.right, serializationKey)
+    ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey)
   static:
     assert ptrRightSerKey == "r"
 
@@ -103,6 +108,9 @@ block: # ref types
     assert fileDefVal == "closed"
     assert filePathDefVal == "invalid"
 
+  static:
+    assert TypeWithoutPragma.hasCustomPragma(defaultValue) == false
+
 block:
   type
     VariantKind = enum
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index f35965286..945d7ba3d 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -409,4 +409,11 @@ suite "ttimes":
     # Bug with adding a day to a Time
     let day = 24.hours
     let tomorrow = now + day
-    check tomorrow - now == initDuration(days = 1)
\ No newline at end of file
+    check tomorrow - now == initDuration(days = 1)
+  
+  test "fromWinTime/toWinTime":
+    check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0
+    check (-1).fromWinTime.nanoseconds == convert(Seconds, Nanoseconds, 1) - 100
+    check -1.fromWinTime.toWinTime == -1
+    # One nanosecond is discarded due to differences in time resolution
+    check initTime(0, 101).toWinTime.fromWinTime.nanoseconds == 100 
\ No newline at end of file
diff --git a/tests/template/i2416.nim b/tests/template/i2416.nim
new file mode 100644
index 000000000..4b53cd0ca
--- /dev/null
+++ b/tests/template/i2416.nim
@@ -0,0 +1 @@
+template i2416*() = echo "i2416"
diff --git a/tests/template/t2416.nim b/tests/template/t2416.nim
new file mode 100644
index 000000000..f73880718
--- /dev/null
+++ b/tests/template/t2416.nim
@@ -0,0 +1,2 @@
+import i2416
+i2416()
diff --git a/tests/varres/tnewseq_on_result_vart.nim b/tests/varres/tnewseq_on_result_vart.nim
new file mode 100644
index 000000000..18935a1d1
--- /dev/null
+++ b/tests/varres/tnewseq_on_result_vart.nim
@@ -0,0 +1,9 @@
+
+discard """
+  line: 9
+  errormsg: "address of 'result' may not escape its stack frame"
+"""
+# bug #5113
+
+proc makeSeqVar(size: Natural): var seq[int] =
+  newSeq(result, size)
diff --git a/tools/nimpretty.nim b/tools/nimpretty.nim
index 36d1382cf..396f17b0b 100644
--- a/tools/nimpretty.nim
+++ b/tools/nimpretty.nim
@@ -24,7 +24,7 @@ const
 Usage:
   nimpretty [options] file.nim
 Options:
-  --backup:ON|OFF     create a backup file before overwritting (default: ON)
+  --backup:on|off     create a backup file before overwritting (default: ON)
   --version           show the version
   --help              show this help
 """
@@ -43,7 +43,7 @@ proc prettyPrint(infile: string) =
   let fileIdx = fileInfoIdx(infile)
   let tree = parseFile(fileIdx, newIdentCache())
   let outfile = changeFileExt(infile, ".pretty.nim")
-  renderModule(tree, infile, outfile, {})
+  renderModule(tree, infile, outfile, {}, fileIdx)
 
 proc main =
   var infile: string
diff --git a/web/website.ini b/web/website.ini
index 56b7c436f..18e7bf2cb 100644
--- a/web/website.ini
+++ b/web/website.ini
@@ -31,7 +31,7 @@ file: ticker.html
 [Documentation]
 doc: "endb.rst;intern.txt;apis.txt;lib.rst;manual.rst;tut1.rst;tut2.rst;nimc.rst;overview.rst;filters.rst"
 doc: "tools.txt;niminst.rst;nimgrep.rst;gc.rst;estp.rst;idetools.rst;docgen.rst;koch.rst;backends.txt"
-doc: "nimfix.rst;nimsuggest.rst;nep1.rst;nims.rst;contributing.rst"
+doc: "nimfix.rst;nimsuggest.rst;nep1.rst;nims.rst;contributing.rst;manual/*.rst"
 pdf: "manual.rst;lib.rst;tut1.rst;tut2.rst;nimc.rst;niminst.rst;gc.rst"
 srcdoc2: "system.nim;system/nimscript;pure/ospaths"
 srcdoc2: "core/macros;pure/marshal;core/typeinfo"