summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/astalgo.nim28
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/ccgutils.nim58
-rw-r--r--compiler/extccomp.nim3
-rw-r--r--compiler/filter_tmpl.nim18
-rw-r--r--compiler/importer.nim2
-rw-r--r--compiler/jsgen.nim2
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/nimlexbase.nim2
-rw-r--r--compiler/renderer.nim6
-rw-r--r--compiler/sem.nim46
-rw-r--r--compiler/semcall.nim119
-rw-r--r--compiler/sigmatch.nim279
-rw-r--r--compiler/types.nim484
-rw-r--r--compiler/vm.nim46
-rw-r--r--doc/lib.txt3
-rw-r--r--koch.nim2
-rw-r--r--lib/impure/re.nim6
-rw-r--r--lib/nimbase.h18
-rw-r--r--lib/packages/docutils/rst.nim4
-rw-r--r--lib/packages/docutils/rstast.nim10
-rw-r--r--lib/packages/docutils/rstgen.nim6
-rw-r--r--lib/pure/algorithm.nim28
-rw-r--r--lib/pure/asyncfile.nim4
-rw-r--r--lib/pure/collections/tables.nim6
-rw-r--r--lib/pure/hashes.nim4
-rw-r--r--lib/pure/httpclient.nim10
-rw-r--r--lib/pure/json.nim2
-rw-r--r--lib/pure/lexbase.nim2
-rw-r--r--lib/pure/redis.nim16
-rw-r--r--lib/pure/streams.nim10
-rw-r--r--lib/pure/times.nim8
-rw-r--r--lib/pure/uri.nim10
-rw-r--r--lib/pure/xmldom.nim12
-rw-r--r--tests/ccgbugs/tuple_canon.nim80
-rw-r--r--tests/clearmsg/tconsttypemismatch.nim8
-rw-r--r--tests/generics/tgeneric3.nim2
-rw-r--r--tests/manyloc/argument_parser/argument_parser.nim2
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim6
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_server.nim2
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/map_filter.nim4
-rw-r--r--tests/manyloc/keineschweine/lib/zlib_helpers.nim10
-rw-r--r--tests/manyloc/keineschweine/server/old_sg_server.nim2
-rw-r--r--tests/overload/tsymtabchange_during_or.nim24
-rw-r--r--tests/testament/categories.nim5
-rw-r--r--tests/vm/tconsteval.nim2
-rw-r--r--tools/nimgrep.nim2
-rw-r--r--tools/nimweb.nim4
-rw-r--r--web/website.ini1
50 files changed, 802 insertions, 612 deletions
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 8d132ab26..c53e53b88 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -203,9 +203,9 @@ proc mustRehash(length, counter: int): bool =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc spaces(x: int): PRope = 
+proc rspaces(x: int): PRope = 
   # returns x spaces
-  result = toRope(repeatChar(x))
+  result = toRope(spaces(x))
 
 proc toYamlChar(c: char): string = 
   case c
@@ -253,7 +253,7 @@ proc typeToYamlAux(n: PType, marker: var IntSet,
                    indent, maxRecDepth: int): PRope
 proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int, 
                     maxRecDepth: int): PRope = 
-  var istr = spaces(indent + 2)
+  var istr = rspaces(indent + 2)
   result = toRope("[")
   var mycount = 0
   for i in countup(0, high(n.data)): 
@@ -262,20 +262,20 @@ proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
       appf(result, "$N$1$2", 
            [istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
       inc(mycount)
-  if mycount > 0: appf(result, "$N$1", [spaces(indent)])
+  if mycount > 0: appf(result, "$N$1", [rspaces(indent)])
   app(result, "]")
   assert(mycount == n.counter)
 
 proc ropeConstr(indent: int, c: openArray[PRope]): PRope = 
   # array of (name, value) pairs
-  var istr = spaces(indent + 2)
+  var istr = rspaces(indent + 2)
   result = toRope("{")
   var i = 0
   while i <= high(c): 
     if i > 0: app(result, ",")
     appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
     inc(i, 2)
-  appf(result, "$N$1}", [spaces(indent)])
+  appf(result, "$N$1}", [rspaces(indent)])
 
 proc symToYamlAux(n: PSym, marker: var IntSet, indent: int, 
                   maxRecDepth: int): PRope = 
@@ -310,9 +310,9 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
       result = toRope("[")
       for i in countup(0, sonsLen(n) - 1): 
         if i > 0: app(result, ",")
-        appf(result, "$N$1$2", [spaces(indent + 4), typeToYamlAux(n.sons[i], 
+        appf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i], 
             marker, indent + 4, maxRecDepth - 1)])
-      appf(result, "$N$1]", [spaces(indent + 2)])
+      appf(result, "$N$1]", [rspaces(indent + 2)])
     else: 
       result = toRope("null")
     result = ropeConstr(indent, [toRope("kind"), 
@@ -331,7 +331,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
   if n == nil: 
     result = toRope("null")
   else: 
-    var istr = spaces(indent + 2)
+    var istr = rspaces(indent + 2)
     result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
     if maxRecDepth != 0: 
       appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
@@ -359,12 +359,12 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
           appf(result, ",$N$1\"sons\": [", [istr])
           for i in countup(0, sonsLen(n) - 1): 
             if i > 0: app(result, ",")
-            appf(result, "$N$1$2", [spaces(indent + 4), treeToYamlAux(n.sons[i], 
+            appf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i], 
                 marker, indent + 4, maxRecDepth - 1)])
           appf(result, "$N$1]", [istr])
       appf(result, ",$N$1\"typ\": $2", 
            [istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
-    appf(result, "$N$1}", [spaces(indent)])
+    appf(result, "$N$1}", [rspaces(indent)])
 
 proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope = 
   var marker = initIntSet()
@@ -408,7 +408,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
   if n == nil: 
     result = toRope("null")
   else: 
-    var istr = spaces(indent + 2)
+    var istr = rspaces(indent + 2)
     result = ropef("{$N$1\"kind\": $2", 
                    [istr, makeYamlString($n.kind)])
     if maxRecDepth != 0: 
@@ -440,11 +440,11 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
           appf(result, ",$N$1\"sons\": [", [istr])
           for i in countup(0, sonsLen(n) - 1): 
             if i > 0: app(result, ",")
-            appf(result, "$N$1$2", [spaces(indent + 4), debugTree(n.sons[i], 
+            appf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i], 
                 indent + 4, maxRecDepth - 1, renderType)])
           appf(result, "$N$1]", [istr])
     appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
-    appf(result, "$N$1}", [spaces(indent)])
+    appf(result, "$N$1}", [rspaces(indent)])
 
 proc debug(n: PSym) =
   if n == nil:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 5f5aa6308..564d1fd36 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -949,7 +949,7 @@ proc genEcho(p: BProc, n: PNode) =
     initLocExpr(p, n.sons[i], a)
     appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
   linefmt(p, cpsStmts, "printf($1$2);$n",
-          makeCString(repeatStr(n.len, "%s") & tnl), args)
+          makeCString(repeat("%s", n.len) & tnl), args)
 
 proc gcUsage(n: PNode) =
   if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 59b9611fc..25c1a12e5 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -9,31 +9,31 @@
 
 # This module declares some helpers for the C code generator.
 
-import 
-  ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg, 
+import
+  ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
   platform, trees
 
 proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
   case n.kind
-  of nkStmtList: 
-    for i in 0 .. < n.len: 
+  of nkStmtList:
+    for i in 0 .. < n.len:
       result = getPragmaStmt(n[i], w)
       if result != nil: break
   of nkPragma:
-    for i in 0 .. < n.len: 
+    for i in 0 .. < n.len:
       if whichPragma(n[i]) == w: return n[i]
   else: discard
 
 proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
   result = getPragmaStmt(n, w) != nil
 
-proc hashString*(s: string): BiggestInt = 
+proc hashString*(s: string): BiggestInt =
   # has to be the same algorithm as system.hashString!
-  if CPU[targetCPU].bit == 64: 
+  if CPU[targetCPU].bit == 64:
     # we have to use the same bitwidth
     # as the target CPU
     var b = 0'i64
-    for i in countup(0, len(s) - 1): 
+    for i in countup(0, len(s) - 1):
       b = b +% ord(s[i])
       b = b +% `shl`(b, 10)
       b = b xor `shr`(b, 6)
@@ -41,9 +41,9 @@ proc hashString*(s: string): BiggestInt =
     b = b xor `shr`(b, 11)
     b = b +% `shl`(b, 15)
     result = b
-  else: 
+  else:
     var a = 0'i32
-    for i in countup(0, len(s) - 1): 
+    for i in countup(0, len(s) - 1):
       a = a +% ord(s[i]).int32
       a = a +% `shl`(a, 10'i32)
       a = a xor `shr`(a, 6'i32)
@@ -52,11 +52,11 @@ proc hashString*(s: string): BiggestInt =
     a = a +% `shl`(a, 15'i32)
     result = a
 
-var 
+var
   gTypeTable: array[TTypeKind, TIdTable]
   gCanonicalTypes: array[TTypeKind, PType]
 
-proc initTypeTables() = 
+proc initTypeTables() =
   for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
 
 proc resetCaches* =
@@ -67,7 +67,7 @@ proc resetCaches* =
 
 when false:
   proc echoStats*() =
-    for i in countup(low(TTypeKind), high(TTypeKind)): 
+    for i in countup(low(TTypeKind), high(TTypeKind)):
       echo i, " ", gTypeTable[i].counter
 
 proc slowSearch(key: PType; k: TTypeKind): PType =
@@ -78,21 +78,21 @@ proc slowSearch(key: PType; k: TTypeKind): PType =
   if idTableHasObjectAsKey(gTypeTable[k], key): return key
   for h in countup(0, high(gTypeTable[k].data)):
     var t = PType(gTypeTable[k].data[h].key)
-    if t != nil and sameBackendType(t, key): 
+    if t != nil and sameBackendType(t, key):
       return t
   idTablePut(gTypeTable[k], key, key)
   result = key
 
-proc getUniqueType*(key: PType): PType = 
+proc getUniqueType*(key: PType): PType =
   # this is a hotspot in the compiler!
-  if key == nil: return 
+  if key == nil: return
   var k = key.kind
   case k
   of tyBool, tyChar, tyInt..tyUInt64:
     # no canonicalization for integral types, so that e.g. ``pid_t`` is
     # produced instead of ``NI``.
     result = key
-  of  tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString, 
+  of  tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
       tyCString, tyNone, tyBigNum:
     result = gCanonicalTypes[k]
     if result == nil:
@@ -127,7 +127,7 @@ proc getUniqueType*(key: PType): PType =
     if tfFromGeneric notin key.flags:
       # fast case; lookup per id suffices:
       result = PType(idTableGet(gTypeTable[k], key))
-      if result == nil: 
+      if result == nil:
         idTablePut(gTypeTable[k], key, key)
         result = key
     else:
@@ -138,10 +138,10 @@ proc getUniqueType*(key: PType): PType =
         if t != nil and sameBackendType(t, key):
           return t
       idTablePut(gTypeTable[k], key, key)
-      result = key    
+      result = key
   of tyEnum:
     result = PType(idTableGet(gTypeTable[k], key))
-    if result == nil: 
+    if result == nil:
       idTablePut(gTypeTable[k], key, key)
       result = key
   of tyProc:
@@ -151,16 +151,16 @@ proc getUniqueType*(key: PType): PType =
       # ugh, we need the canon here:
       result = slowSearch(key, k)
 
-proc tableGetType*(tab: TIdTable, key: PType): RootRef = 
+proc tableGetType*(tab: TIdTable, key: PType): RootRef =
   # returns nil if we need to declare this type
   result = idTableGet(tab, key)
-  if (result == nil) and (tab.counter > 0): 
+  if (result == nil) and (tab.counter > 0):
     # we have to do a slow linear search because types may need
     # to be compared by their structure:
-    for h in countup(0, high(tab.data)): 
+    for h in countup(0, high(tab.data)):
       var t = PType(tab.data[h].key)
-      if t != nil: 
-        if sameType(t, key): 
+      if t != nil:
+        if sameType(t, key):
           return tab.data[h].val
 
 proc makeSingleLineCString*(s: string): string =
@@ -193,16 +193,16 @@ proc mangle*(name: string): string =
     else:
       add(result, "HEX" & toHex(ord(c), 2))
 
-proc makeLLVMString*(s: string): PRope = 
+proc makeLLVMString*(s: string): PRope =
   const MaxLineLength = 64
   result = nil
   var res = "c\""
-  for i in countup(0, len(s) - 1): 
-    if (i + 1) mod MaxLineLength == 0: 
+  for i in countup(0, len(s) - 1):
+    if (i + 1) mod MaxLineLength == 0:
       app(result, toRope(res))
       setLen(res, 0)
     case s[i]
-    of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\': 
+    of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
       add(res, '\\')
       add(res, toHex(ord(s[i]), 2))
     else: add(res, s[i])
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 5f6033e57..8888632b9 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -572,6 +572,9 @@ proc footprint(filename: string): TCrc32 =
       getCompileCFileCmd(filename, true)
 
 proc externalFileChanged(filename: string): bool = 
+  if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
+    return false
+
   var crcFile = toGeneratedFile(filename.withPackageName, "crc")
   var currentCrc = int(footprint(filename))
   var f: File
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index 7b975dbaa..5d1f73be4 100644
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -37,11 +37,11 @@ const
   PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
 
 proc newLine(p: var TTmplParser) = 
-  llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
+  llStreamWrite(p.outp, repeat(')', p.emitPar))
   p.emitPar = 0
   if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
   if p.pendingExprLine:
-    llStreamWrite(p.outp, repeatChar(2))
+    llStreamWrite(p.outp, spaces(2))
     p.pendingExprLine = false
   
 proc scanPar(p: var TTmplParser, d: int) = 
@@ -88,24 +88,24 @@ proc parseLine(p: var TTmplParser) =
       else: 
         p.info.col = int16(j)
         localError(p.info, errXNotAllowedHere, "end")
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, "#end")
     of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator, 
        wConverter, wMacro, wTemplate, wMethod: 
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, substr(p.x, d))
       inc(p.indent, 2)
     of wElif, wOf, wElse, wExcept, wFinally: 
-      llStreamWrite(p.outp, repeatChar(p.indent - 2))
+      llStreamWrite(p.outp, spaces(p.indent - 2))
       llStreamWrite(p.outp, substr(p.x, d))
     of wLet, wVar, wConst, wType:
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, substr(p.x, d))
       if not p.x.contains({':', '='}):
         # no inline element --> treat as block:
         inc(p.indent, 2)
     else:
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, substr(p.x, d))
     p.state = psDirective
   else: 
@@ -120,11 +120,11 @@ proc parseLine(p: var TTmplParser) =
       # next line of string literal:
       llStreamWrite(p.outp, p.conc)
       llStreamWrite(p.outp, "\n")
-      llStreamWrite(p.outp, repeatChar(p.indent + 2))
+      llStreamWrite(p.outp, spaces(p.indent + 2))
       llStreamWrite(p.outp, "\"")
     of psDirective: 
       newLine(p)
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, p.emit)
       llStreamWrite(p.outp, "(\"")
       inc(p.emitPar)
diff --git a/compiler/importer.nim b/compiler/importer.nim
index fbf3be4f2..57a1e542b 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -27,7 +27,7 @@ proc getModuleName*(n: PNode): string =
     result = n.ident.s
   of nkSym:
     result = n.sym.name.s
-  of nkInfix:
+  of nkInfix, nkPrefix:
     if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
       # XXX hack ahead:
       n.kind = nkImportAs
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 34f842d4a..87847204f 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -780,7 +780,7 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
     moveInto(p, stmt, r)
     appf(p.body, "}$n" | "end$n")
   if p.target == targetJS:
-    app(p.body, repeatChar(toClose, '}') & tnl)
+    app(p.body, repeat('}', toClose) & tnl)
   else:
     for i in 1..toClose: appf(p.body, "end$n")
 
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index a72dedf57..e15cdc86d 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -784,7 +784,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
 proc writeSurroundingSrc(info: TLineInfo) =
   const indent = "  "
   msgWriteln(indent & info.sourceLine.ropeToStr)
-  msgWriteln(indent & repeatChar(info.col, ' ') & '^')
+  msgWriteln(indent & spaces(info.col) & '^')
 
 proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
   let frmt = case msg
diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim
index e18e1c22a..f5db5ca4f 100644
--- a/compiler/nimlexbase.nim
+++ b/compiler/nimlexbase.nim
@@ -166,4 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
     inc(i)
   result.add("\n")
   if marker: 
-    result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
+    result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n")
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 204bfbf94..f5cabb4bc 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -92,7 +92,7 @@ proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
 
 proc addPendingNL(g: var TSrcGen) = 
   if g.pendingNL >= 0: 
-    addTok(g, tkSpaces, "\n" & repeatChar(g.pendingNL))
+    addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
     g.lineLen = g.pendingNL
     g.pendingNL = - 1
 
@@ -190,7 +190,7 @@ proc putComment(g: var TSrcGen, s: string) =
       if not isCode and (g.lineLen + (j - i) > MaxLineLen): 
         put(g, tkComment, com)
         optNL(g, ind)
-        com = '#' & repeatChar(comIndent)
+        com = '#' & spaces(comIndent)
       while s[i] > ' ': 
         add(com, s[i])
         inc(i)
@@ -280,7 +280,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
         (g.lineLen < LineCommentColumn): 
       var ml = maxLineLength(n.comment)
       if ml + LineCommentColumn <= MaxLineLen: 
-        put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
+        put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
     putComment(g, n.comment)  #assert(g.comStack[high(g.comStack)] = n);
   
 proc gcoms(g: var TSrcGen) = 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index a90948245..36c0342cd 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -65,8 +65,8 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
         echo "passing to safeSemExpr: ", renderTree(n)
       discard safeSemExpr(c, n)
 
-proc typeMismatch(n: PNode, formal, actual: PType) = 
-  if formal.kind != tyError and actual.kind != tyError: 
+proc typeMismatch(n: PNode, formal, actual: PType) =
+  if formal.kind != tyError and actual.kind != tyError:
     localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
         typeToString(actual) & ") " &
         `%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
@@ -113,7 +113,7 @@ proc commonType*(x, y: PType): PType =
     else:
       result = newType(tyTypeDesc, a.owner)
       rawAddSon(result, newType(tyNone, a.owner))
-  elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and 
+  elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
       a.kind == b.kind:
     # check for seq[empty] vs. seq[int]
     let idx = ord(b.kind in {tyArray, tyArrayConstr})
@@ -163,7 +163,7 @@ proc commonType*(x, y: PType): PType =
         result = newType(k, r.owner)
         result.addSonSkipIntLit(r)
 
-proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = 
+proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
   result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
 
 proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
@@ -182,7 +182,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
                  allowed: TSymFlags): PSym
   # identifier with visability
-proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, 
+proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
                         allowed: TSymFlags): PSym
 proc semStmtScope(c: PContext, n: PNode): PNode
 
@@ -190,7 +190,7 @@ proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
   let t = typeAllowed(typ, kind)
   if t != nil:
     if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
-    else: localError(info, "invalid type: '" & typeToString(t) & 
+    else: localError(info, "invalid type: '" & typeToString(t) &
                            "' in this context: '" & typeToString(typ) & "'")
 
 proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
@@ -226,7 +226,7 @@ when false:
         result = newSymNode(getSysSym"void")
       else:
         result.typ = makeTypeDesc(c, result.typ)
-    
+
     result.handleIsOperator = proc (n: PNode): PNode =
       result = isOpImpl(c, n)
 
@@ -248,7 +248,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
     if result == nil:
       result = arg
       # for 'tcnstseq' we support [] to become 'seq'
-      if eOrig.typ.skipTypes(abstractInst).kind == tySequence and 
+      if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
          arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
         arg.typ = eOrig.typ
 
@@ -320,7 +320,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
   else:
     case s.typ.sons[0].kind
     of tyExpr:
-      # BUGFIX: we cannot expect a type here, because module aliases would not 
+      # BUGFIX: we cannot expect a type here, because module aliases would not
       # work then (see the ``tmodulealias`` test)
       # semExprWithType(c, result)
       result = semExpr(c, result, flags)
@@ -355,18 +355,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
     result = semAfterMacroCall(c, result, sym, flags)
   popInfoContext()
 
-proc forceBool(c: PContext, n: PNode): PNode = 
+proc forceBool(c: PContext, n: PNode): PNode =
   result = fitNode(c, getSysType(tyBool), n)
   if result == nil: result = n
 
-proc semConstBoolExpr(c: PContext, n: PNode): PNode = 
+proc semConstBoolExpr(c: PContext, n: PNode): PNode =
   let nn = semExprWithType(c, n)
   result = fitNode(c, getSysType(tyBool), nn)
   if result == nil:
     localError(n.info, errConstExprExpected)
     return nn
   result = getConstExpr(c.module, result)
-  if result == nil: 
+  if result == nil:
     localError(n.info, errConstExprExpected)
     result = nn
 
@@ -403,9 +403,9 @@ proc myOpen(module: PSym): PPassContext =
   pushOwner(c.module)
   c.importTable = openScope(c)
   c.importTable.addSym(module) # a module knows itself
-  if sfSystemModule in module.flags: 
+  if sfSystemModule in module.flags:
     magicsys.systemModule = module # set global variable!
-  else: 
+  else:
     c.importTable.addSym magicsys.systemModule # import the "System" identifier
     importAllSymbols(c, magicsys.systemModule)
   c.topLevelScope = openScope(c)
@@ -415,13 +415,13 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
   result = myOpen(module)
   for m in items(rd.methods): methodDef(m, true)
 
-proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = 
+proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
   result = semStmt(c, n)
   # BUGFIX: process newly generated generics here, not at the end!
   if c.lastGenericIdx < c.generics.len:
     var a = newNodeI(nkStmtList, n.info)
     addCodeForGenerics(c, a)
-    if sonsLen(a) > 0: 
+    if sonsLen(a) > 0:
       # a generic has been added to `a`:
       if result.kind != nkEmpty: addSon(a, result)
       result = a
@@ -429,17 +429,17 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
   if gCmd == cmdInteractive and not isEmptyType(result.typ):
     result = buildEchoStmt(c, result)
   result = transformStmt(c.module, result)
-    
-proc recoverContext(c: PContext) = 
+
+proc recoverContext(c: PContext) =
   # clean up in case of a semantic error: We clean up the stacks, etc. This is
-  # faster than wrapping every stack operation in a 'try finally' block and 
+  # faster than wrapping every stack operation in a 'try finally' block and
   # requires far less code.
   c.currentScope = c.topLevelScope
   while getCurrOwner().kind != skModule: popOwner()
   while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
 
-proc myProcess(context: PPassContext, n: PNode): PNode = 
-  var c = PContext(context)    
+proc myProcess(context: PPassContext, n: PNode): PNode =
+  var c = PContext(context)
   # no need for an expensive 'try' if we stop after the first error anyway:
   if msgs.gErrorMax <= 1:
     result = semStmtAndGenerateGenerics(c, n)
@@ -455,8 +455,8 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
       if getCurrentException() of ESuggestDone: result = nil
       else: result = ast.emptyNode
       #if gCmd == cmdIdeTools: findSuggest(c, n)
-    
-proc myClose(context: PPassContext, n: PNode): PNode = 
+
+proc myClose(context: PPassContext, n: PNode): PNode =
   var c = PContext(context)
   closeScope(c)         # close module's scope
   rawCloseScope(c)      # imported symbols; don't check for unused ones!
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index d92e1ab20..647e75b3a 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -7,16 +7,16 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements semantic checking for calls. 
+## This module implements semantic checking for calls.
 # included from sem.nim
 
 proc sameMethodDispatcher(a, b: PSym): bool =
   result = false
-  if a.kind == skMethod and b.kind == skMethod: 
+  if a.kind == skMethod and b.kind == skMethod:
     var aa = lastSon(a.ast)
     var bb = lastSon(b.ast)
     if aa.kind == nkSym and bb.kind == nkSym:
-      if aa.sym == bb.sym: 
+      if aa.sym == bb.sym:
         result = true
     else:
       discard
@@ -31,7 +31,7 @@ proc sameMethodDispatcher(a, b: PSym): bool =
       # to avoid subtle problems, the call remains ambiguous and needs to
       # be disambiguated by the programmer; this way the right generic is
       # instantiated.
-  
+
 proc determineType(c: PContext, s: PSym)
 
 proc pickBestCandidate(c: PContext, headSymbol: PNode,
@@ -41,73 +41,80 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
                        best, alt: var TCandidate,
                        errors: var CandidateErrors) =
   var o: TOverloadIter
-  var sym = initOverloadIter(o, c, headSymbol)
+  # thanks to the lazy semchecking for operands, we need to iterate over the
+  # symbol table *before* any call to 'initCandidate' which might invoke
+  # semExpr which might modify the symbol table in cases like
+  # 'init(a, 1, (var b = new(Type2); b))'.
+  var symx = initOverloadIter(o, c, headSymbol)
   let symScope = o.lastOverloadScope
 
+  var syms: seq[tuple[a: PSym, b: int]] = @[]
+  while symx != nil:
+    if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
+    symx = nextOverloadIter(o, c, headSymbol)
+  if syms.len == 0: return
+
   var z: TCandidate
-  
-  if sym == nil: return
-  initCandidate(c, best, sym, initialBinding, symScope)
-  initCandidate(c, alt, sym, initialBinding, symScope)
+  initCandidate(c, best, syms[0][0], initialBinding, symScope)
+  initCandidate(c, alt, syms[0][0], initialBinding, symScope)
   best.state = csNoMatch
-  
-  while sym != nil:
-    if sym.kind in filter:
-      determineType(c, sym)
-      initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
-      z.calleeSym = sym
 
+  for i in 0 .. <syms.len:
+    let sym = syms[i][0]
+    determineType(c, sym)
+    initCandidate(c, z, sym, initialBinding, syms[i][1])
+    z.calleeSym = sym
+
+    #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
+    #  gDebug = true
+    matches(c, n, orig, z)
+    if errors != nil:
+      errors.safeAdd(sym)
+      if z.errors != nil:
+        for err in z.errors:
+          errors.add(err)
+    if z.state == csMatch:
+      # little hack so that iterators are preferred over everything else:
+      if sym.kind in skIterators: inc(z.exactMatches, 200)
+      case best.state
+      of csEmpty, csNoMatch: best = z
+      of csMatch:
+        var cmp = cmpCandidates(best, z)
+        if cmp < 0: best = z   # x is better than the best so far
+        elif cmp == 0: alt = z # x is as good as the best so far
+        else: discard
       #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
-      #  gDebug = true
-      matches(c, n, orig, z)
-      if errors != nil:
-        errors.safeAdd(sym)
-        if z.errors != nil:
-          for err in z.errors:
-            errors.add(err)
-      if z.state == csMatch:
-        # little hack so that iterators are preferred over everything else:
-        if sym.kind in skIterators: inc(z.exactMatches, 200)
-        case best.state
-        of csEmpty, csNoMatch: best = z
-        of csMatch:
-          var cmp = cmpCandidates(best, z)
-          if cmp < 0: best = z   # x is better than the best so far
-          elif cmp == 0: alt = z # x is as good as the best so far
-          else: discard
-        #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
-        #  echo "Matches ", n.info, " ", typeToString(sym.typ)
-        #  debug sym
-        #  writeMatches(z)
-        #  for i in 1 .. <len(z.call):
-        #    z.call[i].typ.debug
-        #  quit 1
-    sym = nextOverloadIter(o, c, headSymbol)
+      #  echo "Matches ", n.info, " ", typeToString(sym.typ)
+      #  debug sym
+      #  writeMatches(z)
+      #  for i in 1 .. <len(z.call):
+      #    z.call[i].typ.debug
+      #  quit 1
 
 proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   # Gives a detailed error message; this is separated from semOverloadedCall,
   # as semOverlodedCall is already pretty slow (and we need this information
   # only in case of an error).
-  if c.inCompilesContext > 0: 
+  if c.inCompilesContext > 0:
     # fail fast:
     globalError(n.info, errTypeMismatch, "")
   if errors.isNil or errors.len == 0:
     localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
     return
 
-  # to avoid confusing errors like: 
+  # to avoid confusing errors like:
   #   got (SslPtr, SocketHandle)
-  #   but expected one of: 
+  #   but expected one of:
   #   openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
   # we do a pre-analysis. If all types produce the same string, we will add
   # module information.
   let proto = describeArgs(c, n, 1, preferName)
-  
+
   var prefer = preferName
   for err in errors:
     var errProto = ""
     let n = err.typ.n
-    for i in countup(1, n.len - 1): 
+    for i in countup(1, n.len - 1):
       var p = n.sons[i]
       if p.kind == nkSym:
         add(errProto, typeToString(p.sym.typ, preferName))
@@ -159,9 +166,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
     n.sons.insert(hiddenArg, 1)
     orig.sons.insert(hiddenArg, 1)
-    
+
     pickBest(f)
- 
+
     if result.state != csMatch:
       n.sons.delete(1)
       orig.sons.delete(1)
@@ -179,7 +186,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       # we are going to try multiple variants
       n.sons[0..1] = [nil, n[1], calleeName]
       orig.sons[0..1] = [nil, orig[1], calleeName]
-      
+
       template tryOp(x) =
         let op = newIdentNode(getIdent(x), n.info)
         n.sons[0] = op
@@ -188,7 +195,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
       if nfExplicitCall in n.flags:
         tryOp ".()"
-   
+
       if result.state in {csEmpty, csNoMatch}:
         tryOp "."
 
@@ -199,7 +206,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       n.sons[0..1] = [callOp, n[1], calleeName]
       orig.sons[0..1] = [callOp, orig[1], calleeName]
       pickBest(callOp)
-   
+
     if overloadsState == csEmpty and result.state == csEmpty:
       localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
       return
@@ -224,7 +231,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
     internalAssert result.state == csMatch
     #writeMatches(result)
     #writeMatches(alt)
-    if c.inCompilesContext > 0: 
+    if c.inCompilesContext > 0:
       # quick error message for performance of 'compiles' built-in:
       globalError(n.info, errGenerated, "ambiguous call")
     elif gErrorCounter == 0:
@@ -254,7 +261,7 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
     for i in 1 .. <n.len:
       instGenericConvertersArg(c, n.sons[i], x)
 
-proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode = 
+proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
   var m: TCandidate
   initCandidate(c, m, f)
   result = paramTypesMatch(m, f, a, arg, nil)
@@ -325,7 +332,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
       # get rid of the deref again for a better error message:
       n.sons[1] = n.sons[1].sons[0]
       notFoundError(c, n, errors)
-  else: 
+  else:
     notFoundError(c, n, errors)
   # else: result = errorNode(c, n)
 
@@ -341,7 +348,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
   styleCheckUse(n.info, s)
   result = newSymNode(newInst, n.info)
 
-proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = 
+proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   assert n.kind == nkBracketExpr
   for i in 1..sonsLen(n)-1:
     n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
@@ -361,11 +368,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
     # XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
     # It's good enough for now.
     result = newNodeI(a.kind, n.info)
-    for i in countup(0, len(a)-1): 
+    for i in countup(0, len(a)-1):
       var candidate = a.sons[i].sym
       if candidate.kind in {skProc, skMethod, skConverter,
                             skIterator, skClosureIterator}:
-        # it suffices that the candidate has the proper number of generic 
+        # it suffices that the candidate has the proper number of generic
         # type parameters:
         if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
           result.add(explicitGenericSym(c, n, candidate))
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index a1b5c8dc9..f34bdd3da 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -10,7 +10,7 @@
 ## This module implements the signature matching for resolving
 ## the call to overloaded procs, generic procs and operators.
 
-import 
+import
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
   nimfix.pretty
@@ -19,7 +19,7 @@ when not defined(noDocgen):
   import docgen
 
 type
-  TCandidateState* = enum 
+  TCandidateState* = enum
     csEmpty, csMatch, csNoMatch
 
   CandidateErrors* = seq[PSym]
@@ -62,10 +62,10 @@ type
     isGeneric,
     isFromIntLit,            # conversion *from* int literal; proven safe
     isEqual
-  
+
 const
   isNilConversion = isConvertible # maybe 'isIntConv' fits better?
-    
+
 proc markUsed*(info: TLineInfo, s: PSym)
 
 template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
@@ -128,7 +128,7 @@ proc newCandidate*(ctx: PContext, callee: PSym,
 proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
   initCandidate(ctx, result, callee)
 
-proc copyCandidate(a: var TCandidate, b: TCandidate) = 
+proc copyCandidate(a: var TCandidate, b: TCandidate) =
   a.c = b.c
   a.exactMatches = b.exactMatches
   a.subtypeMatches = b.subtypeMatches
@@ -176,7 +176,7 @@ proc complexDisambiguation(a, b: PType): int =
       let bb = b.sons[1].sumGeneric
       var a = a
       var b = b
-      
+
       if aa < bb: swap(a, b)
       # all must be better
       for i in 2 .. <min(a.len, b.len):
@@ -203,7 +203,7 @@ proc cmpCandidates*(a, b: TCandidate): int =
   # prefer more specialized generic over more general generic:
   result = complexDisambiguation(a.callee, b.callee)
 
-proc writeMatches*(c: TCandidate) = 
+proc writeMatches*(c: TCandidate) =
   writeln(stdout, "exact matches: " & $c.exactMatches)
   writeln(stdout, "generic matches: " & $c.genericMatches)
   writeln(stdout, "subtype matches: " & $c.subtypeMatches)
@@ -225,7 +225,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
   result = ""
   for i in countup(startIdx, n.len - 1):
     var arg = n.sons[i]
-    if n.sons[i].kind == nkExprEqExpr: 
+    if n.sons[i].kind == nkExprEqExpr:
       add(result, renderTree(n.sons[i].sons[0]))
       add(result, ": ")
       if arg.typ.isNil:
@@ -241,9 +241,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
     if i != sonsLen(n) - 1: add(result, ", ")
 
 proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
-proc concreteType(c: TCandidate, t: PType): PType = 
+proc concreteType(c: TCandidate, t: PType): PType =
   case t.kind
-  of tyArrayConstr: 
+  of tyArrayConstr:
     # make it an array
     result = newType(tyArray, t.owner)
     addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID!
@@ -255,7 +255,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
     else: result = t
   of tyGenericParam, tyAnything:
     result = t
-    while true: 
+    while true:
       result = PType(idTableGet(c.bindings, t))
       if result == nil:
         break # it's ok, no match
@@ -267,15 +267,15 @@ proc concreteType(c: TCandidate, t: PType): PType =
     result = t
   else:
     result = t                # Note: empty is valid here
-  
-proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = 
-  if a.kind == f.kind: 
+
+proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
+  if a.kind == f.kind:
     result = isEqual
   else:
     let ab = skipTypes(a, {tyRange})
     let k = ab.kind
     if k == f.kind: result = isSubrange
-    elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, 
+    elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
                                    tyUInt..tyUInt64} and
         isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
                          ab.n.intVal <= lastOrd(f):
@@ -286,7 +286,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
       result = isIntConv
     elif k >= min and k <= max:
       result = isConvertible
-    elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64, 
+    elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
                                                   tyUInt8..tyUInt32} and
                          a.n[0].intVal >= firstOrd(f) and
                          a.n[1].intVal <= lastOrd(f):
@@ -318,12 +318,12 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
       if f.kind == tyFloat32: result = isConvertible
       else: result = isIntConv
     else: result = isNone
-  
+
 proc isObjectSubtype(a, f: PType): int =
   var t = a
   assert t.kind == tyObject
   var depth = 0
-  while t != nil and not sameObjectTypes(f, t): 
+  while t != nil and not sameObjectTypes(f, t):
     assert t.kind == tyObject
     t = t.sons[0]
     if t == nil: break
@@ -332,17 +332,17 @@ proc isObjectSubtype(a, f: PType): int =
   if t != nil:
     result = depth
 
-proc minRel(a, b: TTypeRelation): TTypeRelation = 
+proc minRel(a, b: TTypeRelation): TTypeRelation =
   if a <= b: result = a
   else: result = b
-  
+
 proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
   result = isNone
   if sameType(f, a): result = isEqual
   elif sonsLen(a) == sonsLen(f):
     result = isEqual
     let firstField = if f.kind == tyTuple: 0
-                     else: 1 
+                     else: 1
     for i in countup(firstField, sonsLen(f) - 1):
       var m = typeRel(c, f.sons[i], a.sons[i])
       if m < isSubtype: return isNone
@@ -373,7 +373,7 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
       # We are matching a generic proc (as proc param)
       # to another generic type appearing in the proc
       # signature. There is a change that the target
-      # type is already fully-determined, so we are 
+      # type is already fully-determined, so we are
       # going to try resolve it
       f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
       if f == nil or f.isMetaType:
@@ -388,17 +388,17 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
 
   if result <= isSubtype or inconsistentVarTypes(f, a):
     result = isNone
- 
+
   if result == isEqual:
     inc c.exactMatches
-    
+
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   case a.kind
   of tyProc:
     if sonsLen(f) != sonsLen(a): return
     result = isEqual      # start with maximum; also correct for no
                           # params at all
-    
+
     template checkParam(f, a) =
       result = minRel(result, procParamTypeRel(c, f, a))
       if result == isNone: return
@@ -407,7 +407,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     # return type!
     for i in 1 .. <f.sonsLen:
       checkParam(f.sons[i], a.sons[i])
-    
+
     if f.sons[0] != nil:
       if a.sons[0] != nil:
         checkParam(f.sons[0], a.sons[0])
@@ -487,14 +487,14 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
       else:
         param = paramSym skType
         param.typ = makeTypeDesc(c, typ)
-      
+
       addDecl(c, param)
 
   for param in body.n[0]:
     var
       dummyName: PNode
       dummyType: PType
-    
+
     if param.kind == nkVarTy:
       dummyName = param[0]
       dummyType = if a.kind != tyVar: makeVarType(c, a)
@@ -520,7 +520,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
       of nkTypeSection: discard
       of nkConstDef: discard
       else: discard
-    
+
   return isGeneric
 
 proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
@@ -554,7 +554,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # typeRel can be used to establish various relationships between types:
   #
   # 1) When used with concrete types, it will check for type equivalence
-  # or a subtype relationship. 
+  # or a subtype relationship.
   #
   # 2) When used with a concrete type against a type class (such as generic
   # signature of a proc), it will check whether the concrete type is a member
@@ -569,7 +569,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   result = isNone
   assert(f != nil)
-  
+
   if f.kind == tyExpr:
     if aOrig != nil: put(c.bindings, f, aOrig)
     return isGeneric
@@ -582,7 +582,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # start the param matching process. This could be done in `prepareOperand`
   # for example, but unfortunately `prepareOperand` is not called in certain
   # situation when nkDotExpr are rotated to nkDotCalls
-  
+
   if a.kind == tyGenericInst and
       skipTypes(f, {tyVar}).kind notin {
         tyGenericBody, tyGenericInvocation,
@@ -626,9 +626,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       # seq[!int] vs seq[!number]
       # seq[float] matches the first, but not the second
       # we must turn the problem around:
-      # is number a subset of int? 
+      # is number a subset of int?
       return typeRel(c, a.lastSon, f.lastSon)
- 
+
     else:
       # negative type classes are essentially infinite,
       # so only the `any` type class is their superset
@@ -727,20 +727,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     of tyOpenArray, tyVarargs:
       result = typeRel(c, base(f), base(a))
       if result < isGeneric: result = isNone
-    of tyArrayConstr: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
+    of tyArrayConstr:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
         result = isSubtype    # [] is allowed here
-      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
         result = isSubtype
-    of tyArray: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
+    of tyArray:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
         result = isSubtype
-      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
         result = isConvertible
-    of tySequence: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
+    of tySequence:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
         result = isConvertible
-      elif typeRel(c, base(f), a.sons[0]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
         result = isConvertible
     else: discard
   of tySequence:
@@ -768,7 +768,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyForward: internalError("forward type in typeRel()")
   of tyNil:
     if a.kind == f.kind: result = isEqual
-  of tyTuple: 
+  of tyTuple:
     if a.kind == tyTuple: result = recordRel(c, f, a)
   of tyObject:
     if a.kind == tyObject:
@@ -783,13 +783,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyDistinct:
     if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
     elif c.coerceDistincts: result = typeRel(c, f.base, a)
-  of tySet: 
-    if a.kind == tySet: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
+  of tySet:
+    if a.kind == tySet:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
         result = isSubtype
-      else: 
+      else:
         result = typeRel(c, f.sons[0], a.sons[0])
-        if result <= isConvertible: 
+        if result <= isConvertible:
           result = isNone     # BUGFIX!
   of tyPtr, tyRef:
     if a.kind == f.kind:
@@ -823,9 +823,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       if a.len == 1: result = isConvertible
     of tyCString: result = isConvertible
     else: discard
-  of tyString: 
+  of tyString:
     case a.kind
-    of tyString: 
+    of tyString:
       if tfNotNil in f.flags and tfNotNil notin a.flags:
         result = isNilConversion
       else:
@@ -848,7 +848,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     of tyArray:
       if (firstOrd(a.sons[0]) == 0) and
           (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
-          (a.sons[1].kind == tyChar): 
+          (a.sons[1].kind == tyChar):
         result = isConvertible
     else: discard
 
@@ -863,7 +863,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         let ff = rootf.sons[i]
         let aa = roota.sons[i]
         result = typeRel(c, ff, aa)
-        if result == isNone: return        
+        if result == isNone: return
         if ff.kind == tyRange and result != isEqual: return isNone
       result = isGeneric
       # XXX See bug #2220. A[int] should match A[int] better than some generic X
@@ -883,13 +883,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
       # simply no match for now:
       discard
-    elif x.kind == tyGenericInst and 
+    elif x.kind == tyGenericInst and
           (f.sons[0] == x.sons[0]) and
           (sonsLen(x) - 1 == sonsLen(f)):
       for i in countup(1, sonsLen(f) - 1):
         if x.sons[i].kind == tyGenericParam:
           internalError("wrong instantiated type!")
-        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return 
+        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
       result = isGeneric
     else:
       result = typeRel(c, f.sons[0], x)
@@ -900,7 +900,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
           if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}:
             internalError("wrong instantiated type!")
           put(c.bindings, f.sons[i], x)
-  
+
   of tyAnd:
     considerPreviousT:
       for branch in f.sons:
@@ -914,7 +914,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       for branch in f.sons:
         if typeRel(c, branch, aOrig) >= isSubtype:
           bindingRet isGeneric
-       
+
       return isNone
 
   of tyNot:
@@ -922,7 +922,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       for branch in f.sons:
         if typeRel(c, branch, aOrig) != isNone:
           return isNone
-      
+
       bindingRet isGeneric
 
   of tyAnything:
@@ -961,7 +961,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     if x == nil:
       if c.callee.kind == tyGenericBody and
          f.kind == tyGenericParam and not c.typedescMatched:
-        # XXX: The fact that generic types currently use tyGenericParam for 
+        # XXX: The fact that generic types currently use tyGenericParam for
         # their parameters is really a misnomer. tyGenericParam means "match
         # any value" and what we need is "match any type", which can be encoded
         # by a tyTypeDesc params. Unfortunately, this requires more substantial
@@ -1004,7 +1004,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       result = isGeneric
     else:
       result = typeRel(c, x, a) # check if it fits
-  
+
   of tyStatic:
     let prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
@@ -1034,12 +1034,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       # when `f` is an unresolved typedesc, `a` could be any
       # type, so we should not perform this check earlier
       if a.kind != tyTypeDesc: return isNone
-    
+
       if f.base.kind == tyNone:
         result = isGeneric
       else:
         result = typeRel(c, f.base, a.base)
-      
+
       if result != isNone:
         put(c.bindings, f, a)
     else:
@@ -1049,9 +1049,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         result = typeRel(c, prev.base, a.base)
       else:
         result = isNone
- 
+
   of tyIter:
-    if a.kind == tyIter or 
+    if a.kind == tyIter or
       (a.kind == tyProc and tfIterator in a.flags):
       result = typeRel(c, f.base, a.base)
     else:
@@ -1059,7 +1059,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   of tyStmt:
     result = isGeneric
-  
+
   of tyProxy:
     result = isEqual
 
@@ -1078,11 +1078,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     else:
       localError(f.n.info, errTypeExpected)
       result = isNone
-  
+
   else:
     internalAssert false
-  
-proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = 
+
+proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
   var m: TCandidate
   initCandidate(c, m, f)
   result = typeRel(m, f, a)
@@ -1095,9 +1095,9 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
   if result == nil:
     internalError(arg.info, "getInstantiatedType")
     result = errorType(c)
-  
-proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, 
-                  c: PContext): PNode = 
+
+proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
+                  c: PContext): PNode =
   result = newNodeI(kind, arg.info)
   if containsGenericType(f):
     if not m.hasFauxMatch:
@@ -1110,10 +1110,10 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
   addSon(result, ast.emptyNode)
   addSon(result, arg)
 
-proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, 
-                   arg: PNode): PNode = 
+proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                   arg: PNode): PNode =
   result = nil
-  for i in countup(0, len(c.converters) - 1): 
+  for i in countup(0, len(c.converters) - 1):
     var src = c.converters[i].typ.sons[1]
     var dest = c.converters[i].typ.sons[0]
     # for generic type converters we need to check 'src <- a' before
@@ -1121,12 +1121,12 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
     # see tests/tgenericconverter:
     let srca = typeRel(m, src, a)
     if srca notin {isEqual, isGeneric}: continue
-    
+
     let destIsGeneric = containsGenericType(dest)
     if destIsGeneric:
       dest = generateTypeInstance(c, m.bindings, arg, dest)
     let fdest = typeRel(m, f, dest)
-    if fdest in {isEqual, isGeneric}: 
+    if fdest in {isEqual, isGeneric}:
       markUsed(arg.info, c.converters[i])
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
@@ -1138,8 +1138,8 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       m.genericConverter = srca == isGeneric or destIsGeneric
       return result
 
-proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, 
-                    arg: PNode): PNode = 
+proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                    arg: PNode): PNode =
   # arg.typ can be nil in 'suggest':
   if isNil(arg.typ): return nil
 
@@ -1181,12 +1181,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     arg = argSemantized
     argType = argType
     c = m.c
-  
+
   if tfHasStatic in fMaybeStatic.flags:
     # XXX: When implicit statics are the default
     # this will be done earlier - we just have to
     # make sure that static types enter here
-     
+
     # XXX: weaken tyGenericParam and call it tyGenericPlaceholder
     # and finally start using tyTypedesc for generic types properly.
     if argType.kind == tyGenericParam and tfWildcard in argType.flags:
@@ -1205,11 +1205,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
         arg.typ.sons = @[evaluated.typ]
         arg.typ.n = evaluated
         argType = arg.typ
- 
+
   var
     a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
         else: argType
- 
+
     r = typeRel(m, f, a)
 
   if r != isNone and m.calleeSym != nil and
@@ -1244,19 +1244,18 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
   case r
   of isConvertible:
     inc(m.convMatches)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isIntConv:
     # I'm too lazy to introduce another ``*matches`` field, so we conflate
     # ``isIntConv`` and ``isIntLit`` here:
     inc(m.intConvMatches)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-  of isSubtype: 
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isSubtype:
     inc(m.subtypeMatches)
-    result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
+    result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isSubrange:
     inc(m.subtypeMatches)
-    #result = copyTree(arg)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isInferred, isInferredConvertible:
     inc(m.genericMatches)
     if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
@@ -1269,42 +1268,32 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
       result = implicitConv(nkHiddenStdConv, f, result, m, c)
   of isGeneric:
     inc(m.genericMatches)
-    when true:
-      if arg.typ == nil:
-        result = arg
-      elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
-        result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-      elif arg.typ.isEmptyContainer:
-        result = arg.copyTree
-        result.typ = getInstantiatedType(c, arg, m, f)
-      else:
-        result = arg
-    else:
-      # XXX Why is this ever necessary? arg's type should not be retrofitted
-      # to match formal's type in this way!
-      result = copyTree(arg)
+    if arg.typ == nil:
+      result = arg
+    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
+      result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    elif arg.typ.isEmptyContainer:
+      result = arg.copyTree
       result.typ = getInstantiatedType(c, arg, m, f)
-      # BUG: f may not be the right key!
-      if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
-        result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-        # BUGFIX: use ``result.typ`` and not `f` here
+    else:
+      result = arg
   of isFromIntLit:
     # too lazy to introduce another ``*matches`` field, so we conflate
     # ``isIntConv`` and ``isIntLit`` here:
     inc(m.intConvMatches, 256)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-  of isEqual: 
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isEqual:
     inc(m.exactMatches)
-    result = copyTree(arg)
+    result = arg
     if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
-      result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isNone:
     # do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
     if a.kind in {tyProxy, tyUnknown}:
       inc(m.genericMatches)
       m.fauxMatch = a.kind
-      return copyTree(arg)
-    result = userConvMatch(c, m, f, a, arg) 
+      return arg
+    result = userConvMatch(c, m, f, a, arg)
     # check for a base type match, which supports varargs[T] without []
     # constructor in a call:
     if result == nil and f.kind == tyVarargs:
@@ -1325,7 +1314,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
                       arg, argOrig: PNode): PNode =
   if arg == nil or arg.kind notin nkSymChoices:
     result = paramTypesMatchAux(m, f, a, arg, argOrig)
-  else: 
+  else:
     # CAUTION: The order depends on the used hashing scheme. Thus it is
     # incorrect to simply use the first fitting match. However, to implement
     # this correctly is inefficient. We have to copy `m` here to be able to
@@ -1339,28 +1328,28 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     y.calleeSym = m.calleeSym
     z.calleeSym = m.calleeSym
     var best = -1
-    for i in countup(0, sonsLen(arg) - 1): 
+    for i in countup(0, sonsLen(arg) - 1):
       if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
         copyCandidate(z, m)
         var r = typeRel(z, f, arg.sons[i].typ)
-        if r != isNone: 
+        if r != isNone:
           case x.state
-          of csEmpty, csNoMatch: 
+          of csEmpty, csNoMatch:
             x = z
             best = i
             x.state = csMatch
-          of csMatch: 
+          of csMatch:
             var cmp = cmpCandidates(x, z)
             if cmp < 0:
               best = i
               x = z
             elif cmp == 0:
               y = z           # z is as good as x
-    if x.state == csEmpty: 
+    if x.state == csEmpty:
       result = nil
-    elif y.state == csMatch and cmpCandidates(x, y) == 0: 
-      if x.state != csMatch: 
-        internalError(arg.info, "x.state is not csMatch") 
+    elif y.state == csMatch and cmpCandidates(x, y) == 0:
+      if x.state != csMatch:
+        internalError(arg.info, "x.state is not csMatch")
       # ambiguous: more than one symbol fits!
       # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
       # anyway:
@@ -1373,7 +1362,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
 
-proc setSon(father: PNode, at: int, son: PNode) = 
+proc setSon(father: PNode, at: int, son: PNode) =
   if sonsLen(father) <= at: setLen(father.sons, at + 1)
   father.sons[at] = son
 
@@ -1417,7 +1406,7 @@ proc incrIndexType(t: PType) =
   inc t.sons[0].n.sons[1].intVal
 
 proc matchesAux(c: PContext, n, nOrig: PNode,
-                m: var TCandidate, marker: var IntSet) = 
+                m: var TCandidate, marker: var IntSet) =
   template checkConstraint(n: expr) {.immediate, dirty.} =
     if not formal.constraint.isNil:
       if matchNodeKinds(formal.constraint, n):
@@ -1447,20 +1436,20 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       # named param
       # check if m.callee has such a param:
       prepareNamedParam(n.sons[a])
-      if n.sons[a].sons[0].kind != nkIdent: 
+      if n.sons[a].sons[0].kind != nkIdent:
         localError(n.sons[a].info, errNamedParamHasToBeIdent)
         m.state = csNoMatch
-        return 
+        return
       formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
-      if formal == nil: 
+      if formal == nil:
         # no error message!
         m.state = csNoMatch
-        return 
-      if containsOrIncl(marker, formal.position): 
+        return
+      if containsOrIncl(marker, formal.position):
         # already in namedParams:
         localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
         m.state = csNoMatch
-        return 
+        return
       m.baseTypeMatch = false
       n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
       n.sons[a].typ = n.sons[a].sons[1].typ
@@ -1470,7 +1459,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         m.state = csNoMatch
         return
       checkConstraint(n.sons[a].sons[1])
-      if m.baseTypeMatch: 
+      if m.baseTypeMatch:
         #assert(container == nil)
         container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
         addSon(container, arg)
@@ -1507,7 +1496,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.state = csNoMatch
           return
       else:
-        if m.callee.n.sons[f].kind != nkSym: 
+        if m.callee.n.sons[f].kind != nkSym:
           internalError(n.sons[a].info, "matches")
           return
         formal = m.callee.n.sons[f].sym
@@ -1515,7 +1504,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           # already in namedParams:
           localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
           m.state = csNoMatch
-          return 
+          return
         m.baseTypeMatch = false
         n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
         var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
@@ -1528,7 +1517,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           if container.isNil:
             container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
           addSon(container, arg)
-          setSon(m.call, formal.position + 1, 
+          setSon(m.call, formal.position + 1,
                  implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
           #if f != formalLen - 1: container = nil
 
@@ -1603,7 +1592,7 @@ when not declared(tests):
 
 tests:
   var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
-  
+
   proc `|` (t1, t2: PType): PType =
     result = newType(tyOr, dummyOwner)
     result.rawAddSon(t1)
@@ -1624,12 +1613,12 @@ tests:
 
   proc array(x: int, t: PType): PType =
     result = newType(tyArray, dummyOwner)
-    
+
     var n = newNodeI(nkRange, UnknownLineInfo())
     addSon(n, newIntNode(nkIntLit, 0))
     addSon(n, newIntNode(nkIntLit, x))
     let range = newType(tyRange, dummyOwner)
-    
+
     result.rawAddSon(range)
     result.rawAddSon(t)
 
@@ -1664,7 +1653,7 @@ tests:
     template no(x, y) =
       test astToStr(x) & " is not " & astToStr(y):
         check typeRel(c, y, x) == isNone
-    
+
     yes seq(any), array(10, int) | seq(any)
     # Sure, seq[any] is directly included
 
@@ -1672,16 +1661,16 @@ tests:
     yes seq(int), seq(number)
     # Sure, the int sequence is certainly
     # part of the number sequences (and all sequences)
-    
+
     no seq(any), seq(float)
     # Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
 
     yes seq(int|string), seq(any)
     # Sure
- 
+
     yes seq(int&string), seq(any)
     # Again
-    
+
     yes seq(int&string), seq(int)
     # A bit more complicated
     # seq[int&string] is not a real type, but it's analogous to
@@ -1690,23 +1679,23 @@ tests:
     no seq(int|string), seq(int|float)
     # Nope, seq[string] is not included in not included in
     # the seq[int|float] set
-    
+
     no seq(!(int|string)), seq(string)
     # A sequence that is neither seq[int] or seq[string]
     # is obviously not seq[string]
-     
+
     no seq(!int), seq(number)
     # Now your head should start to hurt a bit
     # A sequence that is not seq[int] is not necessarily a number sequence
     # it could well be seq[string] for example
-    
+
     yes seq(!(int|string)), seq(!string)
     # all sequnece types besides seq[int] and seq[string]
     # are subset of all sequence types that are not seq[string]
 
     no seq(!(int|string)), seq(!(string|TFoo))
     # Nope, seq[TFoo] is included in the first set, but not in the second
-    
+
     no seq(!string), seq(!number)
     # Nope, seq[int] in included in the first set, but not in the second
 
@@ -1714,7 +1703,7 @@ tests:
     yes seq(!int), seq(any)
     no seq(any), seq(!any)
     no seq(!int), seq(!any)
-    
+
     yes int, ordinal
     no  string, ordinal
 
diff --git a/compiler/types.nim b/compiler/types.nim
index 5c3be7553..0cc5a212b 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -9,20 +9,20 @@
 
 # this module contains routines for accessing and iterating over types
 
-import 
+import
   intsets, ast, astalgo, trees, msgs, strutils, platform, renderer
 
 proc firstOrd*(t: PType): BiggestInt
 proc lastOrd*(t: PType): BiggestInt
 proc lengthOrd*(t: PType): BiggestInt
-type 
+type
   TPreferedDesc* = enum
     preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg
 
 proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
 proc base*(t: PType): PType
   # ------------------- type iterator: ----------------------------------------
-type 
+type
   TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop
   TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it
   TTypePredicate* = proc (t: PType): bool {.nimcall.}
@@ -32,7 +32,7 @@ proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool
 proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType
   # Returns result of `iter`.
 
-type 
+type
   TParamsEquality* = enum     # they are equal, but their
                               # identifiers or their return
                               # type differ (i.e. they cannot be
@@ -59,7 +59,7 @@ const
   abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal,
                    tyTypeDesc}
 
-  skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, 
+  skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
                tyTypeDesc}
   typedescPtrs* = abstractPtrs + {tyTypeDesc}
   typedescInst* = abstractInst + {tyTypeDesc}
@@ -75,9 +75,9 @@ proc getSize*(typ: PType): BiggestInt
 proc isPureObject*(typ: PType): bool
 proc invalidGenericInst*(f: PType): bool
   # for debugging
-type 
-  TTypeFieldResult* = enum 
-    frNone,                   # type has no object type field 
+type
+  TTypeFieldResult* = enum
+    frNone,                   # type has no object type field
     frHeader,                 # type has an object type field only in the header
     frEmbedded                # type has an object type field somewhere embedded
 
@@ -86,15 +86,15 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
   # made or intializing of the type field suffices or if there is no type field
   # at all in this type.
 
-proc invalidGenericInst(f: PType): bool = 
+proc invalidGenericInst(f: PType): bool =
   result = f.kind == tyGenericInst and lastSon(f) == nil
 
-proc isPureObject(typ: PType): bool = 
+proc isPureObject(typ: PType): bool =
   var t = typ
   while t.kind == tyObject and t.sons[0] != nil: t = t.sons[0]
   result = t.sym != nil and sfPure in t.sym.flags
 
-proc getOrdValue(n: PNode): BiggestInt = 
+proc getOrdValue(n: PNode): BiggestInt =
   case n.kind
   of nkCharLit..nkUInt64Lit: result = n.intVal
   of nkNilLit: result = 0
@@ -109,21 +109,21 @@ proc isIntLit*(t: PType): bool {.inline.} =
 proc isFloatLit*(t: PType): bool {.inline.} =
   result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit
 
-proc isCompatibleToCString(a: PType): bool = 
-  if a.kind == tyArray: 
+proc isCompatibleToCString(a: PType): bool =
+  if a.kind == tyArray:
     if (firstOrd(a.sons[0]) == 0) and
-        (skipTypes(a.sons[0], {tyRange, tyConst, 
-                               tyMutable, tyGenericInst}).kind in 
+        (skipTypes(a.sons[0], {tyRange, tyConst,
+                               tyMutable, tyGenericInst}).kind in
             {tyInt..tyInt64, tyUInt..tyUInt64}) and
-        (a.sons[1].kind == tyChar): 
+        (a.sons[1].kind == tyChar):
       result = true
-  
-proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = 
+
+proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   result = sym.owner.name.s & '.' & sym.name.s & '('
   var n = sym.typ.n
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var p = n.sons[i]
-    if p.kind == nkSym: 
+    if p.kind == nkSym:
       add(result, p.sym.name.s)
       add(result, ": ")
       add(result, typeToString(p.sym.typ, prefer))
@@ -134,7 +134,7 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   if n.sons[0].typ != nil:
     result.add(": " & typeToString(n.sons[0].typ, prefer))
 
-proc elemType*(t: PType): PType = 
+proc elemType*(t: PType): PType =
   assert(t != nil)
   case t.kind
   of tyGenericInst, tyDistinct: result = elemType(lastSon(t))
@@ -142,10 +142,10 @@ proc elemType*(t: PType): PType =
   else: result = t.lastSon
   assert(result != nil)
 
-proc skipGeneric(t: PType): PType = 
+proc skipGeneric(t: PType): PType =
   result = t
   while result.kind == tyGenericInst: result = lastSon(result)
-      
+
 proc isOrdinalType(t: PType): bool =
   assert(t != nil)
   # caution: uint, uint64 are no ordinal types!
@@ -153,134 +153,134 @@ proc isOrdinalType(t: PType): bool =
       (t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
        isOrdinalType(t.sons[0])
 
-proc enumHasHoles(t: PType): bool = 
+proc enumHasHoles(t: PType): bool =
   var b = t
   while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0]
   result = b.kind == tyEnum and tfEnumHasHoles in b.flags
 
-proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, 
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
                      closure: RootRef): bool
-proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, 
-                  closure: RootRef): bool = 
-  if n != nil: 
+proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter,
+                  closure: RootRef): bool =
+  if n != nil:
     case n.kind
-    of nkNone..nkNilLit: 
+    of nkNone..nkNilLit:
       # a leaf
       result = iterOverTypeAux(marker, n.typ, iter, closure)
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         result = iterOverNode(marker, n.sons[i], iter, closure)
-        if result: return 
-  
-proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, 
-                     closure: RootRef): bool = 
+        if result: return
+
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
+                     closure: RootRef): bool =
   result = false
-  if t == nil: return 
+  if t == nil: return
   result = iter(t, closure)
-  if result: return 
-  if not containsOrIncl(marker, t.id): 
+  if result: return
+  if not containsOrIncl(marker, t.id):
     case t.kind
-    of tyGenericInst, tyGenericBody: 
+    of tyGenericInst, tyGenericBody:
       result = iterOverTypeAux(marker, lastSon(t), iter, closure)
-    else: 
-      for i in countup(0, sonsLen(t) - 1): 
+    else:
+      for i in countup(0, sonsLen(t) - 1):
         result = iterOverTypeAux(marker, t.sons[i], iter, closure)
-        if result: return 
+        if result: return
       if t.n != nil: result = iterOverNode(marker, t.n, iter, closure)
-  
-proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = 
+
+proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool =
   var marker = initIntSet()
   result = iterOverTypeAux(marker, t, iter, closure)
 
-proc searchTypeForAux(t: PType, predicate: TTypePredicate, 
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
                       marker: var IntSet): bool
 
-proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, 
-                          marker: var IntSet): bool = 
+proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
+                          marker: var IntSet): bool =
   result = false
   case n.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
       result = searchTypeNodeForAux(n.sons[i], p, marker)
-      if result: return 
-  of nkRecCase: 
+      if result: return
+  of nkRecCase:
     assert(n.sons[0].kind == nkSym)
     result = searchTypeNodeForAux(n.sons[0], p, marker)
-    if result: return 
-    for i in countup(1, sonsLen(n) - 1): 
+    if result: return
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
-        if result: return 
+        if result: return
       else: internalError("searchTypeNodeForAux(record case branch)")
-  of nkSym: 
+  of nkSym:
     result = searchTypeForAux(n.sym.typ, p, marker)
   else: internalError(n.info, "searchTypeNodeForAux()")
-  
-proc searchTypeForAux(t: PType, predicate: TTypePredicate, 
-                      marker: var IntSet): bool = 
+
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
+                      marker: var IntSet): bool =
   # iterates over VALUE types!
   result = false
-  if t == nil: return 
-  if containsOrIncl(marker, t.id): return 
+  if t == nil: return
+  if containsOrIncl(marker, t.id): return
   result = predicate(t)
-  if result: return 
+  if result: return
   case t.kind
-  of tyObject: 
+  of tyObject:
     result = searchTypeForAux(t.sons[0], predicate, marker)
     if not result: result = searchTypeNodeForAux(t.n, predicate, marker)
-  of tyGenericInst, tyDistinct: 
+  of tyGenericInst, tyDistinct:
     result = searchTypeForAux(lastSon(t), predicate, marker)
-  of tyArray, tyArrayConstr, tySet, tyTuple: 
-    for i in countup(0, sonsLen(t) - 1): 
+  of tyArray, tyArrayConstr, tySet, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
       result = searchTypeForAux(t.sons[i], predicate, marker)
-      if result: return 
-  else: 
+      if result: return
+  else:
     discard
 
-proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = 
+proc searchTypeFor(t: PType, predicate: TTypePredicate): bool =
   var marker = initIntSet()
   result = searchTypeForAux(t, predicate, marker)
 
-proc isObjectPredicate(t: PType): bool = 
+proc isObjectPredicate(t: PType): bool =
   result = t.kind == tyObject
 
-proc containsObject(t: PType): bool = 
+proc containsObject(t: PType): bool =
   result = searchTypeFor(t, isObjectPredicate)
 
-proc isObjectWithTypeFieldPredicate(t: PType): bool = 
+proc isObjectWithTypeFieldPredicate(t: PType): bool =
   result = t.kind == tyObject and t.sons[0] == nil and
       not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
       tfFinal notin t.flags
 
-proc analyseObjectWithTypeFieldAux(t: PType, 
-                                   marker: var IntSet): TTypeFieldResult = 
+proc analyseObjectWithTypeFieldAux(t: PType,
+                                   marker: var IntSet): TTypeFieldResult =
   var res: TTypeFieldResult
   result = frNone
-  if t == nil: return 
+  if t == nil: return
   case t.kind
-  of tyObject: 
-    if (t.n != nil): 
-      if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): 
+  of tyObject:
+    if (t.n != nil):
+      if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
         return frEmbedded
-    for i in countup(0, sonsLen(t) - 1): 
+    for i in countup(0, sonsLen(t) - 1):
       res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
-      if res == frEmbedded: 
+      if res == frEmbedded:
         return frEmbedded
       if res == frHeader: result = frHeader
-    if result == frNone: 
+    if result == frNone:
       if isObjectWithTypeFieldPredicate(t): result = frHeader
-  of tyGenericInst, tyDistinct, tyConst, tyMutable: 
+  of tyGenericInst, tyDistinct, tyConst, tyMutable:
     result = analyseObjectWithTypeFieldAux(lastSon(t), marker)
-  of tyArray, tyArrayConstr, tyTuple: 
-    for i in countup(0, sonsLen(t) - 1): 
+  of tyArray, tyArrayConstr, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
       res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
-      if res != frNone: 
+      if res != frNone:
         return frEmbedded
-  else: 
+  else:
     discard
 
-proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = 
+proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
   var marker = initIntSet()
   result = analyseObjectWithTypeFieldAux(t, marker)
 
@@ -288,7 +288,7 @@ proc isGCRef(t: PType): bool =
   result = t.kind in GcTypeKinds or
     (t.kind == tyProc and t.callConv == ccClosure)
 
-proc containsGarbageCollectedRef(typ: PType): bool = 
+proc containsGarbageCollectedRef(typ: PType): bool =
   # returns true if typ contains a reference, sequence or string (all the
   # things that are garbage-collected)
   result = searchTypeFor(typ, isGCRef)
@@ -296,47 +296,47 @@ proc containsGarbageCollectedRef(typ: PType): bool =
 proc isTyRef(t: PType): bool =
   result = t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure)
 
-proc containsTyRef*(typ: PType): bool = 
+proc containsTyRef*(typ: PType): bool =
   # returns true if typ contains a 'ref'
   result = searchTypeFor(typ, isTyRef)
 
-proc isHiddenPointer(t: PType): bool = 
+proc isHiddenPointer(t: PType): bool =
   result = t.kind in {tyString, tySequence}
 
-proc containsHiddenPointer(typ: PType): bool = 
+proc containsHiddenPointer(typ: PType): bool =
   # returns true if typ contains a string, table or sequence (all the things
   # that need to be copied deeply)
   result = searchTypeFor(typ, isHiddenPointer)
 
 proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool
-proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = 
+proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool =
   result = false
-  if n != nil: 
+  if n != nil:
     result = canFormAcycleAux(marker, n.typ, startId)
-    if not result: 
+    if not result:
       case n.kind
-      of nkNone..nkNilLit: 
+      of nkNone..nkNilLit:
         discard
-      else: 
-        for i in countup(0, sonsLen(n) - 1): 
+      else:
+        for i in countup(0, sonsLen(n) - 1):
           result = canFormAcycleNode(marker, n.sons[i], startId)
-          if result: return 
-  
-proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = 
+          if result: return
+
+proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
   result = false
-  if typ == nil: return 
-  if tfAcyclic in typ.flags: return 
+  if typ == nil: return
+  if tfAcyclic in typ.flags: return
   var t = skipTypes(typ, abstractInst-{tyTypeDesc})
-  if tfAcyclic in t.flags: return 
+  if tfAcyclic in t.flags: return
   case t.kind
   of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray,
      tyVarargs:
-    if not containsOrIncl(marker, t.id): 
-      for i in countup(0, sonsLen(t) - 1): 
+    if not containsOrIncl(marker, t.id):
+      for i in countup(0, sonsLen(t) - 1):
         result = canFormAcycleAux(marker, t.sons[i], startId)
-        if result: return 
+        if result: return
       if t.n != nil: result = canFormAcycleNode(marker, t.n, startId)
-    else: 
+    else:
       result = t.id == startId
     # Inheritance can introduce cyclic types, however this is not relevant
     # as the type that is passed to 'new' is statically known!
@@ -351,29 +351,29 @@ proc canFormAcycle(typ: PType): bool =
   var marker = initIntSet()
   result = canFormAcycleAux(marker, typ, typ.id)
 
-proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, 
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
                    closure: RootRef): PType
-proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, 
-                closure: RootRef): PNode = 
+proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator,
+                closure: RootRef): PNode =
   result = nil
-  if n != nil: 
+  if n != nil:
     result = copyNode(n)
     result.typ = mutateTypeAux(marker, n.typ, iter, closure)
     case n.kind
-    of nkNone..nkNilLit: 
+    of nkNone..nkNilLit:
       # a leaf
       discard
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         addSon(result, mutateNode(marker, n.sons[i], iter, closure))
-  
-proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, 
-                   closure: RootRef): PType = 
+
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
+                   closure: RootRef): PType =
   result = nil
-  if t == nil: return 
+  if t == nil: return
   result = iter(t, closure)
-  if not containsOrIncl(marker, t.id): 
-    for i in countup(0, sonsLen(t) - 1): 
+  if not containsOrIncl(marker, t.id):
+    for i in countup(0, sonsLen(t) - 1):
       result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
     if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure)
   assert(result != nil)
@@ -393,7 +393,7 @@ proc rangeToStr(n: PNode): string =
   assert(n.kind == nkRange)
   result = valueToString(n.sons[0]) & ".." & valueToString(n.sons[1])
 
-const 
+const
   typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
     "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
     "GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
@@ -414,7 +414,7 @@ const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
 proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   var t = typ
   result = ""
-  if t == nil: return 
+  if t == nil: return
   if prefer in preferToResolveSymbols and t.sym != nil and
        sfAnon notin t.sym.flags:
     if t.kind == tyInt and isIntLit(t):
@@ -484,47 +484,47 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     result = "expr"
   of tyFromExpr, tyFieldAccessor:
     result = renderTree(t.n)
-  of tyArray: 
-    if t.sons[0].kind == tyRange: 
+  of tyArray:
+    if t.sons[0].kind == tyRange:
       result = "array[" & rangeToStr(t.sons[0].n) & ", " &
           typeToString(t.sons[1]) & ']'
-    else: 
+    else:
       result = "array[" & typeToString(t.sons[0]) & ", " &
           typeToString(t.sons[1]) & ']'
-  of tyArrayConstr: 
+  of tyArrayConstr:
     result = "Array constructor[" & rangeToStr(t.sons[0].n) & ", " &
         typeToString(t.sons[1]) & ']'
-  of tySequence: 
+  of tySequence:
     result = "seq[" & typeToString(t.sons[0]) & ']'
-  of tyOrdinal: 
+  of tyOrdinal:
     result = "ordinal[" & typeToString(t.sons[0]) & ']'
-  of tySet: 
+  of tySet:
     result = "set[" & typeToString(t.sons[0]) & ']'
-  of tyOpenArray: 
+  of tyOpenArray:
     result = "openarray[" & typeToString(t.sons[0]) & ']'
   of tyDistinct:
     result = "distinct " & typeToString(t.sons[0],
       if prefer == preferModuleInfo: preferModuleInfo else: preferName)
-  of tyTuple: 
+  of tyTuple:
     # we iterate over t.sons here, because t.n may be nil
     result = "tuple["
-    if t.n != nil: 
+    if t.n != nil:
       assert(sonsLen(t.n) == sonsLen(t))
-      for i in countup(0, sonsLen(t.n) - 1): 
+      for i in countup(0, sonsLen(t.n) - 1):
         assert(t.n.sons[i].kind == nkSym)
         add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
         if i < sonsLen(t.n) - 1: add(result, ", ")
-    else: 
-      for i in countup(0, sonsLen(t) - 1): 
+    else:
+      for i in countup(0, sonsLen(t) - 1):
         add(result, typeToString(t.sons[i]))
         if i < sonsLen(t) - 1: add(result, ", ")
     add(result, ']')
-  of tyPtr, tyRef, tyVar, tyMutable, tyConst: 
+  of tyPtr, tyRef, tyVar, tyMutable, tyConst:
     result = typeToStr[t.kind]
     if t.len >= 2:
       setLen(result, result.len-1)
       result.add '['
-      for i in countup(0, sonsLen(t) - 1): 
+      for i in countup(0, sonsLen(t) - 1):
         add(result, typeToString(t.sons[i]))
         if i < sonsLen(t) - 1: add(result, ", ")
       result.add ']'
@@ -536,7 +536,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       result.add("(" & typeToString(t.sons[0]) & ")")
   of tyProc:
     result = if tfIterator in t.flags: "iterator (" else: "proc ("
-    for i in countup(1, sonsLen(t) - 1): 
+    for i in countup(1, sonsLen(t) - 1):
       add(result, typeToString(t.sons[i]))
       if i < sonsLen(t) - 1: add(result, ", ")
     add(result, ')')
@@ -554,29 +554,29 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if len(prag) != 0: add(result, "{." & prag & ".}")
   of tyVarargs, tyIter:
     result = typeToStr[t.kind] % typeToString(t.sons[0])
-  else: 
+  else:
     result = typeToStr[t.kind]
   if tfShared in t.flags: result = "shared " & result
   if tfNotNil in t.flags: result.add(" not nil")
 
-proc resultType(t: PType): PType = 
+proc resultType(t: PType): PType =
   assert(t.kind == tyProc)
   result = t.sons[0]          # nil is allowed
-  
-proc base(t: PType): PType = 
+
+proc base(t: PType): PType =
   result = t.sons[0]
 
-proc firstOrd(t: PType): BiggestInt = 
+proc firstOrd(t: PType): BiggestInt =
   case t.kind
   of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
     result = 0
   of tySet, tyVar: result = firstOrd(t.sons[0])
   of tyArray, tyArrayConstr: result = firstOrd(t.sons[0])
-  of tyRange: 
+  of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[0])
-  of tyInt: 
+  of tyInt:
     if platform.intSize == 4: result = - (2147483646) - 2
     else: result = 0x8000000000000000'i64
   of tyInt8: result = - 128
@@ -584,11 +584,11 @@ proc firstOrd(t: PType): BiggestInt =
   of tyInt32: result = - 2147483646 - 2
   of tyInt64: result = 0x8000000000000000'i64
   of tyUInt..tyUInt64: result = 0
-  of tyEnum: 
+  of tyEnum:
     # if basetype <> nil then return firstOrd of basetype
-    if (sonsLen(t) > 0) and (t.sons[0] != nil): 
+    if (sonsLen(t) > 0) and (t.sons[0] != nil):
       result = firstOrd(t.sons[0])
-    else: 
+    else:
       assert(t.n.sons[0].kind == nkSym)
       result = t.n.sons[0].sym.position
   of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor:
@@ -600,31 +600,31 @@ proc firstOrd(t: PType): BiggestInt =
     internalError("invalid kind for first(" & $t.kind & ')')
     result = 0
 
-proc lastOrd(t: PType): BiggestInt = 
+proc lastOrd(t: PType): BiggestInt =
   case t.kind
   of tyBool: result = 1
   of tyChar: result = 255
   of tySet, tyVar: result = lastOrd(t.sons[0])
   of tyArray, tyArrayConstr: result = lastOrd(t.sons[0])
-  of tyRange: 
+  of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[1])
-  of tyInt: 
+  of tyInt:
     if platform.intSize == 4: result = 0x7FFFFFFF
     else: result = 0x7FFFFFFFFFFFFFFF'i64
   of tyInt8: result = 0x0000007F
   of tyInt16: result = 0x00007FFF
   of tyInt32: result = 0x7FFFFFFF
   of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyUInt: 
+  of tyUInt:
     if platform.intSize == 4: result = 0xFFFFFFFF
     else: result = 0x7FFFFFFFFFFFFFFF'i64
   of tyUInt8: result = 0xFF
   of tyUInt16: result = 0xFFFF
   of tyUInt32: result = 0xFFFFFFFF
   of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyEnum: 
+  of tyEnum:
     assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
     result = t.n.sons[sonsLen(t.n) - 1].sym.position
   of tyGenericInst, tyDistinct, tyConst, tyMutable,
@@ -638,7 +638,7 @@ proc lastOrd(t: PType): BiggestInt =
     internalError("invalid kind for last(" & $t.kind & ')')
     result = 0
 
-proc lengthOrd(t: PType): BiggestInt = 
+proc lengthOrd(t: PType): BiggestInt =
   case t.kind
   of tyInt64, tyInt32, tyInt: result = lastOrd(t)
   of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
@@ -654,7 +654,7 @@ type
     dcEqOrDistinctOf       ## a equals b or a is distinct of b
 
   TTypeCmpFlag* = enum
-    IgnoreTupleFields
+    IgnoreTupleFields      ## NOTE: Only set this flag for backends!
     IgnoreCC
     ExactTypeDescValues
     ExactGenericParams
@@ -673,7 +673,7 @@ type
 proc initSameTypeClosure: TSameTypeClosure =
   # we do the initialization lazily for performance (avoids memory allocations)
   discard
-  
+
 proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
   result = not isNil(c.s) and c.s.contains((a.id, b.id))
   if not result:
@@ -700,17 +700,17 @@ proc sameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
     if a == nil or b == nil: result = false
     else: result = sameType(a, b, flags)
 
-proc equalParam(a, b: PSym): TParamsEquality = 
+proc equalParam(a, b: PSym): TParamsEquality =
   if sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and
       exprStructuralEquivalent(a.constraint, b.constraint):
-    if a.ast == b.ast: 
+    if a.ast == b.ast:
       result = paramsEqual
-    elif a.ast != nil and b.ast != nil: 
+    elif a.ast != nil and b.ast != nil:
       if exprStructuralEquivalent(a.ast, b.ast): result = paramsEqual
       else: result = paramsIncompatible
-    elif a.ast != nil: 
+    elif a.ast != nil:
       result = paramsEqual
-    elif b.ast != nil: 
+    elif b.ast != nil:
       result = paramsIncompatible
   else:
     result = paramsNotEqual
@@ -723,70 +723,70 @@ proc sameConstraints(a, b: PNode): bool =
       return false
   return true
 
-proc equalParams(a, b: PNode): TParamsEquality = 
+proc equalParams(a, b: PNode): TParamsEquality =
   result = paramsEqual
   var length = sonsLen(a)
-  if length != sonsLen(b): 
+  if length != sonsLen(b):
     result = paramsNotEqual
-  else: 
-    for i in countup(1, length - 1): 
+  else:
+    for i in countup(1, length - 1):
       var m = a.sons[i].sym
       var n = b.sons[i].sym
       assert((m.kind == skParam) and (n.kind == skParam))
       case equalParam(m, n)
-      of paramsNotEqual: 
+      of paramsNotEqual:
         return paramsNotEqual
-      of paramsEqual: 
+      of paramsEqual:
         discard
-      of paramsIncompatible: 
+      of paramsIncompatible:
         result = paramsIncompatible
-      if (m.name.id != n.name.id): 
+      if (m.name.id != n.name.id):
         # BUGFIX
         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 (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
         result = paramsNotEqual # one proc has a result, the other not is OK
-      else: 
+      else:
         result = paramsIncompatible # overloading by different
                                     # result types does not work
-  
-proc sameLiteral(x, y: PNode): bool = 
-  if x.kind == y.kind: 
+
+proc sameLiteral(x, y: PNode): bool =
+  if x.kind == y.kind:
     case x.kind
     of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal
     of nkFloatLit..nkFloat64Lit: result = x.floatVal == y.floatVal
     of nkNilLit: result = true
     else: assert(false)
-  
-proc sameRanges(a, b: PNode): bool = 
+
+proc sameRanges(a, b: PNode): bool =
   result = sameLiteral(a.sons[0], b.sons[0]) and
            sameLiteral(a.sons[1], b.sons[1])
 
-proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = 
+proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
   # two tuples are equivalent iff the names, types and positions are the same;
   # however, both types may not have any field names (t.n may be nil) which
   # complicates the matter a bit.
   if sonsLen(a) == sonsLen(b):
     result = true
-    for i in countup(0, sonsLen(a) - 1): 
+    for i in countup(0, sonsLen(a) - 1):
       var x = a.sons[i]
       var y = b.sons[i]
       if IgnoreTupleFields in c.flags:
-        x = skipTypes(x, {tyRange})
-        y = skipTypes(y, {tyRange})
-      
+        x = skipTypes(x, {tyRange, tyGenericInst})
+        y = skipTypes(y, {tyRange, tyGenericInst})
+
       result = sameTypeAux(x, y, c)
-      if not result: return 
+      if not result: return
     if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags:
-      for i in countup(0, sonsLen(a.n) - 1): 
-        # check field names: 
+      for i in countup(0, sonsLen(a.n) - 1):
+        # check field names:
         if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym:
           var x = a.n.sons[i].sym
           var y = b.n.sons[i].sym
           result = x.name.id == y.name.id
-          if not result: break 
+          if not result: break
         else: internalError(a.n.info, "sameTuple")
 
 template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
@@ -797,7 +797,7 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
     # expensive structural equality test; however due to the way generic and
     # objects work, if one of the types does **not** contain tfFromGeneric,
     # they cannot be equal. The check ``a.sym.id == b.sym.id`` checks
-    # for the same origin and is essential because we don't want "pure" 
+    # for the same origin and is essential because we don't want "pure"
     # structural type equivalence:
     #
     # type
@@ -835,9 +835,9 @@ proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
       of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
       of nkEmpty, nkNilLit, nkType: result = true
       else:
-        if sonsLen(a) == sonsLen(b): 
-          for i in countup(0, sonsLen(a) - 1): 
-            if not sameObjectTree(a.sons[i], b.sons[i], c): return 
+        if sonsLen(a) == sonsLen(b):
+          for i in countup(0, sonsLen(a) - 1):
+            if not sameObjectTree(a.sons[i], b.sons[i], c): return
           result = true
 
 proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
@@ -853,7 +853,7 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
   result = true
   for i in countup(0, sonsLen(a) - 1):
     result = sameTypeOrNilAux(a.sons[i], b.sons[i], c)
-    if not result: return 
+    if not result: return
 
 proc isGenericAlias*(t: PType): bool =
   return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst
@@ -866,7 +866,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     # believe it or not, the direct check for ``containsOrIncl(c, a, b)``
     # increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat
     # again: Since the recursion check is only to not get caught in an endless
-    # recursion, we use a counter and only if it's value is over some 
+    # recursion, we use a counter and only if it's value is over some
     # threshold we perform the expensive exact cycle check:
     if c.recCheck < 3:
       inc c.recCheck
@@ -874,11 +874,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       if containsOrIncl(c, a, b): return true
 
   proc sameFlags(a, b: PType): bool {.inline.} =
-    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags   
+    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
 
   if x == y: return true
   var a = skipTypes(x, {tyGenericInst})
-  var b = skipTypes(y, {tyGenericInst})  
+  var b = skipTypes(y, {tyGenericInst})
   assert(a != nil)
   assert(b != nil)
   if a.kind != b.kind:
@@ -891,7 +891,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     of dcEqOrDistinctOf:
       while a.kind == tyDistinct: a = a.sons[0]
       if a.kind != b.kind: return false
-  
+
   if x.kind == tyGenericInst:
     let
       lhs = x.skipGenericAlias
@@ -916,11 +916,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       result = sameObjectStructures(a, b, c) and sameFlags(a, b)
   of tyDistinct:
     cycleCheck()
-    if c.cmp == dcEq:      
+    if c.cmp == dcEq:
       if sameFlags(a, b):
         ifFastObjectTypeCheckFailed(a, b):
-          result = sameTypeAux(a.sons[0], b.sons[0], c)     
-    else: 
+          result = sameTypeAux(a.sons[0], b.sons[0], c)
+    else:
       result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
   of tyEnum, tyForward:
     # XXX generic enums do not make much sense, but require structural checking
@@ -957,13 +957,13 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
         sameValue(a.n.sons[0], b.n.sons[0]) and
         sameValue(a.n.sons[1], b.n.sons[1])
   of tyGenericInst: discard
-  of tyNone: result = false  
+  of tyNone: result = false
 
 proc sameBackendType*(x, y: PType): bool =
   var c = initSameTypeClosure()
   c.flags.incl IgnoreTupleFields
   result = sameTypeAux(x, y, c)
-  
+
 proc compareTypes*(x, y: PType,
                    cmp: TDistinctCompare = dcEq,
                    flags: TTypeCmpFlags = {}): bool =
@@ -972,8 +972,8 @@ proc compareTypes*(x, y: PType,
   c.cmp = cmp
   c.flags = flags
   result = sameTypeAux(x, y, c)
-  
-proc inheritanceDiff*(a, b: PType): int = 
+
+proc inheritanceDiff*(a, b: PType): int =
   # | returns: 0 iff `a` == `b`
   # | returns: -x iff `a` is the x'th direct superclass of `b`
   # | returns: +x iff `a` is the x'th direct subclass of `b`
@@ -985,14 +985,14 @@ proc inheritanceDiff*(a, b: PType): int =
   result = 0
   while x != nil:
     x = skipTypes(x, skipPtrs)
-    if sameObjectTypes(x, b): return 
+    if sameObjectTypes(x, b): return
     x = x.sons[0]
     dec(result)
   var y = b
   result = 0
   while y != nil:
     y = skipTypes(y, skipPtrs)
-    if sameObjectTypes(y, a): return 
+    if sameObjectTypes(y, a): return
     y = y.sons[0]
     inc(result)
   result = high(int)
@@ -1066,7 +1066,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     if kind == skConst: return t
     var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
     case t2.kind
-    of tyVar: 
+    of tyVar:
       if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
     of tyOpenArray:
       if kind != skParam: result = t
@@ -1075,9 +1075,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
       if kind notin {skParam, skResult}: result = t
       else: result = typeAllowedAux(marker, t2, kind, flags)
   of tyProc:
-    for i in countup(1, sonsLen(t) - 1): 
+    for i in countup(1, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], skParam, flags)
-      if result != nil: break 
+      if result != nil: break
     if result.isNil and t.sons[0] != nil:
       result = typeAllowedAux(marker, t.sons[0], skResult, flags)
   of tyExpr, tyStmt, tyTypeDesc, tyStatic:
@@ -1092,7 +1092,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     result = t
   of tyNil:
     if kind != skConst: result = t
-  of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: 
+  of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
     result = nil
   of tyOrdinal:
     if kind != skParam: result = t
@@ -1132,13 +1132,13 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     # prevent cascading errors:
     result = nil
 
-proc typeAllowed*(t: PType, kind: TSymKind): PType = 
+proc typeAllowed*(t: PType, kind: TSymKind): PType =
   # returns 'nil' on success and otherwise the part of the type that is
   # wrong!
   var marker = initIntSet()
   result = typeAllowedAux(marker, t, kind, {})
 
-proc align(address, alignment: BiggestInt): BiggestInt = 
+proc align(address, alignment: BiggestInt): BiggestInt =
   result = (address + (alignment - 1)) and not (alignment - 1)
 
 const
@@ -1147,17 +1147,17 @@ const
   szUnknownSize* = -1
 
 proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt
-proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = 
+proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
   var maxAlign, maxSize, b, res: BiggestInt
   case n.kind
-  of nkRecCase: 
+  of nkRecCase:
     assert(n.sons[0].kind == nkSym)
     result = computeRecSizeAux(n.sons[0], a, currOffset)
     maxSize = 0
     maxAlign = 1
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         res = computeRecSizeAux(lastSon(n.sons[i]), b, currOffset)
         if res < 0: return res
         maxSize = max(maxSize, res)
@@ -1166,17 +1166,17 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
     currOffset = align(currOffset, maxAlign) + maxSize
     result = align(result, maxAlign) + maxSize
     a = maxAlign
-  of nkRecList: 
+  of nkRecList:
     result = 0
     maxAlign = 1
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       res = computeRecSizeAux(n.sons[i], b, currOffset)
       if res < 0: return res
       currOffset = align(currOffset, b) + res
       result = align(result, b) + res
       if b > maxAlign: maxAlign = b
     a = maxAlign
-  of nkSym: 
+  of nkSym:
     result = computeSizeAux(n.sym.typ, a)
     n.sym.offset = int(currOffset)
   else:
@@ -1193,31 +1193,31 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     # size already computed
     result = typ.size
     a = typ.align
-    return 
+    return
   typ.size = szIllegalRecursion # mark as being computed
   case typ.kind
-  of tyInt, tyUInt: 
+  of tyInt, tyUInt:
     result = intSize
     a = result
-  of tyInt8, tyUInt8, tyBool, tyChar: 
+  of tyInt8, tyUInt8, tyBool, tyChar:
     result = 1
     a = result
-  of tyInt16, tyUInt16: 
+  of tyInt16, tyUInt16:
     result = 2
     a = result
-  of tyInt32, tyUInt32, tyFloat32: 
+  of tyInt32, tyUInt32, tyFloat32:
     result = 4
     a = result
-  of tyInt64, tyUInt64, tyFloat64: 
+  of tyInt64, tyUInt64, tyFloat64:
     result = 8
     a = result
   of tyFloat128:
     result = 16
     a = result
-  of tyFloat: 
+  of tyFloat:
     result = floatSize
     a = result
-  of tyProc: 
+  of tyProc:
     if typ.callConv == ccClosure: result = 2 * ptrSize
     else: result = ptrSize
     a = ptrSize
@@ -1232,17 +1232,17 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     let elemSize = computeSizeAux(typ.sons[1], a)
     if elemSize < 0: return elemSize
     result = lengthOrd(typ.sons[0]) * elemSize
-  of tyEnum: 
-    if firstOrd(typ) < 0: 
+  of tyEnum:
+    if firstOrd(typ) < 0:
       result = 4              # use signed int32
-    else: 
+    else:
       length = lastOrd(typ)   # BUGFIX: use lastOrd!
       if length + 1 < `shl`(1, 8): result = 1
       elif length + 1 < `shl`(1, 16): result = 2
       elif length + 1 < `shl`(BiggestInt(1), 32): result = 4
       else: result = 8
     a = result
-  of tySet: 
+  of tySet:
     length = lengthOrd(typ.sons[0])
     if length <= 8: result = 1
     elif length <= 16: result = 2
@@ -1251,32 +1251,32 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     elif align(length, 8) mod 8 == 0: result = align(length, 8) div 8
     else: result = align(length, 8) div 8 + 1
     a = result
-  of tyRange: 
+  of tyRange:
     result = computeSizeAux(typ.sons[0], a)
-  of tyTuple: 
+  of tyTuple:
     result = 0
     maxAlign = 1
-    for i in countup(0, sonsLen(typ) - 1): 
+    for i in countup(0, sonsLen(typ) - 1):
       res = computeSizeAux(typ.sons[i], a)
       if res < 0: return res
       maxAlign = max(maxAlign, a)
       result = align(result, a) + res
     result = align(result, maxAlign)
     a = maxAlign
-  of tyObject: 
-    if typ.sons[0] != nil: 
+  of tyObject:
+    if typ.sons[0] != nil:
       result = computeSizeAux(typ.sons[0], a)
-      if result < 0: return 
+      if result < 0: return
       maxAlign = a
-    elif isObjectWithTypeFieldPredicate(typ): 
+    elif isObjectWithTypeFieldPredicate(typ):
       result = intSize
       maxAlign = result
-    else: 
+    else:
       result = 0
       maxAlign = 1
     currOffset = result
     result = computeRecSizeAux(typ.n, a, currOffset)
-    if result < 0: return 
+    if result < 0: return
     if a < maxAlign: a = maxAlign
     result = align(result, a)
   of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
@@ -1290,7 +1290,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
   typ.size = result
   typ.align = int16(a)
 
-proc computeSize(typ: PType): BiggestInt = 
+proc computeSize(typ: PType): BiggestInt =
   var a: BiggestInt = 1
   result = computeSizeAux(typ, a)
 
@@ -1299,7 +1299,7 @@ proc getReturnType*(s: PSym): PType =
   assert s.kind in skProcKinds
   result = s.typ.sons[0]
 
-proc getSize(typ: PType): BiggestInt = 
+proc getSize(typ: PType): BiggestInt =
   result = computeSize(typ)
   if result < 0: internalError("getSize: " & $typ.kind)
 
@@ -1317,7 +1317,7 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
 
   return false
 
-proc containsGenericType*(t: PType): bool = 
+proc containsGenericType*(t: PType): bool =
   result = iterOverType(t, containsGenericTypeIter, nil)
 
 proc baseOfDistinct*(t: PType): PType =
@@ -1336,7 +1336,7 @@ proc baseOfDistinct*(t: PType): PType =
 
 proc safeInheritanceDiff*(a, b: PType): int =
   # same as inheritanceDiff but checks for tyError:
-  if a.kind == tyError or b.kind == tyError: 
+  if a.kind == tyError or b.kind == tyError:
     result = -1
   else:
     result = inheritanceDiff(a, b)
@@ -1356,7 +1356,7 @@ proc compatibleEffects*(formal, actual: PType): bool =
   assert formal.kind == tyProc and actual.kind == tyProc
   internalAssert formal.n.sons[0].kind == nkEffectList
   internalAssert actual.n.sons[0].kind == nkEffectList
-  
+
   var spec = formal.n.sons[0]
   if spec.len != 0:
     var real = actual.n.sons[0]
diff --git a/compiler/vm.nim b/compiler/vm.nim
index a36de1c20..f0a0135e8 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -239,7 +239,7 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
 
 proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
 
-proc cleanUpOnException(c: PCtx; tos: PStackFrame): 
+proc cleanUpOnException(c: PCtx; tos: PStackFrame):
                                               tuple[pc: int, f: PStackFrame] =
   let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
   var f = tos
@@ -257,7 +257,7 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame):
       let exceptType = c.types[c.code[pc2].regBx-wordExcess].skipTypes(
                           abstractPtrs)
       if inheritanceDiff(exceptType, raisedType) <= 0:
-        # mark exception as handled but keep it in B for 
+        # mark exception as handled but keep it in B for
         # the getCurrentException() builtin:
         c.currentExceptionB = c.currentExceptionA
         c.currentExceptionA = nil
@@ -349,14 +349,14 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
       if dest.kind != rkFloat:
         myreset(dest); dest.kind = rkFloat
       case skipTypes(srctyp, abstractRange).kind
-      of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar: 
+      of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
         dest.floatVal = toFloat(src.intVal.int)
       else:
         dest.floatVal = src.floatVal
     else:
       asgnComplex(dest, src)
 
-proc compile(c: PCtx, s: PSym): int = 
+proc compile(c: PCtx, s: PSym): int =
   result = vmgen.genProc(c, s)
   when debugEchoCode: c.echoCode result
   #c.echoCode
@@ -396,10 +396,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       pc = tos.comesFrom
       tos = tos.next
       let retVal = regs[0]
-      if tos.isNil: 
+      if tos.isNil:
         #echo "RET ", retVal.rendertree
         return retVal
-      
+
       move(regs, tos.slots)
       assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
       if c.code[pc].opcode == opcIndCallAsgn:
@@ -653,7 +653,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcSubu:
       decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
-    of opcMulu: 
+    of opcMulu:
       decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
     of opcDivu:
@@ -726,7 +726,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLeSet:
       decodeBC(rkInt)
       regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node))
-    of opcEqSet: 
+    of opcEqSet:
       decodeBC(rkInt)
       regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node))
     of opcLtSet:
@@ -737,9 +737,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcMulSet:
       decodeBC(rkNode)
       createSet(regs[ra])
-      move(regs[ra].node.sons, 
+      move(regs[ra].node.sons,
             nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
-    of opcPlusSet: 
+    of opcPlusSet:
       decodeBC(rkNode)
       createSet(regs[ra])
       move(regs[ra].node.sons,
@@ -753,7 +753,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeBC(rkNode)
       createSet(regs[ra])
       move(regs[ra].node.sons,
-           nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)    
+           nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)
     of opcConcatStr:
       decodeBC(rkNode)
       createStr regs[ra]
@@ -793,7 +793,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       assert c.code[pc].opcode == opcSubStr
       let rd = c.code[pc].regA
       createStr regs[ra]
-      regs[ra].node.strVal = substr(regs[rb].node.strVal, 
+      regs[ra].node.strVal = substr(regs[rb].node.strVal,
                                     regs[rc].intVal.int, regs[rd].intVal.int)
     of opcParseFloat:
       decodeBC(rkInt)
@@ -896,12 +896,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       # we know the next instruction is a 'fjmp':
       let branch = c.constants[instr.regBx-wordExcess]
       var cond = false
-      for j in countup(0, sonsLen(branch) - 2): 
-        if overlap(regs[ra].regToNode, branch.sons[j]): 
+      for j in countup(0, sonsLen(branch) - 2):
+        if overlap(regs[ra].regToNode, branch.sons[j]):
           cond = true
           break
       assert c.code[pc+1].opcode == opcFJmp
-      inc pc 
+      inc pc
       # we skip this instruction so that the final 'inc(pc)' skips
       # the following jump
       if not cond:
@@ -1273,7 +1273,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNSetIntVal:
       decodeB(rkNode)
       var dest = regs[ra].node
-      if dest.kind in {nkCharLit..nkInt64Lit} and 
+      if dest.kind in {nkCharLit..nkInt64Lit} and
          regs[rb].kind in {rkInt}:
         dest.intVal = regs[rb].intVal
       else:
@@ -1281,24 +1281,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNSetFloatVal:
       decodeB(rkNode)
       var dest = regs[ra].node
-      if dest.kind in {nkFloatLit..nkFloat64Lit} and 
+      if dest.kind in {nkFloatLit..nkFloat64Lit} and
          regs[rb].kind in {rkFloat}:
         dest.floatVal = regs[rb].floatVal
-      else: 
+      else:
         stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
     of opcNSetSymbol:
       decodeB(rkNode)
       var dest = regs[ra].node
       if dest.kind == nkSym and regs[rb].node.kind == nkSym:
         dest.sym = regs[rb].node.sym
-      else: 
+      else:
         stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
     of opcNSetIdent:
       decodeB(rkNode)
       var dest = regs[ra].node
       if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
         dest.ident = regs[rb].node.ident
-      else: 
+      else:
         stackTrace(c, tos, pc, errFieldXNotFound, "ident")
     of opcNSetType:
       decodeB(rkNode)
@@ -1309,7 +1309,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNSetStrVal:
       decodeB(rkNode)
       var dest = regs[ra].node
-      if dest.kind in {nkStrLit..nkTripleStrLit} and 
+      if dest.kind in {nkStrLit..nkTripleStrLit} and
          regs[rb].kind in {rkNode}:
         dest.strVal = regs[rb].node.strVal
       else:
@@ -1435,8 +1435,9 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): 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
 
-proc evalConstExpr*(module: PSym, e: PNode): PNode = 
+proc evalConstExpr*(module: PSym, e: PNode): PNode =
   result = evalConstExprAux(module, nil, e, emConst)
 
 proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
@@ -1496,6 +1497,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   # temporary storage:
   #for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
   result = rawExecute(c, start, tos).regToNode
+  if result.info.line < 0: result.info = n.info
   if cyclicTree(result): globalError(n.info, errCyclicTree)
   dec(evalMacroCounter)
   c.callsite = nil
diff --git a/doc/lib.txt b/doc/lib.txt
index 76920c6a9..385e7a91a 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -175,6 +175,9 @@ Generic Operating System Services
   This module implements the ability to monitor a directory/file for changes
   using Posix's inotify API.
 
+* `asyncfile <asyncfile.html>`_
+  This module implements asynchronous file reading and writing using
+  ``asyncdispatch``.
 
 Math libraries
 --------------
diff --git a/koch.nim b/koch.nim
index d365262c1..34cb1317d 100644
--- a/koch.nim
+++ b/koch.nim
@@ -347,7 +347,7 @@ proc temp(args: string) =
   if args.len > 0: exec(finalDest & " " & args)
 
 proc showHelp() = 
-  quit(HelpText % [VersionAsString & repeatChar(44-len(VersionAsString)), 
+  quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)), 
                    CompileDate, CompileTime], QuitSuccess)
 
 var op = initOptParser()
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index 7d5ff8948..921a24fd1 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -66,7 +66,7 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
     offset: cint
   result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
   if result == nil:
-    raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
+    raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
 
 proc finalizeRegEx(x: Regex) = 
   # XXX This is a hack, but PCRE does not export its "free" function properly.
@@ -291,7 +291,7 @@ proc replace*(s: string, sub: Regex, by = ""): string =
   ## accessed in `by`. Examples:
   ##
   ## .. code-block:: nim
-  ##   "var1=key; var2=key2".replace(re"(\w+)'='(\w+)")
+  ##   "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
   ##
   ## Results in:
   ##
@@ -313,7 +313,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
   ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
   ##
   ## .. code-block:: nim
-  ## "var1=key; var2=key2".replacef(re"(\w+)'='(\w+)", "$1<-$2$2")
+  ##   "var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2")
   ##
   ## Results in:
   ##
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 50c7968ac..a1d4d1e27 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -67,7 +67,7 @@ __clang__
 #endif
 
 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
-#  define NIM_THREADVAR __declspec(thread) 
+#  define NIM_THREADVAR __declspec(thread)
 #else
 #  define NIM_THREADVAR __thread
 #endif
@@ -103,7 +103,11 @@ __clang__
 #  define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
 #  define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
 
-#  define N_LIB_EXPORT  extern __declspec(dllexport)
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C" __declspec(dllexport)
+#  else
+#    define N_LIB_EXPORT  extern __declspec(dllexport)
+#  endif
 #  define N_LIB_IMPORT  extern __declspec(dllimport)
 #else
 #  define N_CDECL(rettype, name) rettype name
@@ -118,7 +122,11 @@ __clang__
 #  define N_FASTCALL_PTR(rettype, name) rettype (*name)
 #  define N_SAFECALL_PTR(rettype, name) rettype (*name)
 
-#  define N_LIB_EXPORT  extern
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C"
+#  else
+#    define N_LIB_EXPORT  extern
+#  endif
 #  define N_LIB_IMPORT  extern
 #endif
 
@@ -345,7 +353,7 @@ struct TFrame {
 #define nimln(n, file) \
   F.line = n; F.filename = file;
 
-#define NIM_POSIX_INIT  __attribute__((constructor)) 
+#define NIM_POSIX_INIT  __attribute__((constructor))
 
 #if defined(_MSCVER) && defined(__i386__)
 __declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
@@ -380,7 +388,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
 #endif
 
 /* Test to see if Nim and the C compiler agree on the size of a pointer.
-   On disagreement, your C compiler will say something like: 
+   On disagreement, your C compiler will say something like:
    "error: 'assert_numbits' declared as an array with a negative size" */
 typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
 #endif
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 95d49bad7..97784898e 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -189,7 +189,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
   tok.line = L.line
   L.col = tok.ival
   tok.ival = max(tok.ival - L.baseIndent, 0)
-  tok.symbol = "\n" & repeatChar(tok.ival)
+  tok.symbol = "\n" & spaces(tok.ival)
 
 proc rawGetTok(L: var TLexer, tok: var TToken) = 
   tok.symbol = ""
@@ -963,7 +963,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
           break 
         else: 
           add(n.text, "\n")
-          add(n.text, repeatChar(p.tok[p.idx].ival - indent))
+          add(n.text, spaces(p.tok[p.idx].ival - indent))
           inc(p.idx)
       else: 
         add(n.text, p.tok[p.idx].symbol)
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 52af672df..614001d76 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -110,7 +110,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   const 
     lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
   if n == nil: return
-  var ind = repeatChar(d.indent)
+  var ind = spaces(d.indent)
   case n.kind
   of rnInner: 
     renderRstSons(d, n, result)
@@ -124,7 +124,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
 
     result.add("\n")
     result.add(ind)
-    result.add repeatChar(headlineLen, lvlToChar[n.level])
+    result.add repeat(lvlToChar[n.level], headlineLen)
   of rnOverline:
     result.add("\n")
     result.add(ind)
@@ -132,7 +132,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     var headline = ""
     renderRstSons(d, n, headline)
     
-    let lvl = repeatChar(headline.len - d.indent, lvlToChar[n.level])
+    let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
     result.add(lvl)
     result.add("\n")
     result.add(headline)
@@ -143,7 +143,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   of rnTransition: 
     result.add("\n\n")
     result.add(ind)
-    result.add repeatChar(78-d.indent, '-')
+    result.add repeat('-', 78-d.indent)
     result.add("\n\n")
   of rnParagraph:
     result.add("\n\n")
@@ -196,7 +196,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add ':'
     result.add tmp
     result.add ':'
-    result.add repeatChar(L - tmp.len - 2)
+    result.add spaces(L - tmp.len - 2)
     renderRstToRst(d, n.sons[1], result)
     
     dec(d.indent, L)
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index e1e590877..a385336d6 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -461,9 +461,9 @@ proc indentToLevel(level: var int, newLevel: int): string =
   if level == newLevel:
     return
   if newLevel > level:
-    result = repeatStr(newLevel - level, "<ul>")
+    result = repeat("<ul>", newLevel - level)
   else:
-    result = repeatStr(level - newLevel, "</ul>")
+    result = repeat("</ul>", level - newLevel)
   level = newLevel
 
 proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
@@ -701,7 +701,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
   # Generate index entry using spaces to indicate TOC level for the output HTML.
   assert n.level >= 0
   setIndexTerm(d, refname, tmp.stripTOCHTML,
-    repeatChar(max(0, n.level), ' ') & tmp)
+    spaces(max(0, n.level)) & tmp)
 
 proc renderOverline(d: PDoc, n: PRstNode, result: var string) = 
   if d.meta[metaTitle].len == 0:
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 20bfc5c7c..20976e788 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -187,6 +187,34 @@ proc sort*[T](a: var openArray[T],
       dec(m, s*2)
     s = s*2
 
+proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, order = SortOrder.Ascending): seq[T] =
+  ## returns `a` sorted by `cmp` in the specified `order`.
+  result = newSeq[T](a.len)
+  for i in 0 .. a.high:
+    result[i] = a[i]
+  sort(result, cmp, order)
+
+template sortByIt*(seq1, op: expr): expr =
+  ## Convenience template around the ``sorted`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##     var users: seq[tuple[id: int, name: string]] =
+  ##       @[(0, "Smith"), (1, "Pratt"), (2, "Sparrow")]
+  ##
+  ##     echo users.sortByIt(it.name)
+  ##
+  var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
+    var it {.inject.} = x
+    let a = op
+    it = y
+    let b = op
+    result = cmp(a, b))
+  result
+
 proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   ## produces the Cartesian product of the array. Warning: complexity
   ## may explode.
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index 752c01eac..844c2ab55 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements asynchronous file handling.
+## This module implements asynchronous file reading and writing.
 ##
 ## .. code-block:: Nim
 ##    import asyncfile, asyncdispatch, os
@@ -30,7 +30,7 @@ else:
   import posix
 
 type
-  AsyncFile = ref object
+  AsyncFile* = ref object
     fd: TAsyncFd
     offset: int64
 
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 959688d6a..93a7591ac 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -196,7 +196,11 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
   var hc: THash
   var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
-  else: raise newException(KeyError, "key not found: " & $key)
+  else:
+    when compiles($key):
+      raise newException(KeyError, "key not found: " & $key)
+    else:
+      raise newException(KeyError, "key not found")
 
 iterator allValues*[A, B](t: Table[A, B]; key: A): B =
   ## iterates over any value in the table `t` that belongs to the given `key`.
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 30daaf2dc..a16342d44 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -33,8 +33,8 @@
 ##  proc hash(x: Something): THash =
 ##    ## Computes a THash from `x`.
 ##    var h: THash = 0
-##    h = h &! hash(x.foo)
-##    h = h &! hash(x.bar)
+##    h = h !& hash(x.foo)
+##    h = h !& hash(x.bar)
 ##    result = !$h
 
 import 
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 37af14df3..f11101511 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -390,8 +390,11 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = if proxy == nil: parseUri(url) else: proxy.url
   var headers = substr(httpMethod, len("http"))
+  # TODO: Use generateHeaders further down once it supports proxies.
   if proxy == nil:
-    headers.add(" " & r.path)
+    headers.add ' '
+    if r.path[0] != '/': headers.add '/'
+    headers.add(r.path)
     if r.query.len > 0:
       headers.add("?" & r.query)
   else:
@@ -567,9 +570,12 @@ proc downloadFile*(url: string, outputFilename: string,
 
 proc generateHeaders(r: Uri, httpMethod: string,
                      headers: StringTableRef): string =
+  # TODO: Use this in the blocking HttpClient once it supports proxies.
   result = substr(httpMethod, len("http"))
   # TODO: Proxies
-  result.add(" " & r.path)
+  result.add ' '
+  if r.path[0] != '/': result.add '/'
+  result.add(r.path)
   if r.query.len > 0:
     result.add("?" & r.query)
   result.add(" HTTP/1.1\c\L")
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 2038b246d..5041fe2f6 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -816,7 +816,7 @@ proc copy*(p: JsonNode): JsonNode =
 # ------------- pretty printing ----------------------------------------------
 
 proc indent(s: var string, i: int) = 
-  s.add(repeatChar(i))
+  s.add(spaces(i))
 
 proc newIndent(curr, indent: int, ml: bool): int =
   if ml: return curr + indent
diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim
index a3a3d7b5c..23a87d9f8 100644
--- a/lib/pure/lexbase.nim
+++ b/lib/pure/lexbase.nim
@@ -165,5 +165,5 @@ proc getCurrentLine(L: BaseLexer, marker: bool = true): string =
     inc(i)
   add(result, "\n")
   if marker:
-    add(result, repeatChar(getColNumber(L, L.bufpos)) & "^\n")
+    add(result, spaces(getColNumber(L, L.bufpos)) & "^\n")
 
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 52d81b3a4..64d3e1470 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -798,6 +798,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
   
   return r.readInteger()
 
+# HyperLogLog
+
+proc pfadd*(r: Redis, key: string, elements: varargs[string]): RedisInteger = 
+  ## Add variable number of elements into special 'HyperLogLog' set type
+  r.sendCommand("PFADD", key, elements)
+  return r.readInteger()
+
+proc pfcount*(r: Redis, key: string): RedisInteger =
+  ## Count approximate number of elements in 'HyperLogLog'
+  r.sendCommand("PFCOUNT", key)
+  return r.readInteger()
+
+proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
+  ## Merge several source HyperLogLog's into one specified by destKey
+  r.sendCommand("PFMERGE", destination, sources)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
 
 # Pub/Sub
 
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 67c80e592..e706f2016 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -224,10 +224,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
 
 proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = 
   var s = StringStream(s)
-  if bufLen > 0: 
-    setLen(s.data, s.data.len + bufLen)
-    copyMem(addr(s.data[s.pos]), buffer, bufLen)
-    inc(s.pos, bufLen)
+  if bufLen <= 0:
+    return
+  if s.pos + bufLen > s.data.len:
+    setLen(s.data, s.pos + bufLen)
+  copyMem(addr(s.data[s.pos]), buffer, bufLen)
+  inc(s.pos, bufLen)
 
 proc ssClose(s: Stream) =
   var s = StringStream(s)
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index e32ea786a..c39667611 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -628,25 +628,25 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
     var fr = ($info.year).len()-2
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
+    if fyear.len != 2: fyear = repeat('0', 2-fyear.len()) & fyear
     buf.add(fyear)
   of "yyy":
     var fr = ($info.year).len()-3
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
+    if fyear.len != 3: fyear = repeat('0', 3-fyear.len()) & fyear
     buf.add(fyear)
   of "yyyy":
     var fr = ($info.year).len()-4
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
+    if fyear.len != 4: fyear = repeat('0', 4-fyear.len()) & fyear
     buf.add(fyear)
   of "yyyyy":
     var fr = ($info.year).len()-5
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
+    if fyear.len != 5: fyear = repeat('0', 5-fyear.len()) & fyear
     buf.add(fyear)
   of "z":
     let hrs = (info.timezone div 60) div 60
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 9a6e273a8..b0afb75f9 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -286,6 +286,16 @@ proc `$`*(u: Uri): string =
 
 when isMainModule:
   block:
+    let str = "http://localhost"
+    let test = parseUri(str)
+    doAssert test.path == ""
+
+  block:
+    let str = "http://localhost/"
+    let test = parseUri(str)
+    doAssert test.path == "/"
+
+  block:
     let str = "http://localhost:8080/test"
     let test = parseUri(str)
     doAssert test.scheme == "http"
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index 2e55ff182..6242e589e 100644
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -1083,7 +1083,7 @@ proc addEscaped(s: string): string =
     else: result.add(c)
 
 proc nodeToXml(n: PNode, indent: int = 0): string =
-  result = repeatChar(indent, ' ') & "<" & n.nodeName
+  result = spaces(indent) & "<" & n.nodeName
   if not isNil(n.attributes):
     for i in items(n.attributes):
       result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
@@ -1098,23 +1098,23 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
       of ElementNode:
         result.add(nodeToXml(i, indent + 2))
       of TextNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add(addEscaped(i.nodeValue))
       of CDataSectionNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<![CDATA[" & i.nodeValue & "]]>")
       of ProcessingInstructionNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<?" & PProcessingInstruction(i).target & " " &
                           PProcessingInstruction(i).data & " ?>")
       of CommentNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<!-- " & i.nodeValue & " -->")
       else:
         continue
       result.add("\n")
     # Add the ending tag - </tag>
-    result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
+    result.add(spaces(indent) & "</" & n.nodeName & ">")
 
 proc `$`*(doc: PDocument): string =
   ## Converts a PDocument object into a string representation of it's XML
diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim
new file mode 100644
index 000000000..960e2aae9
--- /dev/null
+++ b/tests/ccgbugs/tuple_canon.nim
@@ -0,0 +1,80 @@
+# bug #2250
+
+import
+    math, strutils
+
+type
+    Meters = float
+    Point2[T] = tuple[x, y: T]
+
+    HexState* = enum
+        hsOn, hsOff
+
+    Index = uint16
+
+    HexGrid* = object
+        w, h: int                       ## Width and height of the hex grid.
+        radius: Meters                  ## Radius of circle that circumscribes a hexagon.
+        grid: seq[HexState]             ## Information on what hexes are drawn.
+
+    HexVtxIndex = enum
+        hiA, hiB, hiC, hiD, hiE, hiF
+
+    HexCoord* = Point2[int]
+
+const
+    HexDY = sqrt(1.0 - (0.5 * 0.5))     # dy from center to midpoint of 1-2
+    HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5)
+
+
+let
+    hexOffsets : array[HexVtxIndex, Point2[float]] = [
+                  (-1.0, 0.0),
+                  (-HexDX, -HexDY),
+                  (HexDX, -HexDY),
+                  (1.0, 0.0),
+                  (HexDX, HexDY),
+                  (-HexDX, HexDY)]
+
+    evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,-1), hiA),
+            ((1,0), hiB),
+            ((1,0), hiA),
+            ((0,1), hiB)]
+
+    oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,0), hiA),
+            ((1,1), hiB),
+            ((1,1), hiA),
+            ((0,1), hiB)]
+
+template odd*(i: int) : expr =
+    (i and 1) != 0
+
+proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index =
+    #NOTE: this variation compiles
+    #var offset : type(evenSharingOffsets[i])
+    #
+    #if odd(col):
+    #    offset = oddSharingOffsets[i]
+    #else:
+    #    offset = evenSharingOffsets[i]
+
+    let
+        #NOTE: this line generates the bad code
+        offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i])
+        x = col + 1 + offset.hc.x
+        y = row + 1 + offset.hc.y
+
+    result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx))
+
+proc go() =
+    var hg : HexGrid
+
+    echo "vidx ", $vidx(hg, 1, 2, hiC)
+
+go()
diff --git a/tests/clearmsg/tconsttypemismatch.nim b/tests/clearmsg/tconsttypemismatch.nim
new file mode 100644
index 000000000..edf480348
--- /dev/null
+++ b/tests/clearmsg/tconsttypemismatch.nim
@@ -0,0 +1,8 @@
+discard """
+  file: "tconsttypemismatch.nim"
+  line: 7
+  errormsg: "type mismatch"
+"""
+# bug #2252
+const foo: int = 1000 / 30
+
diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim
index 6fb929efb..289bf1fd5 100644
--- a/tests/generics/tgeneric3.nim
+++ b/tests/generics/tgeneric3.nim
@@ -188,7 +188,7 @@ proc traceTree[T,D](root: PNode[T,D]) =
     write stdout, space
 
   proc doTrace(n: PNode[T,D], level: int) =
-    var space = repeatChar(2 * level)
+    var space = spaces(2 * level)
     traceln(space)
     write stdout, "node: "
     if n == nil:
diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim
index a507a08e4..060610ae0 100644
--- a/tests/manyloc/argument_parser/argument_parser.nim
+++ b/tests/manyloc/argument_parser/argument_parser.nim
@@ -471,7 +471,7 @@ proc build_help*(expected: seq[Tparameter_specification] = @[],
   let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
 
   for line in zip(prefixes, helps):
-    result.add(line.a & repeatChar(width - line.a.len) & line.b)
+    result.add(line.a & spaces(width - line.a.len) & line.b)
 
 
 proc echo_help*(expected: seq[Tparameter_specification] = @[],
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
index a9759687f..3c5a7835c 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
@@ -1,5 +1,5 @@
 import streams
-from strutils import repeatChar
+from strutils import repeat
 
 proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString = 
   var lastChr = length
@@ -10,7 +10,7 @@ proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
 proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
   if str.len < length:
     s.write(str)
-    s.write(repeatChar(length - str.len, padChar))
+    s.write(repeat(padChar, length - str.len))
   elif str.len > length:
     s.write(str.substr(0, length - 1))
   else:
@@ -37,7 +37,7 @@ when isMainModule:
   testStream.setPosition 0
   testStream.writePaddedStr("Sup", 10)
   echo(repr(testStream), testStream.data.len)
-  doAssert testStream.data == "Sup"&repeatChar(7, '\0')
+  doAssert testStream.data == "Sup"&repeat('\0', 7)
   
   testStream.setPosition 0
   res = testStream.readPaddedStr(10)
diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim
index 6dd1a6a7f..c2e893273 100644
--- a/tests/manyloc/keineschweine/enet_server/enet_server.nim
+++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim
@@ -144,7 +144,7 @@ when isMainModule:
     discard """block:
       var 
         TestFile: FileChallengePair
-        contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
+        contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
       testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
       testFile.file = checksumStr(contents)
       myAssets.add testFile"""
diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim
index 0a5dc1efc..525d8a054 100644
--- a/tests/manyloc/keineschweine/keineschweine.nim
+++ b/tests/manyloc/keineschweine/keineschweine.nim
@@ -113,7 +113,7 @@ when defined(recordMode):
     isRecording = false
   proc zeroPad*(s: string; minLen: int): string =
     if s.len < minLen:
-      result = repeatChar(minLen - s.len, '0')
+      result = repeat(0, minLen - s.len)
       result.add s
     else:
       result = s
diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim
index 966b84b6a..5776c9225 100644
--- a/tests/manyloc/keineschweine/lib/map_filter.nim
+++ b/tests/manyloc/keineschweine/lib/map_filter.nim
@@ -27,9 +27,9 @@ when isMainModule:
   var res = t.map(proc(z: int): int = result = z * 10)
   dumpSeq res
 
-  from strutils import toHex, repeatStr
+  from strutils import toHex
   var foocakes = t.map(proc(z: int): string = 
-    result = toHex((z * 23).biggestInt, 4))
+    result = toHex((z * 23).BiggestInt, 4))
   dumpSeq foocakes
 
   t.mapInPlace(proc(z: int): int = result = z * 30)
diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
index 9a6542d75..fcd0e8d24 100644
--- a/tests/manyloc/keineschweine/lib/zlib_helpers.nim
+++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
@@ -24,17 +24,17 @@ when isMainModule:
   import strutils
   var r = compress("Hello")
   echo repr(r)
-  var l = "Hello".len
-  var rr = uncompress(r, l)
+  var ln = "Hello".len
+  var rr = uncompress(r, ln)
   echo repr(rr)
   assert rr == "Hello"
 
-  proc `*`(a: string; b: int): string {.inline.} = result = repeatStr(b, a)
+  proc `*`(a: string; b: int): string {.inline.} = result = repeat(a, b)
   var s = "yo dude sup bruh homie" * 50
   r = compress(s)
   echo s.len, " -> ", r.len
 
-  l = s.len
-  rr = uncompress(r, l)
+  ln = s.len
+  rr = uncompress(r, ln)
   echo r.len, " -> ", rr.len
   assert rr == s
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim
index ac85cbf62..1e57c12a1 100644
--- a/tests/manyloc/keineschweine/server/old_sg_server.nim
+++ b/tests/manyloc/keineschweine/server/old_sg_server.nim
@@ -174,7 +174,7 @@ when isMainModule:
   block:
     var 
       TestFile: FileChallengePair
-      contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
+      contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
     testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
     testFile.file = checksumStr(contents)
     myAssets.add testFile
diff --git a/tests/overload/tsymtabchange_during_or.nim b/tests/overload/tsymtabchange_during_or.nim
new file mode 100644
index 000000000..b5551bcc7
--- /dev/null
+++ b/tests/overload/tsymtabchange_during_or.nim
@@ -0,0 +1,24 @@
+
+# bug #2229
+
+type Type1 = object
+        id: int
+
+type Type2 = object
+    id: int
+
+proc init(self: var Type1, a: int, b: ref Type2) =
+    echo "1"
+
+proc init(self: var Type2, a: int) =
+    echo """
+        Works when this proc commented out
+        Otherwise error:
+        test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2)
+    """
+
+var a: Type1
+init(a, 1, (
+    var b = new(Type2);
+    b
+))
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index ab1e46d6f..323abd768 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -302,8 +302,7 @@ proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
         continue
 
       let
-        buildPath = getPackageDir(name)[0.. -3]
-      let
+        buildPath = getPackageDir(name).strip
         buildProcess = startProcess(nimbleExe, buildPath, ["build"])
         buildStatus = waitForExitEx(buildProcess)
       buildProcess.close
@@ -318,7 +317,7 @@ proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
 
 # ----------------------------------------------------------------------------
 
-const AdditionalCategories = ["debugger", "examples", "lib", "nimble-core"]
+const AdditionalCategories = ["debugger", "examples", "lib"]
 
 proc `&.?`(a, b: string): string =
   # candidate for the stdlib?
diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim
index 96a1bafe8..4459931c5 100644
--- a/tests/vm/tconsteval.nim
+++ b/tests/vm/tconsteval.nim
@@ -24,7 +24,7 @@ Possible Commands:
   csource [options]        builds the C sources for installation
   zip                      builds the installation ZIP package
   inno                     builds the Inno Setup installer
-""" % [NimVersion & repeatChar(44-len(NimVersion)), 
+""" % [NimVersion & spaces(44-len(NimVersion)), 
        CompileDate, CompileTime]
 
 echo HelpText
diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim
index aeae86300..72e4adc07 100644
--- a/tools/nimgrep.nim
+++ b/tools/nimgrep.nim
@@ -109,7 +109,7 @@ proc highlight(s, match, repl: string, t: tuple[first, last: int],
   for i in t.last+1 .. y: stdout.write(s[i])
   stdout.write("\n")
   if showRepl:
-    stdout.write(repeatChar(alignment-1), "-> ")
+    stdout.write(spaces(alignment-1), "-> ")
     for i in x .. t.first-1: stdout.write(s[i])
     writeColored(repl)
     for i in t.last+1 .. y: stdout.write(s[i])
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index 8213cf418..a7301195e 100644
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -99,8 +99,8 @@ macro updated(e: expr): expr {.immediate.} =
 proc updatedDate(year, month, day: string): string =
   ## wrapper around the update macro with easy input.
   result = updated("$1-$2-$3T00:00:00Z" % [year,
-    repeatStr(2 - len(month), "0") & month,
-    repeatStr(2 - len(day), "0") & day])
+    repeat("0", 2 - len(month)) & month,
+    repeat("0", 2 - len(day)) & day])
 
 macro entry(e: expr): expr {.immediate.} =
   ## generates the rss xml ``entry`` element.
diff --git a/web/website.ini b/web/website.ini
index 696829764..6266f05bb 100644
--- a/web/website.ini
+++ b/web/website.ini
@@ -59,6 +59,7 @@ srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
 srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
 srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
 srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
+srcdoc2: "pure/asyncfile"
 srcdoc2: "pure/md5"
 srcdoc2: "posix/posix"
 srcdoc2: "pure/fenv"