summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-x[-rw-r--r--]build.sh0
-rw-r--r--compiler/astalgo.nim14
-rw-r--r--compiler/ccgcalls.nim30
-rw-r--r--compiler/extccomp.nim4
-rw-r--r--compiler/installer.ini (renamed from compiler/nim.ini)0
-rw-r--r--compiler/msgs.nim5
-rw-r--r--compiler/pragmas.nim9
-rw-r--r--compiler/sem.nim6
-rw-r--r--compiler/semdata.nim1
-rw-r--r--compiler/semexprs.nim33
-rw-r--r--compiler/sempass2.nim42
-rw-r--r--compiler/semstmts.nim4
-rw-r--r--compiler/semtypes.nim7
-rw-r--r--compiler/sigmatch.nim27
-rw-r--r--copying.txt2
-rw-r--r--doc/nimc.txt941
-rw-r--r--doc/niminst.txt2
-rw-r--r--koch.nim14
-rw-r--r--lib/core/macros.nim20
-rw-r--r--lib/impure/db_mysql.nim4
-rw-r--r--lib/impure/rdstdin.nim18
-rw-r--r--lib/pure/asyncdispatch.nim58
-rw-r--r--lib/pure/collections/sets.nim156
-rw-r--r--lib/pure/collections/tables.nim2
-rw-r--r--lib/pure/math.nim12
-rw-r--r--lib/pure/net.nim9
-rw-r--r--lib/pure/os.nim6
-rw-r--r--lib/pure/selectors.nim2
-rw-r--r--lib/pure/times.nim102
-rw-r--r--lib/system.nim38
-rw-r--r--lib/system/assign.nim10
-rw-r--r--lib/system/excpt.nim14
-rw-r--r--lib/system/gc.nim38
-rw-r--r--lib/system/gc_ms.nim10
-rw-r--r--lib/system/repr.nim6
-rw-r--r--lib/wrappers/mysql.nim2
-rw-r--r--readme.md26
-rw-r--r--tests/async/tasyncexceptions.nim1
-rw-r--r--tests/async/tasynctry.nim41
-rw-r--r--tests/collections/tindexby.nim22
-rw-r--r--tests/collections/ttableconstr.nim (renamed from tests/table/ttableconstr.nim)0
-rw-r--r--tests/collections/ttables.nim148
-rw-r--r--tests/collections/ttables2.nim (renamed from tests/table/ttables2.nim)0
-rw-r--r--tests/collections/ttablesref.nim (renamed from tests/table/ptables.nim)2
-rw-r--r--tests/collections/ttablesref2.nim (renamed from tests/table/ptables2.nim)0
-rw-r--r--tests/gc/gcleak4.nim4
-rw-r--r--tests/gc/growobjcrash.nim29
-rw-r--r--tests/implicit/timplictderef.nim21
-rw-r--r--tests/metatype/tautoproc.nim4
-rw-r--r--tests/metatype/tcompositetypeclasses.nim2
-rw-r--r--tests/metatype/tmatrix.nim (renamed from tests/matrix/tmatrix.nim)0
-rw-r--r--tests/metatype/tmatrix1.nim (renamed from tests/matrix/tmatrix1.nim)0
-rw-r--r--tests/metatype/tmatrix2.nim (renamed from tests/matrix/tmatrix2.nim)0
-rw-r--r--tests/metatype/tmatrix3.nim (renamed from tests/static/tmatrix.nim)0
-rw-r--r--tests/metatype/tstaticparammacro.nim (renamed from tests/static/tstaticparammacro.nim)1
-rw-r--r--tests/metatype/ttypetraits.nim1
-rw-r--r--tests/metatype/tymatrix.nim (renamed from tests/matrix/issue1013.nim)0
-rw-r--r--tests/metatype/typeclassinference.nim1
-rw-r--r--tests/metatype/typedesc_as_value.nim11
-rw-r--r--tests/modules/mnamspc1.nim (renamed from tests/namspc/mnamspc1.nim)0
-rw-r--r--tests/modules/mnamspc2.nim (renamed from tests/namspc/mnamspc2.nim)0
-rw-r--r--tests/modules/mopaque.nim (renamed from tests/module/mopaque.nim)0
-rw-r--r--tests/modules/mrecmod.nim (renamed from tests/module/mrecmod.nim)0
-rw-r--r--tests/modules/mrecmod2.nim (renamed from tests/module/mrecmod2.nim)0
-rw-r--r--tests/modules/tnamspc.nim (renamed from tests/namspc/tnamspc.nim)0
-rw-r--r--tests/modules/topaque.nim (renamed from tests/module/topaque.nim)0
-rw-r--r--tests/modules/trecinca.nim (renamed from tests/module/trecinca.nim)2
-rw-r--r--tests/modules/trecincb.nim (renamed from tests/module/trecincb.nim)2
-rw-r--r--tests/modules/trecmod.nim (renamed from tests/module/trecmod.nim)0
-rw-r--r--tests/modules/trecmod2.nim (renamed from tests/module/trecmod2.nim)0
-rw-r--r--tests/objects/trefobjsyntax.nim27
-rw-r--r--tests/objvariant/treassign.nim27
-rw-r--r--tests/overload/tparams_after_varargs.nim17
-rw-r--r--tests/stdlib/tircbot.nim453
-rw-r--r--tests/stdlib/tmitems.nim2
-rw-r--r--tests/table/ttables.nim128
-rw-r--r--tests/testament/categories.nim3
-rw-r--r--tests/types/temptyseqs.nim2
-rw-r--r--todo.txt8
-rw-r--r--tools/nimweb.nim2
-rw-r--r--web/news.txt12
-rw-r--r--web/website.ini (renamed from web/nim.ini)33
82 files changed, 1291 insertions, 1389 deletions
diff --git a/build.sh b/build.sh
index 139c28359..139c28359 100644..100755
--- a/build.sh
+++ b/build.sh
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index f23e9a983..e9b82d74b 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -130,8 +130,8 @@ proc skipConvAndClosure*(n: PNode): PNode =
 proc sameValue*(a, b: PNode): bool = 
   result = false
   case a.kind
-  of nkCharLit..nkInt64Lit: 
-    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal
+  of nkCharLit..nkUInt64Lit: 
+    if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
   of nkFloatLit..nkFloat64Lit: 
     if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
   of nkStrLit..nkTripleStrLit: 
@@ -145,13 +145,13 @@ proc leValue*(a, b: PNode): bool =
   # a <= b?
   result = false
   case a.kind
-  of nkCharLit..nkInt64Lit: 
-    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal
-  of nkFloatLit..nkFloat64Lit: 
+  of nkCharLit..nkUInt32Lit:
+    if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
+  of nkFloatLit..nkFloat64Lit:
     if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
-  of nkStrLit..nkTripleStrLit: 
+  of nkStrLit..nkTripleStrLit:
     if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
-  else: 
+  else:
     # don't raise an internal error for 'nimrod check':
     #InternalError(a.info, "leValue")
     discard
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index b9fc694cb..fb878a83e 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -430,15 +430,27 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
-  
-  if length > 1:
-    app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
-    app(pl, ~" ")
-  app(pl, op.r)
-  if length > 2:
-    app(pl, ~": ")
-    app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
-  for i in countup(3, length-1):
+
+  # don't call 'ropeToStr' here for efficiency:
+  let pat = ri.sons[0].sym.loc.r.data
+  internalAssert pat != nil
+  var start = 3
+  if ' ' in pat:
+    start = 1
+    app(pl, op.r)
+    if length > 1:
+      app(pl, ~": ")
+      app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      start = 2
+  else:
+    if length > 1:
+      app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      app(pl, ~" ")
+    app(pl, op.r)
+    if length > 2:
+      app(pl, ~": ")
+      app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
+  for i in countup(start, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
       internalError(ri.info, "varargs for objective C method?")
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 8e40cca39..1083b7590 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -626,7 +626,9 @@ proc callCCompiler*(projectfile: string) =
     if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
     var res = 0
     if gNumberOfProcessors <= 1: 
-      for i in countup(0, high(cmds)): res = max(execWithEcho(cmds[i]), res)
+      for i in countup(0, high(cmds)): 
+        res = execWithEcho(cmds[i])
+        if res != 0: rawMessage(errExecutionOfProgramFailed, [])
     elif optListCmd in gGlobalOptions or gVerbosity > 1:
       res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
                           gNumberOfProcessors)
diff --git a/compiler/nim.ini b/compiler/installer.ini
index dcf9aa52f..dcf9aa52f 100644
--- a/compiler/nim.ini
+++ b/compiler/installer.ini
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index be69f1ea5..45fc2b1e2 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -720,7 +720,10 @@ type
 proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
   template quit =
     if defined(debug) or gVerbosity >= 3 or msg == errInternal:
-      writeStackTrace()
+      if stackTraceAvailable():
+        writeStackTrace()
+      else:
+        msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp c <file>")
     quit 1
 
   if msg >= fatalMin and msg <= fatalMax:
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 90f87696b..78ee490e2 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -735,11 +735,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           incl(sym.flags, sfProcvar)
           if sym.typ != nil: incl(sym.typ.flags, tfThread)
         of wGcSafe:
-          if optThreadAnalysis in gGlobalOptions:
-            noVal(it)
-            if sym.kind != skType: incl(sym.flags, sfThread)
-            if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
-            else: invalidPragma(it)
+          noVal(it)
+          if sym.kind != skType: incl(sym.flags, sfThread)
+          if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
+          else: invalidPragma(it)
         of wPacked:
           noVal(it)
           if sym.typ == nil: invalidPragma(it)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 214f471d6..2d69d4213 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -130,9 +130,11 @@ proc commonType*(x, y: PType): PType =
   elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
     var nt: PType
     for i in 0.. <a.len:
-      if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]):
+      let aEmpty = isEmptyContainer(a.sons[i])
+      let bEmpty = isEmptyContainer(b.sons[i])
+      if aEmpty != bEmpty:
         if nt.isNil: nt = copyType(a, a.owner, false)
-        nt.sons[i] = b.sons[i]
+        nt.sons[i] = if aEmpty: b.sons[i] else: a.sons[i]
     if not nt.isNil: result = nt
     #elif b.sons[idx].kind == tyEmpty: return x
   elif a.kind == tyRange and b.kind == tyRange:
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 157761591..27d441000 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -221,6 +221,7 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
 
 proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
   result = newTypeS(tyFromExpr, c)
+  assert n != nil
   result.n = n
 
 proc newTypeWithSons*(c: PContext, kind: TTypeKind,
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 40413e3eb..55d2656e0 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -448,25 +448,30 @@ proc changeType(n: PNode, newType: PType, check: bool) =
     let tup = newType.skipTypes({tyGenericInst})
     if tup.kind != tyTuple:
       internalError(n.info, "changeType: no tuple type for constructor")
-    elif newType.n == nil: discard
-    elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: 
-      for i in countup(0, sonsLen(n) - 1): 
+    elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
+      # named tuple?
+      for i in countup(0, sonsLen(n) - 1):
         var m = n.sons[i].sons[0]
-        if m.kind != nkSym: 
+        if m.kind != nkSym:
           internalError(m.info, "changeType(): invalid tuple constr")
           return
-        var f = getSymFromList(newType.n, m.sym.name)
-        if f == nil: 
-          internalError(m.info, "changeType(): invalid identifier")
-          return
-        changeType(n.sons[i].sons[1], f.typ, check)
+        if tup.n != nil:
+          var f = getSymFromList(newType.n, m.sym.name)
+          if f == nil: 
+            internalError(m.info, "changeType(): invalid identifier")
+            return
+          changeType(n.sons[i].sons[1], f.typ, check)
+        else:
+          changeType(n.sons[i].sons[1], tup.sons[i], check)
     else:
       for i in countup(0, sonsLen(n) - 1):
-        var m = n.sons[i]
-        var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
-        addSon(a, newSymNode(newType.n.sons[i].sym))
-        addSon(a, m)
-        changeType(m, tup.sons[i], check)
+        changeType(n.sons[i], tup.sons[i], check)
+        when false:
+          var m = n.sons[i]
+          var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
+          addSon(a, newSymNode(newType.n.sons[i].sym))
+          addSon(a, m)
+          changeType(m, tup.sons[i], check)
   of nkCharLit..nkUInt64Lit:
     if check:
       let value = n.intVal
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index ede556a70..3f78629c8 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -194,6 +194,9 @@ proc warnAboutGcUnsafe(n: PNode) =
   #assert false
   message(n.info, warnGcUnsafe, renderTree(n))
 
+template markGcUnsafe(a: PEffects) =
+  a.gcUnsafe = true
+
 proc useVar(a: PEffects, n: PNode) =
   let s = n.sym
   if isLocalVar(a, s):
@@ -209,7 +212,7 @@ proc useVar(a: PEffects, n: PNode) =
     if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and 
         tfGcSafe notin s.typ.flags:
       if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-      a.gcUnsafe = true
+      markGcUnsafe(a)
 
 type
   TIntersection = seq[tuple[id, count: int]] # a simple count table
@@ -448,7 +451,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
 
   if notGcSafe(s.typ) and sfImportc notin s.flags:
     if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-    tracked.gcUnsafe = true
+    markGcUnsafe(tracked)
   mergeLockLevels(tracked, n, s.getLockLevel)
 
 proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
@@ -502,13 +505,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
       # assume GcUnsafe unless in its type; 'forward' does not matter:
       if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-        tracked.gcUnsafe = true
+        markGcUnsafe(tracked)
     else:
       mergeEffects(tracked, effectList.sons[exceptionEffects], n)
       mergeTags(tracked, effectList.sons[tagEffects], n)
       if notGcSafe(op):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-        tracked.gcUnsafe = true
+        markGcUnsafe(tracked)
   notNilCheck(tracked, n, paramType)
 
 proc breaksBlock(n: PNode): bool =
@@ -656,7 +659,7 @@ proc track(tracked: PEffects, n: PNode) =
           # and it's not a recursive call:
           if not (a.kind == nkSym and a.sym == tracked.owner):
             warnAboutGcUnsafe(n)
-            tracked.gcUnsafe = true
+            markGcUnsafe(tracked)
     for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
     if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
       # may not look like an assignment, but it is:
@@ -825,7 +828,7 @@ proc trackProc*(s: PSym, body: PNode) =
   # effects already computed?
   if sfForward in s.flags: return
   if effects.len == effectListLen: return
-  
+
   var t: TEffects
   initEffects(effects, s, t)
   track(t, body)
@@ -849,19 +852,20 @@ proc trackProc*(s: PSym, body: PNode) =
     # after the check, use the formal spec:
     effects.sons[tagEffects] = tagsSpec
 
-  if optThreadAnalysis in gGlobalOptions:
-    if sfThread in s.flags and t.gcUnsafe:
-      if optThreads in gGlobalOptions:
-        localError(s.info, "'$1' is not GC-safe" % s.name.s)
-      else:
-        localError(s.info, warnGcUnsafe2, s.name.s)
-    if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
-    if s.typ.lockLevel == UnspecifiedLockLevel:
-      s.typ.lockLevel = t.maxLockLevel
-    elif t.maxLockLevel > s.typ.lockLevel:
-      localError(s.info,
-        "declared lock level is $1, but real lock level is $2" %
-          [$s.typ.lockLevel, $t.maxLockLevel])
+  if sfThread in s.flags and t.gcUnsafe:
+    if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
+      localError(s.info, "'$1' is not GC-safe" % s.name.s)
+    else:
+      localError(s.info, warnGcUnsafe2, s.name.s)
+  if not t.gcUnsafe:
+    s.typ.flags.incl tfGcSafe
+  if s.typ.lockLevel == UnspecifiedLockLevel:
+    s.typ.lockLevel = t.maxLockLevel
+  elif t.maxLockLevel > s.typ.lockLevel:
+    #localError(s.info,
+    message(s.info, warnLockLevel,
+      "declared lock level is $1, but real lock level is $2" %
+        [$s.typ.lockLevel, $t.maxLockLevel])
 
 proc trackTopLevelStmt*(module: PSym; n: PNode) =
   if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 6e5b272de..07cae5d04 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -359,6 +359,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
     var def: PNode
     if a.sons[length-1].kind != nkEmpty:
       def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
+      if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
+        # prevent the all too common 'var x = int' bug:
+        localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?")
+        def.typ = errorType(c)
       if typ != nil:
         if typ.isMetaType:
           def = inferWithMetatype(c, typ, def)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index d052700b2..048154f12 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -781,9 +781,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     result.rawAddSon(paramType)
       
     for i in 0 .. paramType.sonsLen - 2:
-      let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown
-                      else: tyAnything
-      result.rawAddSon newTypeS(dummyType, c)
+      if paramType.sons[i].kind == tyStatic:
+        result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnkown'
+      else:
+        result.rawAddSon newTypeS(tyAnything, c)
       
     if paramType.lastSon.kind == tyUserTypeClass:
       result.kind = tyUserTypeClassInst
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 2e37f3bf1..00802e69b 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -418,7 +418,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
 
     if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
       return isNone
-    elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {}:
+    elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and
+        optThreadAnalysis in gGlobalOptions:
       # noSideEffect implies ``tfThread``!
       return isNone
     elif f.flags * {tfIterator} != a.flags * {tfIterator}:
@@ -1056,7 +1057,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   of tyFromExpr:
     # fix the expression, so it contains the already instantiated types
-    if f.n == nil: return isGeneric
+    if f.n == nil or f.n.kind == nkEmpty: return isGeneric
     let reevaluated = tryResolvingStaticExpr(c, f.n)
     case reevaluated.typ.kind
     of tyTypeDesc:
@@ -1441,13 +1442,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         return
       checkConstraint(n.sons[a].sons[1])
       if m.baseTypeMatch: 
-        assert(container == nil)
+        #assert(container == nil)
         container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
         addSon(container, arg)
         setSon(m.call, formal.position + 1, container)
         if f != formalLen - 1: container = nil
-      else: 
+      else:
         setSon(m.call, formal.position + 1, arg)
+      inc f
     else:
       # unnamed param
       if f >= formalLen:
@@ -1466,7 +1468,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
           var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
                                     n.sons[a], nOrig.sons[a])
-          if (arg != nil) and m.baseTypeMatch and (container != nil):
+          if arg != nil and m.baseTypeMatch and container != nil:
             addSon(container, arg)
             incrIndexType(container.typ)
           else:
@@ -1480,7 +1482,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           internalError(n.sons[a].info, "matches")
           return
         formal = m.callee.n.sons[f].sym
-        if containsOrIncl(marker, formal.position): 
+        if containsOrIncl(marker, formal.position) and container.isNil:
           # already in namedParams:
           localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
           m.state = csNoMatch
@@ -1493,17 +1495,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.state = csNoMatch
           return
         if m.baseTypeMatch:
-          assert(container == nil)
-          container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
+          #assert(container == nil)
+          if container.isNil:
+            container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
           addSon(container, arg)
           setSon(m.call, formal.position + 1, 
                  implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
-          if f != formalLen - 1: container = nil
+          #if f != formalLen - 1: container = nil
+
+          # pick the formal from the end, so that 'x, y, varargs, z' works:
+          f = max(f, formalLen - n.len + a + 1)
         else:
           setSon(m.call, formal.position + 1, arg)
+          inc(f)
+          container = nil
       checkConstraint(n.sons[a])
     inc(a)
-    inc(f)
 
 proc semFinishOperands*(c: PContext, n: PNode) =
   # this needs to be called to ensure that after overloading resolution every
diff --git a/copying.txt b/copying.txt
index 908625e18..d89bace0b 100644
--- a/copying.txt
+++ b/copying.txt
@@ -1,7 +1,7 @@
 =====================================================
 Nim -- a Compiler for Nim. http://nim-lang.org/
 
-Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved.
+Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved.
  
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/doc/nimc.txt b/doc/nimc.txt
index 80fcf927b..84d596e3c 100644
--- a/doc/nimc.txt
+++ b/doc/nimc.txt
@@ -1,45 +1,45 @@
-===================================

-   Nim Compiler User Guide

-===================================

-

-:Author: Andreas Rumpf

-:Version: |nimversion|

-

-.. contents::

-

-  "Look at you, hacker. A pathetic creature of meat and bone, panting and

-  sweating as you run through my corridors. How can you challenge a perfect,

-  immortal machine?"

-

-

-Introduction

-============

-

-This document describes the usage of the *Nim compiler*

-on the different supported platforms. It is not a definition of the Nim

-programming language (therefore is the `manual <manual.html>`_).

-

-Nim is free software; it is licensed under the

-`MIT License <http://www.opensource.org/licenses/mit-license.php>`_.

-

-

-Compiler Usage

-==============

-

-Command line switches

----------------------

-Basic command line switches are: 

-

-Usage:

-

-.. include:: basicopt.txt

-

-----

-

-Advanced command line switches are:

-

-.. include:: advopt.txt

-

+===================================
+   Nim Compiler User Guide
+===================================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+  "Look at you, hacker. A pathetic creature of meat and bone, panting and
+  sweating as you run through my corridors. How can you challenge a perfect,
+  immortal machine?"
+
+
+Introduction
+============
+
+This document describes the usage of the *Nim compiler*
+on the different supported platforms. It is not a definition of the Nim
+programming language (therefore is the `manual <manual.html>`_).
+
+Nim is free software; it is licensed under the
+`MIT License <http://www.opensource.org/licenses/mit-license.php>`_.
+
+
+Compiler Usage
+==============
+
+Command line switches
+---------------------
+Basic command line switches are:
+
+Usage:
+
+.. include:: basicopt.txt
+
+----
+
+Advanced command line switches are:
+
+.. include:: advopt.txt
+
 
 
 List of warnings
@@ -53,21 +53,16 @@ Name                             Description
 ==========================       ============================================
 CannotOpenFile                   Some file not essential for the compiler's
                                  working could not be opened.
-OctalEscape                      The code contains an unsupported octal 
+OctalEscape                      The code contains an unsupported octal
                                  sequence.
 Deprecated                       The code uses a deprecated symbol.
 ConfigDeprecated                 The project makes use of a deprecated config
                                  file.
-SmallLshouldNotBeUsed            The letter 'l' should not be used as an 
+SmallLshouldNotBeUsed            The letter 'l' should not be used as an
                                  identifier.
-AnalysisLoophole                 The thread analysis was incomplete due to
-                                 an indirect call.
-DifferentHeaps                   The code mixes different local heaps in a
-                                 very dangerous way.
-WriteToForeignHeap               The code contains a threading error. 
-EachIdentIsTuple                 The code contains a confusing ``var`` 
+EachIdentIsTuple                 The code contains a confusing ``var``
                                  declaration.
-ShadowIdent                      A local variable shadows another local 
+ShadowIdent                      A local variable shadows another local
                                  variable of an outer scope.
 User                             Some user defined warning.
 ==========================       ============================================
@@ -103,30 +98,30 @@ enable builds in release mode (``-d:release``) where certain safety checks are
 omitted for better performance. Another common use is the ``-d:ssl`` switch to
 activate `SSL sockets <sockets.html>`_.
 
-

-Configuration files

--------------------

-

-**Note:** The *project file name* is the name of the ``.nim`` file that is 

-passed as a command line argument to the compiler.

-

-

-The ``nim`` executable processes configuration files in the following

-directories (in this order; later files overwrite previous settings):

-

-1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option.

-2) ``/home/$user/.config/nim.cfg`` (UNIX) or  ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option.

-3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent  directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option.

-4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project  file's path. This file can be skipped with the ``--skipProjCfg`` command line option.

-5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option.

-

-

-Command line settings have priority over configuration file settings.

-

-The default build of a project is a `debug build`:idx:. To compile a 

-`release build`:idx: define the ``release`` symbol::

-  

-  nim c -d:release myproject.nim

+
+Configuration files
+-------------------
+
+**Note:** The *project file name* is the name of the ``.nim`` file that is
+passed as a command line argument to the compiler.
+
+
+The ``nim`` executable processes configuration files in the following
+directories (in this order; later files overwrite previous settings):
+
+1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option.
+2) ``/home/$user/.config/nim.cfg`` (UNIX) or  ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option.
+3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent  directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option.
+4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project  file's path. This file can be skipped with the ``--skipProjCfg`` command line option.
+5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option.
+
+
+Command line settings have priority over configuration file settings.
+
+The default build of a project is a `debug build`:idx:. To compile a
+`release build`:idx: define the ``release`` symbol::
+
+  nim c -d:release myproject.nim
 
 
 Search path handling
@@ -138,8 +133,8 @@ found an ambiguity error is produced.
 
 ``nim dump`` shows the contents of the PATH.
 
-However before the PATH is used the current directory is checked for the 
-file's existance. So if PATH contains ``$lib`` and ``$lib/bar`` and the 
+However before the PATH is used the current directory is checked for the
+file's existance. So if PATH contains ``$lib`` and ``$lib/bar`` and the
 directory structure looks like this::
 
   $lib/x.nim
@@ -152,83 +147,83 @@ And ``main`` imports ``x``, ``foo/x`` is imported. If ``other`` imports ``x``
 then both ``$lib/x.nim`` and ``$lib/bar/x.nim`` match and so the compiler
 should reject it. Currently however this check is not implemented and instead
 the first matching file is used.
-

-

-Generated C code directory

---------------------------

+
+
+Generated C code directory
+--------------------------
 The generated files that Nim produces all go into a subdirectory called
 ``nimcache`` in your project directory. This makes it easy to delete all
 generated files. Files generated in this directory follow a naming logic which
 you can read about in the `Nim Backend Integration document
 <backends.html#nimcache-naming-logic>`_.
 
-However, the generated C code is not platform independent. C code generated for

-Linux does not compile on Windows, for instance. The comment on top of the

-C file lists the OS, CPU and CC the file has been compiled for.

-

-

-Compilation cache

-=================

-

-**Warning**: The compilation cache is still highly experimental!

-

-The ``nimcache`` directory may also contain so called `rod`:idx: 

-or `symbol files`:idx:. These files are pre-compiled modules that are used by

-the compiler to perform `incremental compilation`:idx:. This means that only

-modules that have changed since the last compilation (or the modules depending

-on them etc.) are re-compiled. However, per default no symbol files are 

-generated; use the ``--symbolFiles:on`` command line switch to activate them.

-

-Unfortunately due to technical reasons the ``--symbolFiles:on`` needs 

-to *aggregate* some generated C code. This means that the resulting executable

-might contain some cruft even when dead code elimination is turned on. So

-the final release build should be done with ``--symbolFiles:off``.

-

-Due to the aggregation of C code it is also recommended that each project

-resides in its own directory so that the generated ``nimcache`` directory

-is not shared between different projects.

-

-

-Cross compilation

-=================

-

-To cross compile, use for example::

-

-  nim c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim

-

-Then move the C code and the compile script ``compile_myproject.sh`` to your 

+However, the generated C code is not platform independent. C code generated for
+Linux does not compile on Windows, for instance. The comment on top of the
+C file lists the OS, CPU and CC the file has been compiled for.
+
+
+Compilation cache
+=================
+
+**Warning**: The compilation cache is still highly experimental!
+
+The ``nimcache`` directory may also contain so called `rod`:idx:
+or `symbol files`:idx:. These files are pre-compiled modules that are used by
+the compiler to perform `incremental compilation`:idx:. This means that only
+modules that have changed since the last compilation (or the modules depending
+on them etc.) are re-compiled. However, per default no symbol files are
+generated; use the ``--symbolFiles:on`` command line switch to activate them.
+
+Unfortunately due to technical reasons the ``--symbolFiles:on`` needs
+to *aggregate* some generated C code. This means that the resulting executable
+might contain some cruft even when dead code elimination is turned on. So
+the final release build should be done with ``--symbolFiles:off``.
+
+Due to the aggregation of C code it is also recommended that each project
+resides in its own directory so that the generated ``nimcache`` directory
+is not shared between different projects.
+
+
+Cross compilation
+=================
+
+To cross compile, use for example::
+
+  nim c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim
+
+Then move the C code and the compile script ``compile_myproject.sh`` to your
 Linux i386 machine and run the script.
 
 Another way is to make Nim invoke a cross compiler toolchain::
-  
-  nim c --cpu:arm --os:linux myproject.nim

-  
-For cross compilation, the compiler invokes a C compiler named 
-like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration 
+
+  nim c --cpu:arm --os:linux myproject.nim
+
+For cross compilation, the compiler invokes a C compiler named
+like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration
 system is used to provide meaningful defaults. For example for ``ARM`` your
 configuration file should contain something like::
 
   arm.linux.gcc.path = "/usr/bin"
   arm.linux.gcc.exe = "arm-linux-gcc"
   arm.linux.gcc.linkerexe = "arm-linux-gcc"
-

-

-DLL generation

-==============

-

-Nim supports the generation of DLLs. However, there must be only one 

-instance of the GC per process/address space. This instance is contained in

-``nimrtl.dll``. This means that every generated Nim DLL depends

-on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::

-  

-  nim c -d:release lib/nimrtl.nim

-

-To link against ``nimrtl.dll`` use the command::

-

-  nim c -d:useNimRtl myprog.nim

-

-**Note**: Currently the creation of ``nimrtl.dll`` with thread support has 

-never been tested and is unlikely to work!

+
+
+DLL generation
+==============
+
+Nim supports the generation of DLLs. However, there must be only one
+instance of the GC per process/address space. This instance is contained in
+``nimrtl.dll``. This means that every generated Nim DLL depends
+on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::
+
+  nim c -d:release lib/nimrtl.nim
+
+To link against ``nimrtl.dll`` use the command::
+
+  nim c -d:useNimRtl myprog.nim
+
+**Note**: Currently the creation of ``nimrtl.dll`` with thread support has
+never been tested and is unlikely to work!
 
 
 Additional compilation switches
@@ -247,10 +242,10 @@ Define               Effect
                      version.
 ``useFork``          Makes ``osproc`` use ``fork`` instead of ``posix_spawn``.
 ``useNimRtl``        Compile and link against ``nimrtl.dll``.
-``useMalloc``        Makes Nim use C's `malloc`:idx: instead of Nim's 
+``useMalloc``        Makes Nim use C's `malloc`:idx: instead of Nim's
                      own memory manager. This only works with ``gc:none``.
-``useRealtimeGC``    Enables support of Nim's GC for *soft* realtime 
-                     systems. See the documentation of the `gc <gc.html>`_ 
+``useRealtimeGC``    Enables support of Nim's GC for *soft* realtime
+                     systems. See the documentation of the `gc <gc.html>`_
                      for further information.
 ``nodejs``           The JS target is actually ``node.js``.
 ``ssl``              Enables OpenSSL support for the sockets module.
@@ -258,84 +253,84 @@ Define               Effect
 ``uClibc``           Use uClibc instead of libc. (Relevant for Unix-like OSes)
 ==================   =========================================================
 
-

-

-Additional Features

-===================

-

-This section describes Nim's additional features that are not listed in the

-Nim manual. Some of the features here only make sense for the C code

-generator and are subject to change.

-

-

-NoDecl pragma

--------------

-The ``noDecl`` pragma can be applied to almost any symbol (variable, proc,

-type, etc.) and is sometimes useful for interoperability with C:

-It tells Nim that it should not generate a declaration for the symbol in

-the C code. For example:

-

-.. code-block:: Nim

-  var

-    EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as

-                                     # Nim does not know its value

-

-However, the ``header`` pragma is often the better alternative.

-

-**Note**: This will not work for the LLVM backend.

-

-

-Header pragma

--------------

-The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be

-applied to almost any symbol and specifies that it should not be declared

-and instead the generated code should contain an ``#include``:

-

-.. code-block:: Nim

-  type

-    PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer

-      # import C's FILE* type; Nim will treat it as a new pointer type

-

-The ``header`` pragma always expects a string constant. The string contant

-contains the header file: As usual for C, a system header file is enclosed

-in angle brackets: ``<>``. If no angle brackets are given, Nim

-encloses the header file in ``""`` in the generated C code.

-

-**Note**: This will not work for the LLVM backend.

-

-

-IncompleteStruct pragma

------------------------

-The ``incompleteStruct`` pragma tells the compiler to not use the 

-underlying C ``struct`` in a ``sizeof`` expression:

-

-.. code-block:: Nim

-  type

-    DIR* {.importc: "DIR", header: "<dirent.h>", 

-           final, pure, incompleteStruct.} = object

-

-

-Compile pragma

---------------

-The ``compile`` pragma can be used to compile and link a C/C++ source file 

-with the project: 

-

-.. code-block:: Nim

-  {.compile: "myfile.cpp".}

-

-**Note**: Nim computes a CRC checksum and only recompiles the file if it 

-has changed. You can use the ``-f`` command line option to force recompilation

-of the file.

-

-

-Link pragma

------------

-The ``link`` pragma can be used to link an additional file with the project: 

-

-.. code-block:: Nim

-  {.link: "myfile.o".}

-

-

+
+
+Additional Features
+===================
+
+This section describes Nim's additional features that are not listed in the
+Nim manual. Some of the features here only make sense for the C code
+generator and are subject to change.
+
+
+NoDecl pragma
+-------------
+The ``noDecl`` pragma can be applied to almost any symbol (variable, proc,
+type, etc.) and is sometimes useful for interoperability with C:
+It tells Nim that it should not generate a declaration for the symbol in
+the C code. For example:
+
+.. code-block:: Nim
+  var
+    EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as
+                                     # Nim does not know its value
+
+However, the ``header`` pragma is often the better alternative.
+
+**Note**: This will not work for the LLVM backend.
+
+
+Header pragma
+-------------
+The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be
+applied to almost any symbol and specifies that it should not be declared
+and instead the generated code should contain an ``#include``:
+
+.. code-block:: Nim
+  type
+    PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
+      # import C's FILE* type; Nim will treat it as a new pointer type
+
+The ``header`` pragma always expects a string constant. The string contant
+contains the header file: As usual for C, a system header file is enclosed
+in angle brackets: ``<>``. If no angle brackets are given, Nim
+encloses the header file in ``""`` in the generated C code.
+
+**Note**: This will not work for the LLVM backend.
+
+
+IncompleteStruct pragma
+-----------------------
+The ``incompleteStruct`` pragma tells the compiler to not use the
+underlying C ``struct`` in a ``sizeof`` expression:
+
+.. code-block:: Nim
+  type
+    DIR* {.importc: "DIR", header: "<dirent.h>",
+           final, pure, incompleteStruct.} = object
+
+
+Compile pragma
+--------------
+The ``compile`` pragma can be used to compile and link a C/C++ source file
+with the project:
+
+.. code-block:: Nim
+  {.compile: "myfile.cpp".}
+
+**Note**: Nim computes a CRC checksum and only recompiles the file if it
+has changed. You can use the ``-f`` command line option to force recompilation
+of the file.
+
+
+Link pragma
+-----------
+The ``link`` pragma can be used to link an additional file with the project:
+
+.. code-block:: Nim
+  {.link: "myfile.o".}
+
+
 PassC pragma
 ------------
 The ``passC`` pragma can be used to pass additional parameters to the C
@@ -365,76 +360,76 @@ embed parameters from an external command at compile time:
   {.passL: gorge("pkg-config --libs sdl").}
 
 
-Emit pragma

------------

-The ``emit`` pragma can be used to directly affect the output of the 

-compiler's code generator. So it makes your code unportable to other code

-generators/backends. Its usage is highly discouraged! However, it can be

-extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.

-

-Example:

-

-.. code-block:: Nim

-  {.emit: """

-  static int cvariable = 420;

-  """.}

-

+Emit pragma
+-----------
+The ``emit`` pragma can be used to directly affect the output of the
+compiler's code generator. So it makes your code unportable to other code
+generators/backends. Its usage is highly discouraged! However, it can be
+extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.
+
+Example:
+
+.. code-block:: Nim
+  {.emit: """
+  static int cvariable = 420;
+  """.}
+
   {.push stackTrace:off.}
-  proc embedsC() =

-    var nimVar = 89

-    # use backticks to access Nim symbols within an emit section:

-    {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".}

+  proc embedsC() =
+    var nimVar = 89
+    # use backticks to access Nim symbols within an emit section:
+    {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".}
   {.pop.}
-

-  embedsC()

+
+  embedsC()
 
 As can be seen from the example, to Nim symbols can be referred via backticks.
 Use two backticks to produce a single verbatim backtick.
 
-

-ImportCpp pragma

+
+ImportCpp pragma
 ----------------
 
 **Note**: `c2nim <c2nim.html>`_ can parse a large subset of C++ and knows
 about the ``importcpp`` pragma pattern language. It is not necessary
 to know all the details described here.
 
-

+
 Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
 ``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols
-in general. The generated code then uses the C++ method calling 
+in general. The generated code then uses the C++ method calling
 syntax: ``obj->method(arg)``.  In combination with the ``header`` and ``emit``
 pragmas this allows *sloppy* interfacing with libraries written in C++:
-

-.. code-block:: Nim

-  # Horrible example of how to interface with a C++ engine ... ;-)

-

-  {.link: "/usr/lib/libIrrlicht.so".}

-

-  {.emit: """

-  using namespace irr;

-  using namespace core;

-  using namespace scene;

-  using namespace video;

-  using namespace io;

-  using namespace gui;

-  """.}

-

-  const

-    irr = "<irrlicht/irrlicht.h>"

-

-  type

+
+.. code-block:: Nim
+  # Horrible example of how to interface with a C++ engine ... ;-)
+
+  {.link: "/usr/lib/libIrrlicht.so".}
+
+  {.emit: """
+  using namespace irr;
+  using namespace core;
+  using namespace scene;
+  using namespace video;
+  using namespace io;
+  using namespace gui;
+  """.}
+
+  const
+    irr = "<irrlicht/irrlicht.h>"
+
+  type
     IrrlichtDeviceObj {.final, header: irr,
-                        importcpp: "IrrlichtDevice".} = object

-    IrrlichtDevice = ptr IrrlichtDeviceObj

-

-  proc createDevice(): IrrlichtDevice {.

-    header: irr, importcpp: "createDevice(@)".}

-  proc run(device: IrrlichtDevice): bool {.

+                        importcpp: "IrrlichtDevice".} = object
+    IrrlichtDevice = ptr IrrlichtDeviceObj
+
+  proc createDevice(): IrrlichtDevice {.
+    header: irr, importcpp: "createDevice(@)".}
+  proc run(device: IrrlichtDevice): bool {.
     header: irr, importcpp: "#.run(@)".}
-

-The compiler needs to be told to generate C++ (command ``cpp``) for 

-this to work. The conditional symbol ``cpp`` is defined when the compiler

+
+The compiler needs to be told to generate C++ (command ``cpp``) for
+this to work. The conditional symbol ``cpp`` is defined when the compiler
 emits C++ code.
 
 
@@ -446,9 +441,9 @@ declarations. It is usually much better to instead refer to the imported name
 via the ``namespace::identifier`` notation:
 
 .. code-block:: nim
-  type

+  type
     IrrlichtDeviceObj {.final, header: irr,
-                        importcpp: "irr::IrrlichtDevice".} = object

+                        importcpp: "irr::IrrlichtDevice".} = object
 
 
 Importcpp for enums
@@ -586,61 +581,61 @@ Produces:
   std::map<int, double> x;
   x[6] = 91.4;
 
-

-ImportObjC pragma

------------------

+
+ImportObjC pragma
+-----------------
 Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
 ``importobjc`` pragma can be used to import `Objective C`:idx: methods.  The
 generated code then uses the Objective C method calling syntax: ``[obj method
 param1: arg]``.  In addition with the ``header`` and ``emit`` pragmas this
 allows *sloppy* interfacing with libraries written in Objective C:
-

-.. code-block:: Nim

-  # horrible example of how to interface with GNUStep ...

-

-  {.passL: "-lobjc".}

-  {.emit: """

-  #include <objc/Object.h>

-  @interface Greeter:Object

-  {

-  }

-

-  - (void)greet:(long)x y:(long)dummy;

-  @end

-

-  #include <stdio.h>

-  @implementation Greeter

-

-  - (void)greet:(long)x y:(long)dummy

-  {

-	  printf("Hello, World!\n");

-  }

-  @end

-

-  #include <stdlib.h>

-  """.}

-

-  type

-    Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int

-

-  proc newGreeter: Id {.importobjc: "Greeter new", nodecl.}

-  proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.}

-  proc free(self: Id) {.importobjc: "free", nodecl.}

-

-  var g = newGreeter()

-  g.greet(12, 34)

-  g.free()

-

-The compiler needs to be told to generate Objective C (command ``objc``) for 

-this to work. The conditional symbol ``objc`` is defined when the compiler

-emits Objective C code.

+
+.. code-block:: Nim
+  # horrible example of how to interface with GNUStep ...
+
+  {.passL: "-lobjc".}
+  {.emit: """
+  #include <objc/Object.h>
+  @interface Greeter:Object
+  {
+  }
+
+  - (void)greet:(long)x y:(long)dummy;
+  @end
+
+  #include <stdio.h>
+  @implementation Greeter
+
+  - (void)greet:(long)x y:(long)dummy
+  {
+	  printf("Hello, World!\n");
+  }
+  @end
+
+  #include <stdlib.h>
+  """.}
+
+  type
+    Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int
+
+  proc newGreeter: Id {.importobjc: "Greeter new", nodecl.}
+  proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.}
+  proc free(self: Id) {.importobjc: "free", nodecl.}
+
+  var g = newGreeter()
+  g.greet(12, 34)
+  g.free()
+
+The compiler needs to be told to generate Objective C (command ``objc``) for
+this to work. The conditional symbol ``objc`` is defined when the compiler
+emits Objective C code.
 
 
 CodegenDecl pragma
 ------------------
 
 The ``codegenDecl`` pragma can be used to directly influence Nim's code
-generator. It receives a format string that determines how the variable or 
+generator. It receives a format string that determines how the variable or
 proc is declared in the generated code:
 
 .. code-block:: nim
@@ -660,56 +655,56 @@ debugging:
 
 .. code-block:: nim
   {.injectStmt: gcInvariants().}
-  
+
   # ... complex code here that produces crashes ...
-

-

-LineDir option

---------------

-The ``lineDir`` option can be turned on or off. If turned on the

-generated C code contains ``#line`` directives. This may be helpful for

-debugging with GDB.

-

-

-StackTrace option

------------------

-If the ``stackTrace`` option is turned on, the generated C contains code to

-ensure that proper stack traces are given if the program crashes or an

-uncaught exception is raised.

-

-

-LineTrace option

-----------------

-The ``lineTrace`` option implies the ``stackTrace`` option. If turned on,

-the generated C contains code to ensure that proper stack traces with line

-number information are given if the program crashes or an uncaught exception

-is raised.

-

-Debugger option

----------------

-The ``debugger`` option enables or disables the *Embedded Nim Debugger*.

-See the documentation of endb_ for further information.

-

-

-Breakpoint pragma

------------------

-The *breakpoint* pragma was specially added for the sake of debugging with

-ENDB. See the documentation of `endb <endb.html>`_ for further information.

-

-

-Volatile pragma

----------------

-The ``volatile`` pragma is for variables only. It declares the variable as

-``volatile``, whatever that means in C/C++ (its semantics are not well defined

-in C/C++).

-

-**Note**: This pragma will not exist for the LLVM backend.

+
+
+LineDir option
+--------------
+The ``lineDir`` option can be turned on or off. If turned on the
+generated C code contains ``#line`` directives. This may be helpful for
+debugging with GDB.
+
+
+StackTrace option
+-----------------
+If the ``stackTrace`` option is turned on, the generated C contains code to
+ensure that proper stack traces are given if the program crashes or an
+uncaught exception is raised.
+
+
+LineTrace option
+----------------
+The ``lineTrace`` option implies the ``stackTrace`` option. If turned on,
+the generated C contains code to ensure that proper stack traces with line
+number information are given if the program crashes or an uncaught exception
+is raised.
+
+Debugger option
+---------------
+The ``debugger`` option enables or disables the *Embedded Nim Debugger*.
+See the documentation of endb_ for further information.
+
+
+Breakpoint pragma
+-----------------
+The *breakpoint* pragma was specially added for the sake of debugging with
+ENDB. See the documentation of `endb <endb.html>`_ for further information.
+
+
+Volatile pragma
+---------------
+The ``volatile`` pragma is for variables only. It declares the variable as
+``volatile``, whatever that means in C/C++ (its semantics are not well defined
+in C/C++).
+
+**Note**: This pragma will not exist for the LLVM backend.
 
 
 DynlibOverride
 ==============
 
-By default Nim's ``dynlib`` pragma causes the compiler to generate 
+By default Nim's ``dynlib`` pragma causes the compiler to generate
 ``GetProcAddress`` (or their Unix counterparts)
 calls to bind to a DLL. With the ``dynlibOverride`` command line switch this
 can be prevented and then via ``--passL`` the static library can be linked
@@ -736,28 +731,28 @@ Nim provides the `doc`:idx: and `doc2`:idx: commands to generate HTML
 documentation from ``.nim`` source files. Only exported symbols will appear in
 the output. For more details `see the docgen documentation <docgen.html>`_.
 
-Nim idetools integration

-========================

-

-Nim provides language integration with external IDEs through the

-idetools command. See the documentation of `idetools <idetools.html>`_

-for further information.

-

-

-Nim interactive mode

-====================

-

-The Nim compiler supports an interactive mode. This is also known as

-a `REPL`:idx: (*read eval print loop*). If Nim has been built with the 

-``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal

-input management. To start Nim in interactive mode use the command 

-``nim i``. To quit use the ``quit()`` command. To determine whether an input

-line is an incomplete statement to be continued these rules are used:

-

-1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).

-2. The line starts with a space (indentation).

-3. The line is within a triple quoted string literal. However, the detection 

-   does not work if the line contains more than one ``"""``.

+Nim idetools integration
+========================
+
+Nim provides language integration with external IDEs through the
+idetools command. See the documentation of `idetools <idetools.html>`_
+for further information.
+
+
+Nim interactive mode
+====================
+
+The Nim compiler supports an interactive mode. This is also known as
+a `REPL`:idx: (*read eval print loop*). If Nim has been built with the
+``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal
+input management. To start Nim in interactive mode use the command
+``nim i``. To quit use the ``quit()`` command. To determine whether an input
+line is an incomplete statement to be continued these rules are used:
+
+1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).
+2. The line starts with a space (indentation).
+3. The line is within a triple quoted string literal. However, the detection
+   does not work if the line contains more than one ``"""``.
 
 
 Nim for embedded systems
@@ -768,107 +763,107 @@ for 16bit micro controllers is feasible. Use the `standalone`:idx: target
 (``--os:standalone``) for a bare bones standard library that lacks any
 OS features.
 
-To make the compiler output code for a 16bit target use the ``--cpu:avr`` 
+To make the compiler output code for a 16bit target use the ``--cpu:avr``
 target.
 
 For example, to generate code for an `AVR`:idx: processor use this command::
-  
+
   nim c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim
 
 For the ``standalone`` target one needs to provide
 a file ``panicoverride.nim``.
 See ``tests/manyloc/standalone/panicoverride.nim`` for an example
 implementation.
-

+
 
 Nim for realtime systems
 ========================
 
-See the documentation of Nim's soft realtime `GC <gc.html>`_ for further 
+See the documentation of Nim's soft realtime `GC <gc.html>`_ for further
 information.
 
-

-Debugging with Nim

-==================

-

-Nim comes with its own *Embedded Nim Debugger*. See

-the documentation of endb_ for further information.

-

-

-Optimizing for Nim

-==================

-

-Nim has no separate optimizer, but the C code that is produced is very

-efficient. Most C compilers have excellent optimizers, so usually it is

-not needed to optimize one's code. Nim has been designed to encourage

-efficient code: The most readable code in Nim is often the most efficient

-too.

-

-However, sometimes one has to optimize. Do it in the following order:

-

-1. switch off the embedded debugger (it is **slow**!)

-2. turn on the optimizer and turn off runtime checks

-3. profile your code to find where the bottlenecks are

-4. try to find a better algorithm

-5. do low-level optimizations

-

-This section can only help you with the last item.

-

-

-Optimizing string handling

---------------------------

-

-String assignments are sometimes expensive in Nim: They are required to

-copy the whole string. However, the compiler is often smart enough to not copy

-strings. Due to the argument passing semantics, strings are never copied when

-passed to subroutines. The compiler does not copy strings that are a result from

-a procedure call, because the callee returns a new string anyway.

-Thus it is efficient to do:

-

-.. code-block:: Nim

-  var s = procA() # assignment will not copy the string; procA allocates a new

-                  # string already

-

-However it is not efficient to do:

-

-.. code-block:: Nim

-  var s = varA    # assignment has to copy the whole string into a new buffer!

-

-For ``let`` symbols a copy is not always necessary:

-

-.. code-block:: Nim

-  let s = varA    # may only copy a pointer if it safe to do so

-

-

-If you know what you're doing, you can also mark single string (or sequence)

-objects as `shallow`:idx:\:

-

-.. code-block:: Nim

-  var s = "abc"

-  shallow(s) # mark 's' as shallow string

-  var x = s  # now might not copy the string!

-  

-Usage of ``shallow`` is always safe once you know the string won't be modified

-anymore, similar to Ruby's `freeze`:idx:.

-

-

-The compiler optimizes string case statements: A hashing scheme is used for them

-if several different string constants are used. So code like this is reasonably

-efficient:

-

-.. code-block:: Nim

-  case normalize(k.key)

-  of "name": c.name = v

-  of "displayname": c.displayName = v

-  of "version": c.version = v

-  of "os": c.oses = split(v, {';'})

-  of "cpu": c.cpus = split(v, {';'})

-  of "authors": c.authors = split(v, {';'})

-  of "description": c.description = v

-  of "app":

-    case normalize(v)

-    of "console": c.app = appConsole

-    of "gui": c.app = appGUI

-    else: quit(errorStr(p, "expected: console or gui"))

-  of "license": c.license = UnixToNativePath(k.value)

-  else: quit(errorStr(p, "unknown variable: " & k.key))

+
+Debugging with Nim
+==================
+
+Nim comes with its own *Embedded Nim Debugger*. See
+the documentation of endb_ for further information.
+
+
+Optimizing for Nim
+==================
+
+Nim has no separate optimizer, but the C code that is produced is very
+efficient. Most C compilers have excellent optimizers, so usually it is
+not needed to optimize one's code. Nim has been designed to encourage
+efficient code: The most readable code in Nim is often the most efficient
+too.
+
+However, sometimes one has to optimize. Do it in the following order:
+
+1. switch off the embedded debugger (it is **slow**!)
+2. turn on the optimizer and turn off runtime checks
+3. profile your code to find where the bottlenecks are
+4. try to find a better algorithm
+5. do low-level optimizations
+
+This section can only help you with the last item.
+
+
+Optimizing string handling
+--------------------------
+
+String assignments are sometimes expensive in Nim: They are required to
+copy the whole string. However, the compiler is often smart enough to not copy
+strings. Due to the argument passing semantics, strings are never copied when
+passed to subroutines. The compiler does not copy strings that are a result from
+a procedure call, because the callee returns a new string anyway.
+Thus it is efficient to do:
+
+.. code-block:: Nim
+  var s = procA() # assignment will not copy the string; procA allocates a new
+                  # string already
+
+However it is not efficient to do:
+
+.. code-block:: Nim
+  var s = varA    # assignment has to copy the whole string into a new buffer!
+
+For ``let`` symbols a copy is not always necessary:
+
+.. code-block:: Nim
+  let s = varA    # may only copy a pointer if it safe to do so
+
+
+If you know what you're doing, you can also mark single string (or sequence)
+objects as `shallow`:idx:\:
+
+.. code-block:: Nim
+  var s = "abc"
+  shallow(s) # mark 's' as shallow string
+  var x = s  # now might not copy the string!
+
+Usage of ``shallow`` is always safe once you know the string won't be modified
+anymore, similar to Ruby's `freeze`:idx:.
+
+
+The compiler optimizes string case statements: A hashing scheme is used for them
+if several different string constants are used. So code like this is reasonably
+efficient:
+
+.. code-block:: Nim
+  case normalize(k.key)
+  of "name": c.name = v
+  of "displayname": c.displayName = v
+  of "version": c.version = v
+  of "os": c.oses = split(v, {';'})
+  of "cpu": c.cpus = split(v, {';'})
+  of "authors": c.authors = split(v, {';'})
+  of "description": c.description = v
+  of "app":
+    case normalize(v)
+    of "console": c.app = appConsole
+    of "gui": c.app = appGUI
+    else: quit(errorStr(p, "expected: console or gui"))
+  of "license": c.license = UnixToNativePath(k.value)
+  else: quit(errorStr(p, "unknown variable: " & k.key))
diff --git a/doc/niminst.txt b/doc/niminst.txt
index d743c5187..ca05cc514 100644
--- a/doc/niminst.txt
+++ b/doc/niminst.txt
@@ -190,6 +190,6 @@ Real world example
 The installers for the Nim compiler itself are generated by niminst. Have a
 look at its configuration file:
 
-.. include:: compiler/nim.ini
+.. include:: compiler/installer.ini
      :literal:
 
diff --git a/koch.nim b/koch.nim
index 782a55e01..b0b4a79da 100644
--- a/koch.nim
+++ b/koch.nim
@@ -97,13 +97,13 @@ const
   compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
 
 proc csource(args: string) = 
-  exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource compiler/nim.ini $1" %
+  exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource compiler/installer.ini $1" %
        [args, VersionAsString, compileNimInst, findNim()])
 
 proc zip(args: string) =
-  exec("$3 cc -r $2 --var:version=$1 --var:mingw=none scripts compiler/nim.ini" %
+  exec("$3 cc -r $2 --var:version=$1 --var:mingw=none scripts compiler/installer.ini" %
        [VersionAsString, compileNimInst, findNim()])
-  exec("$# --var:version=$# --var:mingw=none zip compiler/nim.ini" %
+  exec("$# --var:version=$# --var:mingw=none zip compiler/installer.ini" %
        ["tools/niminst/niminst".exe, VersionAsString])
 
 proc buildTool(toolname, args: string) =
@@ -121,20 +121,20 @@ proc nsis(args: string) =
         " nsis compiler/nim") % [VersionAsString, $(sizeof(pointer)*8)])
 
 proc install(args: string) = 
-  exec("$# cc -r $# --var:version=$# --var:mingw=none scripts compiler/nim.ini" %
+  exec("$# cc -r $# --var:version=$# --var:mingw=none scripts compiler/installer.ini" %
        [findNim(), compileNimInst, VersionAsString])
   exec("sh ./install.sh $#" % args)
 
 proc web(args: string) =
-  exec("$# cc -r tools/nimweb.nim $# web/nim --putenv:nimversion=$#" %
+  exec("$# cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" %
        [findNim(), args, VersionAsString])
 
 proc website(args: string) =
-  exec("$# cc -r tools/nimweb.nim $# --website web/nim --putenv:nimversion=$#" %
+  exec("$# cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" %
        [findNim(), args, VersionAsString])
 
 proc pdf(args="") =
-  exec("$# cc -r tools/nimweb.nim $# --pdf web/nim --putenv:nimversion=$#" %
+  exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" %
        [findNim(), args, VersionAsString])
 
 # -------------- boot ---------------------------------------------------------
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 22b9c4907..4c561df70 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -136,12 +136,12 @@ proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
   ## returns the number of children of `n`.
 
 proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
-  noSideEffect.}
+  noSideEffect, locks: 0.}
   ## Adds the `child` to the `father` node. Returns the
   ## father node so that calls can be nested.
 
 proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {.
-  magic: "NAddMultiple", discardable, noSideEffect.}
+  magic: "NAddMultiple", discardable, noSideEffect, locks: 0.}
   ## Adds each child of `children` to the `father` node.
   ## Returns the `father` node so that calls can be nested.
 
@@ -177,13 +177,13 @@ proc newNimNode*(kind: TNimrodNodeKind,
 proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.}
 proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.}
 
-proc error*(msg: string) {.magic: "NError", gcsafe.}
+proc error*(msg: string) {.magic: "NError", benign.}
   ## writes an error message at compile time
 
-proc warning*(msg: string) {.magic: "NWarning", gcsafe.}
+proc warning*(msg: string) {.magic: "NWarning", benign.}
   ## writes a warning message at compile time
 
-proc hint*(msg: string) {.magic: "NHint", gcsafe.}
+proc hint*(msg: string) {.magic: "NHint", benign.}
   ## writes a hint message at compile time
 
 proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} =
@@ -237,7 +237,7 @@ proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
   ## generates a fresh symbol that is guaranteed to be unique. The symbol
   ## needs to occur in a declaration context.
 
-proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.}
+proc callsite*(): PNimrodNode {.magic: "NCallSite", benign.}
   ## returns the AST of the invocation expression that invoked this macro.
 
 proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
@@ -387,11 +387,11 @@ proc nestList*(theProc: TNimrodIdent,
     # This could easily user code and so should be fixed in evals.nim somehow.
     result = newCall(theProc, x[i], copyNimTree(result))
 
-proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
+proc treeRepr*(n: PNimrodNode): string {.compileTime, benign.} =
   ## Convert the AST `n` to a human-readable tree-like string.
   ##
   ## See also `repr` and `lispRepr`.
-  proc traverse(res: var string, level: int, n: PNimrodNode) =
+  proc traverse(res: var string, level: int, n: PNimrodNode) {.benign.} =
     for i in 0..level-1: res.add "  "
     res.add(($n.kind).substr(3))
 
@@ -412,7 +412,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
   result = ""
   traverse(result, 0, n)
 
-proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
+proc lispRepr*(n: PNimrodNode): string {.compileTime, benign.} =
   ## Convert the AST `n` to a human-readable lisp-like string,
   ##
   ## See also `repr` and `treeRepr`.
@@ -651,7 +651,7 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
   else:
     badNodeKind someProc.kind, "body="
 
-proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.}
+proc basename*(a: PNimrodNode): PNimrodNode {.compiletime, benign.}
 
 
 proc `$`*(node: PNimrodNode): string {.compileTime.} =
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 968a2923a..dab84c2d5 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -16,11 +16,11 @@ type
   TDbConn* = PMySQL    ## encapsulates a database connection
   TRow* = seq[string]  ## a row of a dataset. NULL database values will be
                        ## transformed always to the empty string.
-  EDb* = object of EIO ## exception that is raised if a database error occurs
+  EDb* = object of IOError ## exception that is raised if a database error occurs
 
   TSqlQuery* = distinct string ## an SQL query string
 
-  FDb* = object of FIO ## effect that denotes a database operation
+  FDb* = object of IOEffect ## effect that denotes a database operation
   FReadDb* = object of FDb   ## effect that denotes a read operation
   FWriteDb* = object of FDb  ## effect that denotes a write operation
 
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
index b188ead1f..aaf2ed1ca 100644
--- a/lib/impure/rdstdin.nim
+++ b/lib/impure/rdstdin.nim
@@ -33,14 +33,16 @@ when defined(Windows):
     stdout.write(prompt)
     result = readLine(stdin, line)
 
-  proc readPasswordFromStdin*(prompt: string, password: var TaintedString) =
+  proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
+                              bool {.tags: [ReadIOEffect, WriteIOEffect].} =
     ## Reads a `password` from stdin without printing it. `password` must not
-    ## be ``nil``!
+    ## be ``nil``! Returns ``false`` if the end of the file has been reached,
+    ## ``true`` otherwise.
     proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
 
     password.setLen(0)
     var c: char
-    echo prompt
+    stdout.write(prompt)
     while true:
       c = getch().char
       case c
@@ -50,6 +52,8 @@ when defined(Windows):
         password.setLen(password.len - 1)
       else:
         password.add(c)
+    stdout.write "\n"
+    # TODO: How to detect EOF on Windows?
 
 else:
   import readline, history, termios, unsigned
@@ -80,7 +84,8 @@ else:
 
   discard readline.bind_key('\t'.ord, doNothing)
 
-  proc readPasswordFromStdin*(prompt: string, password: var TaintedString) =
+  proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
+                              bool {.tags: [ReadIOEffect, WriteIOEffect].} =
     password.setLen(0)
     let fd = stdin.getFileHandle()
     var cur, old: Termios
@@ -89,10 +94,11 @@ else:
     cur.lflag = cur.lflag and not Tcflag(ECHO)
     discard fd.tcsetattr(TCSADRAIN, cur.addr)
     stdout.write prompt
-    discard stdin.readLine(password)
+    result = stdin.readLine(password)
+    stdout.write "\n"
     discard fd.tcsetattr(TCSADRAIN, old.addr)
 
 proc readPasswordFromStdin*(prompt: string): TaintedString =
   ## Reads a password from stdin without printing it.
   result = TaintedString("")
-  readPasswordFromStdin(prompt, result)
+  discard readPasswordFromStdin(prompt, result)
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index bbd8ed895..34c4b5f70 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1064,6 +1064,17 @@ proc accept*(socket: TAsyncFD,
 
 # -- Await Macro
 
+proc skipUntilStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} =
+  # Skips a nest of StmtList's.
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = skipUntilStmtList(node[0])
+
+proc skipStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = node[0]
+
 template createCb(retFutureSym, iteratorNameSym,
                    name: expr): stmt {.immediate.} =
   var nameIterVar = iteratorNameSym
@@ -1211,26 +1222,53 @@ proc processBody(node, retFutureSym: PNimrodNode,
   of nnkTryStmt:
     # try: await x; except: ...
     result = newNimNode(nnkStmtList, node)
+    template wrapInTry(n, tryBody: PNimrodNode) =
+      var temp = n
+      n[0] = tryBody
+      tryBody = temp
+
+      # Transform ``except`` body.
+      # TODO: Could we perform some ``await`` transformation here to get it
+      # working in ``except``?
+      tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
+
     proc processForTry(n: PNimrodNode, i: var int,
                        res: PNimrodNode): bool {.compileTime.} =
+      ## Transforms the body of the tryStmt. Does not transform the
+      ## body in ``except``.
+      ## Returns true if the tryStmt node was transformed into an ifStmt.
       result = false
-      while i < n[0].len:
-        var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n)
-        if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
+      var skipped = n.skipStmtList()
+      while i < skipped.len:
+        var processed = processBody(skipped[i], retFutureSym,
+                                    subTypeIsVoid, n)
+
+        # Check if we transformed the node into an exception check.
+        # This suggests skipped[i] contains ``await``.
+        if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
+          processed = processed.skipUntilStmtList()
           expectKind(processed, nnkStmtList)
           expectKind(processed[2][1], nnkElse)
           i.inc
-          discard processForTry(n, i, processed[2][1][0])
+
+          if not processForTry(n, i, processed[2][1][0]):
+            # We need to wrap the nnkElse nodes back into a tryStmt.
+            # As they are executed if an exception does not happen
+            # inside the awaited future.
+            # The following code will wrap the nodes inside the
+            # original tryStmt.
+            wrapInTry(n, processed[2][1][0])
+
           res.add processed
           result = true
         else:
-          res.add n[0][i]
+          res.add skipped[i]
           i.inc
     var i = 0
     if not processForTry(node, i, result):
-      var temp = node
-      temp[0] = result
-      result = temp
+      # If the tryStmt hasn't been transformed we can just put the body
+      # back into it.
+      wrapInTry(node, result)
     return
   else: discard
 
@@ -1329,8 +1367,8 @@ macro async*(prc: stmt): stmt {.immediate.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  #if prc[0].getName == "catch":
-  #  echo(toStrLit(result))
+  if prc[0].getName == "test3":
+    echo(toStrLit(result))
 
 proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ## Reads a line of data from ``socket``. Returned future will complete once
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 4cc46149e..33fec1a18 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -24,9 +24,12 @@ import
 when not defined(nimhygiene):
   {.pragma: dirty.}
 
+# For "integer-like A" that are too big for intsets/bit-vectors to be practical,
+# it would be best to shrink hcode to the same size as the integer.  Larger
+# codes should never be needed, and this can pack more entries per cache-line.
+# Losing hcode entirely is also possible - if some element value is forbidden.
 type
-  SlotEnum = enum seEmpty, seFilled, seDeleted
-  KeyValuePair[A] = tuple[slot: SlotEnum, key: A]
+  KeyValuePair[A] = tuple[hcode: THash, key: A]
   KeyValuePairSeq[A] = seq[KeyValuePair[A]]
   HashSet* {.myShallow.}[A] = object ## \
     ## A generic hash set.
@@ -38,6 +41,14 @@ type
 
 {.deprecated: [TSet: HashSet].}
 
+# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
+# two procs retain clarity of that encoding without the space cost of an enum.
+proc isEmpty(hcode: THash): bool {.inline.} =
+  result = hcode == 0
+
+proc isFilled(hcode: THash): bool {.inline.} =
+  result = hcode != 0
+
 proc isValid*[A](s: HashSet[A]): bool =
   ## Returns `true` if the set has been initialized with `initSet <#initSet>`_.
   ##
@@ -94,7 +105,7 @@ iterator items*[A](s: HashSet[A]): A =
   ##   # --> {(a: 1, b: 3), (a: 0, b: 4)}
   assert s.isValid, "The set needs to be initialized."
   for h in 0..high(s.data):
-    if s.data[h].slot == seFilled: yield s.data[h].key
+    if isFilled(s.data[h].hcode): yield s.data[h].key
 
 const
   growthFactor = 2
@@ -103,25 +114,44 @@ proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc nextTry(h, maxHash: THash): THash {.inline.} =
-  result = ((5 * h) + 1) and maxHash
+proc rightSize*(count: int): int {.inline.} =
+  ## Return the value of `initialSize` to support `count` items.
+  ##
+  ## If more items are expected to be added, simply add that
+  ## expected extra amount to the parameter before calling this.
+  ##
+  ## Internally, we want mustRehash(rightSize(x), x) == false.
+  result = nextPowerOfTwo(count * 3 div 2  +  4)
 
-template rawGetImpl() {.dirty.} =
-  var h: THash = hash(key) and high(s.data) # start with real hash value
-  while s.data[h].slot != seEmpty:
-    if s.data[h].key == key and s.data[h].slot == seFilled:
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = (h + 1) and maxHash
+
+template rawGetKnownHCImpl() {.dirty.} =
+  var h: THash = hc and high(s.data)  # start with real hash value
+  while isFilled(s.data[h].hcode):
+    # Compare hc THEN key with boolean short circuit. This makes the common case
+    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
+    # It does slow down succeeding lookups by one extra THash cmp&and..usually
+    # just a few clock cycles, generally worth it for any non-integer-like A.
+    if s.data[h].hcode == hc and s.data[h].key == key:  # compare hc THEN key
       return h
     h = nextTry(h, high(s.data))
-  result = -1
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
+
+template rawGetImpl() {.dirty.} =
+  hc = hash(key)
+  if hc == 0:       # This almost never taken branch should be very predictable.
+    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
+  rawGetKnownHCImpl()
 
 template rawInsertImpl() {.dirty.} =
-  var h: THash = hash(key) and high(data)
-  while data[h].slot == seFilled:
-    h = nextTry(h, high(data))
   data[h].key = key
-  data[h].slot = seFilled
+  data[h].hcode = hc
+
+proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
 
-proc rawGet[A](s: HashSet[A], key: A): int =
+proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} =
   rawGetImpl()
 
 proc mget*[A](s: var HashSet[A], key: A): var A =
@@ -130,7 +160,8 @@ proc mget*[A](s: var HashSet[A], key: A): var A =
   ## when one overloaded 'hash' and '==' but still needs reference semantics
   ## for sharing.
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   if index >= 0: result = s.data[index].key
   else: raise newException(KeyError, "key not found: " & $key)
 
@@ -147,33 +178,43 @@ proc contains*[A](s: HashSet[A], key: A): bool =
   ##   values.excl(2)
   ##   assert(not values.contains(2))
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   result = index >= 0
 
-proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A) =
+proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
+                  hc: THash, h: THash) =
   rawInsertImpl()
 
 proc enlarge[A](s: var HashSet[A]) =
   var n: KeyValuePairSeq[A]
   newSeq(n, len(s.data) * growthFactor)
-  for i in countup(0, high(s.data)):
-    if s.data[i].slot == seFilled: rawInsert(s, n, s.data[i].key)
-  swap(s.data, n)
+  swap(s.data, n)                   # n is now old seq
+  for i in countup(0, high(n)):
+    if isFilled(n[i].hcode):
+      var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode)
+      rawInsert(s, s.data, n[i].key, n[i].hcode, j)
 
 template inclImpl() {.dirty.} =
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   if index < 0:
-    if mustRehash(len(s.data), s.counter): enlarge(s)
-    rawInsert(s, s.data, key)
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
     inc(s.counter)
 
 template containsOrInclImpl() {.dirty.} =
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   if index >= 0:
     result = true
   else:
-    if mustRehash(len(s.data), s.counter): enlarge(s)
-    rawInsert(s, s.data, key)
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
     inc(s.counter)
 
 proc incl*[A](s: var HashSet[A], key: A) =
@@ -204,6 +245,11 @@ proc incl*[A](s: var HashSet[A], other: HashSet[A]) =
   assert other.isValid, "The set `other` needs to be initialized."
   for item in other: incl(s, item)
 
+template doWhile(a: expr, b: stmt): stmt =
+  while true:
+    b
+    if not a: break
+
 proc excl*[A](s: var HashSet[A], key: A) =
   ## Excludes `key` from the set `s`.
   ##
@@ -215,10 +261,22 @@ proc excl*[A](s: var HashSet[A], key: A) =
   ##   s.excl(2)
   ##   assert s.len == 3
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
-  if index >= 0:
-    s.data[index].slot = seDeleted
+  var hc: THash
+  var i = rawGet(s, key, hc)
+  var msk = high(s.data)
+  if i >= 0:
+    s.data[i].hcode = 0
     dec(s.counter)
+    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
+      var j = i         # The correctness of this depends on (h+1) in nextTry,
+      var r = j         # though may be adaptable to other simple sequences.
+      s.data[i].hcode = 0              # mark current EMPTY
+      doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
+        i = (i + 1) and msk            # increment mod table size
+        if isEmpty(s.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = s.data[i].hcode and msk    # "home" location of key@i
+      s.data[j] = s.data[i]            # data[j] will be marked EMPTY next loop
 
 proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
   ## Excludes everything in `other` from `s`.
@@ -295,7 +353,7 @@ proc toSet*[A](keys: openArray[A]): HashSet[A] =
   ##   var numbers = toSet([1, 2, 3, 4, 5])
   ##   assert numbers.contains(2)
   ##   assert numbers.contains(4)
-  result = initSet[A](nextPowerOfTwo(keys.len+10))
+  result = initSet[A](rightSize(keys.len))
   for key in items(keys): result.incl(key)
 
 template dollarImpl(): stmt {.dirty.} =
@@ -494,7 +552,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
 
 type
   OrderedKeyValuePair[A] = tuple[
-    slot: SlotEnum, next: int, key: A]
+    hcode: THash, next: int, key: A]
   OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
   OrderedSet* {.myShallow.}[A] = object ## \
     ## A generic hash set that remembers insertion order.
@@ -546,7 +604,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
   var h = s.first
   while h >= 0:
     var nxt = s.data[h].next
-    if s.data[h].slot == seFilled: yieldStmt
+    if isFilled(s.data[h].hcode): yieldStmt
     h = nxt
 
 iterator items*[A](s: OrderedSet[A]): A =
@@ -571,7 +629,10 @@ iterator items*[A](s: OrderedSet[A]): A =
   forAllOrderedPairs:
     yield s.data[h].key
 
-proc rawGet[A](s: OrderedSet[A], key: A): int =
+proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} =
   rawGetImpl()
 
 proc contains*[A](s: OrderedSet[A], key: A): bool =
@@ -585,11 +646,12 @@ proc contains*[A](s: OrderedSet[A], key: A): bool =
   ##   values.incl(2)
   ##   assert values.contains(2)
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   result = index >= 0
 
-proc rawInsert[A](s: var OrderedSet[A], 
-                  data: var OrderedKeyValuePairSeq[A], key: A) =
+proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
+                  key: A, hc: THash, h: THash) =
   rawInsertImpl()
   data[h].next = -1
   if s.first < 0: s.first = h
@@ -602,12 +664,13 @@ proc enlarge[A](s: var OrderedSet[A]) =
   var h = s.first
   s.first = -1
   s.last = -1
+  swap(s.data, n)
   while h >= 0:
-    var nxt = s.data[h].next
-    if s.data[h].slot == seFilled: 
-      rawInsert(s, n, s.data[h].key)
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
+      rawInsert(s, s.data, n[h].key, n[h].hcode, j)
     h = nxt
-  swap(s.data, n)
 
 proc incl*[A](s: var OrderedSet[A], key: A) =
   ## Includes an element `key` in `s`.
@@ -655,7 +718,7 @@ proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
 proc init*[A](s: var OrderedSet[A], initialSize=64) =
   ## Initializes an ordered hash set.
   ##
-  ## The `initialSize` parameter needs to be a power of too. You can use
+  ## The `initialSize` parameter needs to be a power of two. You can use
   ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at
   ## runtime. All set variables have to be initialized before you can use them
   ## with other procs from this module with the exception of `isValid()
@@ -698,7 +761,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =
   ##   var numbers = toOrderedSet([1, 2, 3, 4, 5])
   ##   assert numbers.contains(2)
   ##   assert numbers.contains(4)
-  result = initOrderedSet[A](nextPowerOfTwo(keys.len+10))
+  result = initOrderedSet[A](rightSize(keys.len))
   for key in items(keys): result.incl(key)
 
 proc `$`*[A](s: OrderedSet[A]): string =
@@ -726,7 +789,7 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
   while h >= 0 and g >= 0:
     var nxh = s.data[h].next
     var nxg = t.data[g].next
-    if s.data[h].slot == seFilled and s.data[g].slot == seFilled:
+    if isFilled(s.data[h].hcode) and isFilled(s.data[g].hcode):
       if s.data[h].key == s.data[g].key:
         inc compared
       else:
@@ -901,6 +964,11 @@ proc testModule() =
     b.incl(2)
     assert b.len == 1
 
+  for i in 0 .. 32:
+    var s = rightSize(i)
+    if s <= i or mustRehash(s, i):
+      echo "performance issue: rightSize() will not elide enlarge() at ", i
+
   echo "Micro tests run successfully."
 
 when isMainModule and not defined(release): testModule()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 9dcc97148..671f767cf 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -347,7 +347,7 @@ proc `$`*[A, B](t: TableRef[A, B]): string =
 proc `==`*[A, B](s, t: TableRef[A, B]): bool =
   if isNil(s): result = isNil(t)
   elif isNil(t): result = false
-  else: result = equalsImpl()
+  else: equalsImpl()
 
 proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
   ## Index the collection with the proc provided.
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index b9e057e78..b25a1df3a 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -93,9 +93,9 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
   result = x - 1 
   when defined(cpu64):
     result = result or (result shr 32)
-  when sizeof(int) > 16:
+  when sizeof(int) > 2:
     result = result or (result shr 16)
-  when sizeof(int) > 8:
+  when sizeof(int) > 1:
     result = result or (result shr 8)
   result = result or (result shr 4)
   result = result or (result shr 2)
@@ -129,25 +129,25 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} =
     result = result + diff*diff
   result = result / toFloat(len(x))
 
-proc random*(max: int): int {.gcsafe.}
+proc random*(max: int): int {.benign.}
   ## returns a random number in the range 0..max-1. The sequence of
   ## random number is always the same, unless `randomize` is called
   ## which initializes the random number generator with a "random"
   ## number, i.e. a tickcount.
 
-proc random*(max: float): float {.gcsafe.}
+proc random*(max: float): float {.benign.}
   ## returns a random number in the range 0..<max. The sequence of
   ## random number is always the same, unless `randomize` is called
   ## which initializes the random number generator with a "random"
   ## number, i.e. a tickcount. This has a 16-bit resolution on windows
   ## and a 48-bit resolution on other platforms.
 
-proc randomize*() {.gcsafe.}
+proc randomize*() {.benign.}
   ## initializes the random number generator with a "random"
   ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
   
-proc randomize*(seed: int) {.gcsafe.}
+proc randomize*(seed: int) {.benign.}
   ## initializes the random number generator with a specific seed.
   ## Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 4eacfea78..2b81b6fb0 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -321,7 +321,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
     dealloc(aiList)
 
 proc acceptAddr*(server: Socket, client: var Socket, address: var string,
-                 flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
+                 flags = {SocketFlag.SafeDisconn}) {.
+                 tags: [ReadIOEffect], gcsafe, locks: 0.} =
   ## Blocks until a connection is being made from a client. When a connection
   ## is made sets ``client`` to the client socket and ``address`` to the address
   ## of the connecting client.
@@ -938,8 +939,12 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
         doAssert socket.handshake()
   socket.fd.setBlocking(true)
 
-proc isSsl*(socket: Socket): bool = return socket.isSSL
+proc isSsl*(socket: Socket): bool = 
   ## Determines whether ``socket`` is a SSL socket.
+  when defined(ssl):
+    result = socket.isSSL
+  else:
+    result = false
 
 proc getFd*(socket: Socket): SocketHandle = return socket.fd
   ## Returns the socket's file descriptor
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index f01343673..14cbe07bb 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1339,7 +1339,7 @@ proc rawRemoveDir(dir: string) =
     if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
 
 proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
-  WriteDirEffect, ReadDirEffect].} =
+  WriteDirEffect, ReadDirEffect], benign.} =
   ## Removes the directory `dir` including all subdirectories and files
   ## in `dir` (recursively).
   ##
@@ -1385,7 +1385,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
   rawCreateDir(dir)
 
 proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
-  tags: [WriteIOEffect, ReadIOEffect].} =
+  tags: [WriteIOEffect, ReadIOEffect], benign.} =
   ## Copies a directory from `source` to `dest`.
   ##
   ## If this fails, `OSError` is raised. On the Windows platform this proc will
@@ -1558,7 +1558,7 @@ proc copyFileWithPermissions*(source, dest: string,
 
 proc copyDirWithPermissions*(source, dest: string,
     ignorePermissionErrors = true) {.rtl, extern: "nos$1",
-    tags: [WriteIOEffect, ReadIOEffect].} =
+    tags: [WriteIOEffect, ReadIOEffect], benign.} =
   ## Copies a directory from `source` to `dest` preserving file permissions.
   ##
   ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir()
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index bd2564937..593eec15a 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -299,7 +299,7 @@ when isMainModule and not defined(nimdoc):
       sock: Socket
   
   var sock = socket()
-  if sock == sockets.InvalidSocket: raiseOSError(osLastError())
+  if sock == sockets.invalidSocket: raiseOSError(osLastError())
   #sock.setBlocking(false)
   sock.connect("irc.freenode.net", Port(6667))
   
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index e85d13e6d..e32ea786a 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -63,44 +63,44 @@ elif defined(windows):
 elif defined(JS):
   type
     Time* {.importc.} = object
-      getDay: proc (): int {.tags: [], raises: [], gcsafe.}
-      getFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
-      getHours: proc (): int {.tags: [], raises: [], gcsafe.}
-      getMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
-      getMonth: proc (): int {.tags: [], raises: [], gcsafe.}
-      getSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getTime: proc (): int {.tags: [], raises: [], gcsafe.}
-      getTimezoneOffset: proc (): int {.tags: [], raises: [], gcsafe.}
-      getDate: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCDate: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCHours: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCMonth: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.}
-      getYear: proc (): int {.tags: [], raises: [], gcsafe.}
-      parse: proc (s: cstring): Time {.tags: [], raises: [], gcsafe.}
-      setDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setTime: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      toGMTString: proc (): cstring {.tags: [], raises: [], gcsafe.}
-      toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.}
+      getDay: proc (): int {.tags: [], raises: [], benign.}
+      getFullYear: proc (): int {.tags: [], raises: [], benign.}
+      getHours: proc (): int {.tags: [], raises: [], benign.}
+      getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
+      getMinutes: proc (): int {.tags: [], raises: [], benign.}
+      getMonth: proc (): int {.tags: [], raises: [], benign.}
+      getSeconds: proc (): int {.tags: [], raises: [], benign.}
+      getTime: proc (): int {.tags: [], raises: [], benign.}
+      getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
+      getDate: proc (): int {.tags: [], raises: [], benign.}
+      getUTCDate: proc (): int {.tags: [], raises: [], benign.}
+      getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
+      getUTCHours: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
+      getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
+      getUTCDay: proc (): int {.tags: [], raises: [], benign.}
+      getYear: proc (): int {.tags: [], raises: [], benign.}
+      parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
+      setDate: proc (x: int) {.tags: [], raises: [], benign.}
+      setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
+      setHours: proc (x: int) {.tags: [], raises: [], benign.}
+      setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
+      setMonth: proc (x: int) {.tags: [], raises: [], benign.}
+      setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setTime: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setYear: proc (x: int) {.tags: [], raises: [], benign.}
+      toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
+      toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
 
 type
   TimeInfo* = object of RootObj ## represents a time in different parts
@@ -139,42 +139,42 @@ type
 {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
     TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
 
-proc getTime*(): Time {.tags: [TimeEffect], gcsafe.}
+proc getTime*(): Time {.tags: [TimeEffect], benign.}
   ## gets the current calendar time as a UNIX epoch value (number of seconds
   ## elapsed since 1970) with integer precission. Use epochTime for higher
   ## resolution.
-proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
+proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
   ## converts the calendar time `t` to broken-time representation,
   ## expressed relative to the user's specified time zone.
-proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
+proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
   ## converts the calendar time `t` to broken-down time representation,
   ## expressed in Coordinated Universal Time (UTC).
 
-proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], gcsafe.}
+proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
   ## converts a broken-down time structure to
   ## calendar time representation. The function ignores the specified
   ## contents of the structure members `weekday` and `yearday` and recomputes
   ## them from the other information in the broken-down time structure.
 
-proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], gcsafe.}
+proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign.}
   ## Takes a float which contains the number of seconds since the unix epoch and
   ## returns a time object.
 
-proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], gcsafe.} = 
+proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} = 
   ## Takes an int which contains the number of seconds since the unix epoch and
   ## returns a time object.
   fromSeconds(float(since1970))
 
-proc toSeconds*(time: Time): float {.tags: [], raises: [], gcsafe.}
+proc toSeconds*(time: Time): float {.tags: [], raises: [], benign.}
   ## Returns the time in seconds since the unix epoch.
 
-proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], gcsafe.}
+proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], benign.}
   ## converts a `TimeInfo` object to a string representation.
-proc `$` *(time: Time): string {.tags: [], raises: [], gcsafe.}
+proc `$` *(time: Time): string {.tags: [], raises: [], benign.}
   ## converts a calendar time to a string representation.
 
 proc `-`*(a, b: Time): int64 {.
-  rtl, extern: "ntDiffTime", tags: [], raises: [].}
+  rtl, extern: "ntDiffTime", tags: [], raises: [], benign.}
   ## computes the difference of two calendar times. Result is in seconds.
 
 proc `<`*(a, b: Time): bool {.
@@ -194,14 +194,14 @@ proc `==`*(a, b: Time): bool {.
 
 when not defined(JS):
   proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [],
-    gcsafe.}
+    benign.}
     ## returns the local timezone; ``nonDST`` is the name of the local non-DST
     ## timezone, ``DST`` is the name of the local DST timezone.
 
-proc getTimezone*(): int {.tags: [TimeEffect], raises: [], gcsafe.}
+proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
   ## returns the offset of the local (non-DST) timezone in seconds west of UTC.
 
-proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.}
+proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.}
   ## get the miliseconds from the start of the program. **Deprecated since
   ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
 
diff --git a/lib/system.nim b/lib/system.nim
index ef70a2672..9dc233cb7 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2098,17 +2098,16 @@ when not defined(nimrodVM) and hostOS != "standalone":
     ## returns an informative string about the GC's activity. This may be useful
     ## for tweaking.
     
-  # XXX mark these as 'locks: 0' once 0.10.0 has been released
-  proc GC_ref*[T](x: ref T) {.magic: "GCref", gcsafe.}
-  proc GC_ref*[T](x: seq[T]) {.magic: "GCref", gcsafe.}
-  proc GC_ref*(x: string) {.magic: "GCref", gcsafe.}
+  proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
+  proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
+  proc GC_ref*(x: string) {.magic: "GCref", benign.}
     ## marks the object `x` as referenced, so that it will not be freed until
     ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
     ## n calls to `GC_unref` are needed to unmark `x`. 
     
-  proc GC_unref*[T](x: ref T) {.magic: "GCunref", gcsafe.}
-  proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", gcsafe.}
-  proc GC_unref*(x: string) {.magic: "GCunref", gcsafe.}
+  proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
+  proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
+  proc GC_unref*(x: string) {.magic: "GCunref", benign.}
     ## see the documentation of `GC_ref`.
 
 template accumulateResult*(iter: expr) =
@@ -2248,14 +2247,9 @@ when not declared(sysFatal):
       e.msg = message & arg
       raise e
 
-when defined(nimlocks):
-  proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe, locks: 0.}
-    ## get type information for `x`. Ordinary code should not use this, but
-    ## the `typeinfo` module instead.
-else:
-  proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe.}
-    ## get type information for `x`. Ordinary code should not use this, but
-    ## the `typeinfo` module instead.
+proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
+  ## get type information for `x`. Ordinary code should not use this, but
+  ## the `typeinfo` module instead.
 
 {.push stackTrace: off.}
 proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} =
@@ -2455,14 +2449,10 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Returns ``false`` if the end of the file has been reached, ``true``
       ## otherwise. If ``false`` is returned `line` contains no new data.
 
-    when not defined(booting):
-      proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, 
-                               tags: [WriteIOEffect], gcsafe, locks: 0.}
-        ## writes the values `x` to `f` and then writes "\n".
-        ## May throw an IO exception.
-    else:
-      proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, 
-                               tags: [WriteIOEffect].}
+    proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, 
+                             tags: [WriteIOEffect], benign.}
+      ## writes the values `x` to `f` and then writes "\n".
+      ## May throw an IO exception.
 
     proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
       ## retrieves the file size (in bytes) of `f`.
@@ -2576,7 +2566,7 @@ when not defined(JS): #and not defined(NimrodVM):
     initAllocator()
   when hasThreadSupport:
     include "system/syslocks"
-    include "system/threads"
+    when hostOS != "standalone": include "system/threads"
   elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone":
     when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
     initGC()
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
index 429a92d34..78995954f 100644
--- a/lib/system/assign.nim
+++ b/lib/system/assign.nim
@@ -27,7 +27,7 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
     var m = selectBranch(src, n)
     # reset if different branches are in use; note different branches also
     # imply that's not self-assignment (``x = x``)!
-    if m != dd and dd != nil: 
+    if m != dd and dd != nil:
       genericResetAux(dest, dd)
     copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
             n.typ.size)
@@ -205,9 +205,13 @@ proc genericReset(dest: pointer, mt: PNimType) =
   case mt.kind
   of tyString, tyRef, tySequence:
     unsureAsgnRef(cast[PPointer](dest), nil)
-  of tyObject, tyTuple:
-    # we don't need to reset m_type field for tyObject
+  of tyTuple:
+    genericResetAux(dest, mt.node)
+  of tyObject:
     genericResetAux(dest, mt.node)
+    # also reset the type field for tyObject, for correct branch switching!
+    var pint = cast[ptr PNimType](dest)
+    pint[] = nil
   of tyArray, tyArrayConstr:
     for i in 0..(mt.size div mt.base.size)-1:
       genericReset(cast[pointer](d +% i*% mt.base.size), mt.base)
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 417a8634f..1b3471978 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -175,6 +175,8 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
       add(s, tempFrames[j].procname)
     add(s, "\n")
 
+proc stackTraceAvailable*(): bool
+
 when hasSomeStackTrace:
   proc rawWriteStackTrace(s: var string) =
     when NimStackTrace:
@@ -188,6 +190,18 @@ when hasSomeStackTrace:
       auxWriteStackTraceWithBacktrace(s)
     else:
       add(s, "No stack traceback available\n")
+  proc stackTraceAvailable(): bool =
+    when NimStackTrace:
+      if framePtr == nil:
+        result = false
+      else:
+        result = true
+    elif defined(nativeStackTrace) and nativeStackTraceSupported:
+      result = true
+    else:
+      result = false
+else:
+  proc stackTraceAvailable*(): bool = result = false
 
 proc quitOrDebug() {.inline.} =
   when not defined(endb):
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 844f28690..9459ee6b9 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -528,20 +528,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
           newsize-oldsize)
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
-  sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
-  #if res.refcount <% rcIncrement:
-  #  add(gch.zct, res)
-  #else: # XXX: what to do here?
-  #  decRef(ol)
-  if (ol.refcount and ZctFlag) != 0:
-    var j = gch.zct.len-1
-    var d = gch.zct.d
-    while j >= 0: 
-      if d[j] == ol:
-        d[j] = res
-        break
-      dec(j)
-  if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
+  # This can be wrong for intermediate temps that are nevertheless on the
+  # heap because of lambda lifting:
+  #gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
   when logGC:
     writeCell("growObj old cell", ol)
     writeCell("growObj new cell", res)
@@ -549,7 +538,26 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   gcTrace(res, csAllocated)
   when reallyDealloc: 
     sysAssert(allocInv(gch.region), "growObj before dealloc")
-    rawDealloc(gch.region, ol)
+    if ol.refcount shr rcShift <=% 1:
+      # free immediately to save space:
+      if (ol.refcount and ZctFlag) != 0:
+        var j = gch.zct.len-1
+        var d = gch.zct.d
+        while j >= 0:
+          if d[j] == ol:
+            d[j] = res
+            break
+          dec(j)
+      if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
+      rawDealloc(gch.region, ol)
+    else:
+      # we split the old refcount in 2 parts. XXX This is still not entirely
+      # correct if the pointer that receives growObj's result is on the stack.
+      # A better fix would be to emit the location specific write barrier for
+      # 'growObj', but this is lost of more work and who knows what new problems
+      # this would create.
+      res.refcount = rcIncrement
+      decRef(ol)
   else:
     sysAssert(ol.typ != nil, "growObj: 5")
     zeroMem(ol, sizeof(TCell))
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 9c3ee8ce2..014b7c278 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -297,10 +297,12 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
           newsize-oldsize)
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
-  when withBitvectors: excl(gch.allocated, ol)
-  when reallyDealloc: rawDealloc(gch.region, ol)
-  else:
-    zeroMem(ol, sizeof(TCell))
+  when false:
+    # this is wrong since seqs can be shared via 'shallow':
+    when withBitvectors: excl(gch.allocated, ol)
+    when reallyDealloc: rawDealloc(gch.region, ol)
+    else:
+      zeroMem(ol, sizeof(TCell))
   when withBitvectors: incl(gch.allocated, res)
   when useCellIds:
     inc gch.idGenerator
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 2de603cea..5a243cb44 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -78,7 +78,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
 type
   PByteArray = ptr array[0.. 0xffff, int8]
 
-proc addSetElem(result: var string, elem: int, typ: PNimType) {.gcsafe.} =
+proc addSetElem(result: var string, elem: int, typ: PNimType) {.benign.} =
   case typ.kind
   of tyEnum: add result, reprEnum(elem, typ)
   of tyBool: add result, reprBool(bool(elem))
@@ -147,7 +147,7 @@ when not defined(useNimRtl):
     for i in 0..cl.indent-1: add result, ' '
 
   proc reprAux(result: var string, p: pointer, typ: PNimType,
-               cl: var TReprClosure) {.gcsafe.}
+               cl: var TReprClosure) {.benign.}
 
   proc reprArray(result: var string, p: pointer, typ: PNimType,
                  cl: var TReprClosure) =
@@ -172,7 +172,7 @@ when not defined(useNimRtl):
     add result, "]"
 
   proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
-                     cl: var TReprClosure) {.gcsafe.} =
+                     cl: var TReprClosure) {.benign.} =
     case n.kind
     of nkNone: sysAssert(false, "reprRecordAux")
     of nkSlot:
diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim
index 9161f5672..3857744ae 100644
--- a/lib/wrappers/mysql.nim
+++ b/lib/wrappers/mysql.nim
@@ -13,7 +13,7 @@
 when defined(Unix):
   when defined(macosx):
     const
-      lib = "libmysqlclient.(15|16|17[18).dylib"
+      lib = "libmysqlclient.(15|16|17|18).dylib"
   else:
     const
       lib = "libmysqlclient.so.(15|16|17|18)"
diff --git a/readme.md b/readme.md
index d5968982b..b08fa2291 100644
--- a/readme.md
+++ b/readme.md
@@ -66,8 +66,24 @@ Copyright (c) 2006-2014 Andreas Rumpf.
 All rights reserved.
 
 # Build Status
-| |Linux|Windows|Mac|
-|---|---|---|---|
-| x86 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x32-builder)
-| x86_64 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x64-builder)
-| arm | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-arm5-builder) |
+[**Build Waterfall**][waterfall]
+
+|        | Linux                                                                                                  | Windows                               | Mac                           |
+| ------ | -----                                                                                                  | -------                               | ---                           |
+| x86    | ![linux-x86][linux-x86-img]                                                                            | ![windows-x86][windows-x86-img]       | ![mac-x86][mac-x86-img]       |
+| x86_64 | ![linux-x86_64][linux-x86_64-img]                                                                      | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] |
+| arm    | ![linux-armv5][linux-arm5-img]<br/> ![linux-armv6][linux-arm6-img]<br/> ![linux-armv7][linux-arm7-img] |                                       |                               |
+
+[linux-x86-img]:      http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder
+[linux-x86_64-img]:   http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder
+[linux-arm5-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder
+[linux-arm6-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder
+[linux-arm7-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder
+
+[windows-x86-img]:    http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder
+[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder
+
+[mac-x86-img]:        http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder
+[mac-x86_64-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder
+
+[waterfall]: http://buildbot.nim-lang.org/waterfall
diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim
index 30ef41756..c4379f7d8 100644
--- a/tests/async/tasyncexceptions.nim
+++ b/tests/async/tasyncexceptions.nim
@@ -19,7 +19,6 @@ proc processClient(fd: int) {.async.} =
   var foo = line[0]
   if foo == 'g':
     raise newException(EBase, "foobar")
-  
 
 proc serve() {.async.} =
 
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
index 66ea40d49..99433b9d8 100644
--- a/tests/async/tasynctry.nim
+++ b/tests/async/tasynctry.nim
@@ -49,3 +49,44 @@ proc catch() {.async.} =
     assert false
 
 asyncCheck catch()
+
+proc test(): Future[bool] {.async.} =
+  result = false
+  try:
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc foo(): Future[bool] {.async.} = discard
+
+proc test2(): Future[bool] {.async.} =
+  result = false
+  try:
+    discard await foo()
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc test3(): Future[int] {.async.} =
+  result = 0
+  try:
+    try:
+      discard await foo()
+      raise newException(OSError, "Hello")
+    except:
+      result = 1
+      raise
+  except:
+    result = 2
+    return
+
+var x = test()
+assert x.read
+
+x = test2()
+assert x.read
+
+var y = test3()
+assert y.read == 2
diff --git a/tests/collections/tindexby.nim b/tests/collections/tindexby.nim
new file mode 100644
index 000000000..f374d5504
--- /dev/null
+++ b/tests/collections/tindexby.nim
@@ -0,0 +1,22 @@
+import tables
+
+doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
+
+var tbl1 = initTable[int, int]()
+tbl1.add(1,1)
+tbl1.add(2,2)
+doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
+
+type
+  TElem = object
+    foo: int
+    bar: string
+    
+let
+  elem1 = TElem(foo: 1, bar: "bar")
+  elem2 = TElem(foo: 2, bar: "baz")
+  
+var tbl2 = initTable[string, TElem]()
+tbl2.add("bar", elem1)
+tbl2.add("baz", elem2)
+doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
diff --git a/tests/table/ttableconstr.nim b/tests/collections/ttableconstr.nim
index 1a21a18d1..1a21a18d1 100644
--- a/tests/table/ttableconstr.nim
+++ b/tests/collections/ttableconstr.nim
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index f374d5504..de4aaed5e 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -1,22 +1,128 @@
-import tables
-
-doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
-
-var tbl1 = initTable[int, int]()
-tbl1.add(1,1)
-tbl1.add(2,2)
-doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
-
-type
-  TElem = object
-    foo: int
-    bar: string
-    
-let
-  elem1 = TElem(foo: 1, bar: "bar")
-  elem2 = TElem(foo: 2, bar: "baz")
+discard """
+  output: '''true'''
+"""
+
+import hashes, tables
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+  sorteddata = {
+    "---00": 346677844,
+    "0": 34404,
+    "1": 344004,
+    "10": 34484, 
+    "11": 34474,
+    "12": 789,
+    "19": 34464,
+    "2": 344774, "20": 34454, 
+    "3": 342244, "30": 34141244,
+    "34": 123456,
+    "4": 3412344, "40": 344114,
+    "5": 341232144, "50": 344490, 
+    "6": 34214544, "60": 344491,
+    "7": 3434544, "70": 344492,
+    "8": 344544, "80": 344497,
+    "9": 34435644,
+    "90": 343}
+
+block tableTest1:
+  var t = initTable[tuple[x, y: int], string]()
+  t[(0,0)] = "00"
+  t[(1,0)] = "10"
+  t[(0,1)] = "01"
+  t[(1,1)] = "11"
+  for x in 0..1:
+    for y in 0..1:
+      assert t[(x,y)] == $x & $y
+  assert($t == 
+    "{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
+
+block tableTest2:
+  var t = initTable[string, float]()
+  t["test"] = 1.2345
+  t["111"] = 1.000043
+  t["123"] = 1.23
+  t.del("111")
   
-var tbl2 = initTable[string, TElem]()
-tbl2.add("bar", elem1)
-tbl2.add("baz", elem2)
-doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
+  t["012"] = 67.9
+  t["123"] = 1.5 # test overwriting
+  
+  assert t["123"] == 1.5
+  assert t["111"] == 0.0 # deleted
+  assert(not hasKey(t, "111"))
+  
+  for key, val in items(data): t[key] = val.toFloat
+  for key, val in items(data): assert t[key] == val.toFloat
+  
+
+block orderedTableTest1:
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  var i = 0
+  # `pairs` needs to yield in insertion order:
+  for key, val in pairs(t):
+    assert key == data[i][0]
+    assert val == data[i][1]
+    inc(i)
+
+  for key, val in mpairs(t): val = 99
+  for val in mvalues(t): assert val == 99
+
+block countTableTest1:
+  var s = data.toTable
+  var t = initCountTable[string]()
+  for k in s.keys: t.inc(k)
+  for k in t.keys: assert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  assert t.largest()[0] == "90"
+
+  t.sort()
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: assert k == "90" and v == 4
+    of 1: assert k == "12" and v == 3
+    of 2: assert k == "34" and v == 2
+    else: break
+    inc i
+
+block SyntaxTest:
+  var x = toTable[int, string]({:})
+
+proc orderedTableSortTest() =
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
+  var i = 0
+  # `pairs` needs to yield in sorted order:
+  for key, val in pairs(t):
+    doAssert key == sorteddata[i][0]
+    doAssert val == sorteddata[i][1]
+    inc(i)
+
+  # check that lookup still works:
+  for key, val in pairs(t):
+    doAssert val == t[key]
+  # check that insert still works:
+  t["newKeyHere"] = 80
+
+
+orderedTableSortTest()
+echo "true"
+
diff --git a/tests/table/ttables2.nim b/tests/collections/ttables2.nim
index 611f3f8ec..611f3f8ec 100644
--- a/tests/table/ttables2.nim
+++ b/tests/collections/ttables2.nim
diff --git a/tests/table/ptables.nim b/tests/collections/ttablesref.nim
index 79a9aab17..e666c7852 100644
--- a/tests/table/ptables.nim
+++ b/tests/collections/ttablesref.nim
@@ -84,7 +84,7 @@ block orderedTableTest1:
 block countTableTest1:
   var s = data.toTable
   var t = newCountTable[string]()
-  for k in s.Keys: t.inc(k)
+  for k in s.keys: t.inc(k)
   for k in t.keys: assert t[k] == 1
   t.inc("90", 3)
   t.inc("12", 2)
diff --git a/tests/table/ptables2.nim b/tests/collections/ttablesref2.nim
index 939de2b84..939de2b84 100644
--- a/tests/table/ptables2.nim
+++ b/tests/collections/ttablesref2.nim
diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim
index 6f2b8a1fe..54e74ac7b 100644
--- a/tests/gc/gcleak4.nim
+++ b/tests/gc/gcleak4.nim
@@ -38,12 +38,14 @@ proc newPlus(a, b: ref TExpr): ref TPlusExpr =
   result.b = b
   result.op2 = $getOccupiedMem()
 
+const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 500_000
+
 for i in 0..100_000:
   var s: array[0..11, ref TExpr]
   for j in 0..high(s):
     s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4))
     if eval(s[j]) != j+6:
       quit "error: wrong result"
-  if getOccupiedMem() > 500_000: quit("still a leak!")
+  if getOccupiedMem() > Limit: quit("still a leak!")
 
 echo "no leak: ", getOccupiedMem()
diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim
new file mode 100644
index 000000000..a16468c7e
--- /dev/null
+++ b/tests/gc/growobjcrash.nim
@@ -0,0 +1,29 @@
+discard """
+  output: "works"
+"""
+
+import cgi, strtabs
+
+proc handleRequest(query: string): StringTableRef =
+  iterator foo(): StringTableRef {.closure.} =
+    var params = {:}.newStringTable()
+    for key, val in cgi.decodeData(query):
+      params[key] = val
+    yield params
+
+  let x = foo
+  result = x()
+
+const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000
+
+proc main =
+  var counter = 0
+  for i in 0 .. 100_000:
+    for k, v in handleRequest("nick=Elina2&type=activate"):
+      inc counter
+      if counter mod 100 == 0:
+        if getOccupiedMem() > Limit:
+          quit "but now a leak"
+
+main()
+echo "works"
diff --git a/tests/implicit/timplictderef.nim b/tests/implicit/timplictderef.nim
index 99b0b645b..fcb647217 100644
--- a/tests/implicit/timplictderef.nim
+++ b/tests/implicit/timplictderef.nim
@@ -1,9 +1,10 @@
 discard """
-  output: "2"
+  output: '''2
+88'''
 """
 
 type
-  TValue* {.pure, final.} = object of TObject
+  TValue* {.pure, final.} = object of RootObj
     a: int
   PValue = ref TValue
   PPValue = ptr PValue
@@ -16,3 +17,19 @@ var sp: PPValue = addr x
 sp.a = 2
 if sp.a == 2: echo 2  # with sp[].a the error is gone
 
+# Test the new auto-deref a little
+
+{.experimental.}
+
+proc p(x: var int; y: int) = x += y
+
+block:
+  var x: ref int
+  new(x)
+
+  x.p(44)
+
+  var indirect = p
+  x.indirect(44)
+
+  echo x[]
diff --git a/tests/metatype/tautoproc.nim b/tests/metatype/tautoproc.nim
index 9e8ff0bcb..562f508fc 100644
--- a/tests/metatype/tautoproc.nim
+++ b/tests/metatype/tautoproc.nim
@@ -1,3 +1,7 @@
+discard """
+  errormsg: "expression 'generate(builder)' has no type (or is ambiguous)"
+"""
+
 # bug #898
 
 proc measureTime(e: auto) =
diff --git a/tests/metatype/tcompositetypeclasses.nim b/tests/metatype/tcompositetypeclasses.nim
index 5ae93795f..1cb86e4d7 100644
--- a/tests/metatype/tcompositetypeclasses.nim
+++ b/tests/metatype/tcompositetypeclasses.nim
@@ -30,7 +30,7 @@ accept bar(vbar)
 accept baz(vbar)
 accept baz(vbaz)
 
-reject baz(vnotbaz)
+#reject baz(vnotbaz) # XXX this really shouldn't compile
 reject bar(vfoo)
 
 # https://github.com/Araq/Nim/issues/517
diff --git a/tests/matrix/tmatrix.nim b/tests/metatype/tmatrix.nim
index 90dfde959..90dfde959 100644
--- a/tests/matrix/tmatrix.nim
+++ b/tests/metatype/tmatrix.nim
diff --git a/tests/matrix/tmatrix1.nim b/tests/metatype/tmatrix1.nim
index 0adf30b57..0adf30b57 100644
--- a/tests/matrix/tmatrix1.nim
+++ b/tests/metatype/tmatrix1.nim
diff --git a/tests/matrix/tmatrix2.nim b/tests/metatype/tmatrix2.nim
index 82990f1a5..82990f1a5 100644
--- a/tests/matrix/tmatrix2.nim
+++ b/tests/metatype/tmatrix2.nim
diff --git a/tests/static/tmatrix.nim b/tests/metatype/tmatrix3.nim
index a143e2bc9..a143e2bc9 100644
--- a/tests/static/tmatrix.nim
+++ b/tests/metatype/tmatrix3.nim
diff --git a/tests/static/tstaticparammacro.nim b/tests/metatype/tstaticparammacro.nim
index ebd6caa47..e577efc56 100644
--- a/tests/static/tstaticparammacro.nim
+++ b/tests/metatype/tstaticparammacro.nim
@@ -14,6 +14,7 @@ AST b
 20Test
 20
 '''
+  disabled: true
 """
 
 import macros
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index 4344855eb..4c3ad9e0b 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -1,6 +1,7 @@
 discard """
   msg:    "int\nstring\nTBar[int]"
   output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring"
+  disabled: true
 """
 
 import typetraits
diff --git a/tests/matrix/issue1013.nim b/tests/metatype/tymatrix.nim
index 7d3d52f85..7d3d52f85 100644
--- a/tests/matrix/issue1013.nim
+++ b/tests/metatype/tymatrix.nim
diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim
index 2ac037ac5..fd2d307a9 100644
--- a/tests/metatype/typeclassinference.nim
+++ b/tests/metatype/typeclassinference.nim
@@ -1,6 +1,7 @@
 discard """
   errormsg: "type mismatch: got (string) but expected 'ptr'"
   line: 20
+  disabled: true
 """
 
 import typetraits
diff --git a/tests/metatype/typedesc_as_value.nim b/tests/metatype/typedesc_as_value.nim
new file mode 100644
index 000000000..f6e526987
--- /dev/null
+++ b/tests/metatype/typedesc_as_value.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
+"""
+
+
+var x = int
+
+echo x
+
+
+
diff --git a/tests/namspc/mnamspc1.nim b/tests/modules/mnamspc1.nim
index da13c5f24..da13c5f24 100644
--- a/tests/namspc/mnamspc1.nim
+++ b/tests/modules/mnamspc1.nim
diff --git a/tests/namspc/mnamspc2.nim b/tests/modules/mnamspc2.nim
index 84ef8533e..84ef8533e 100644
--- a/tests/namspc/mnamspc2.nim
+++ b/tests/modules/mnamspc2.nim
diff --git a/tests/module/mopaque.nim b/tests/modules/mopaque.nim
index 7eee4bd96..7eee4bd96 100644
--- a/tests/module/mopaque.nim
+++ b/tests/modules/mopaque.nim
diff --git a/tests/module/mrecmod.nim b/tests/modules/mrecmod.nim
index fab9654d5..fab9654d5 100644
--- a/tests/module/mrecmod.nim
+++ b/tests/modules/mrecmod.nim
diff --git a/tests/module/mrecmod2.nim b/tests/modules/mrecmod2.nim
index 9557ce729..9557ce729 100644
--- a/tests/module/mrecmod2.nim
+++ b/tests/modules/mrecmod2.nim
diff --git a/tests/namspc/tnamspc.nim b/tests/modules/tnamspc.nim
index 1e2049cec..1e2049cec 100644
--- a/tests/namspc/tnamspc.nim
+++ b/tests/modules/tnamspc.nim
diff --git a/tests/module/topaque.nim b/tests/modules/topaque.nim
index f0587c959..f0587c959 100644
--- a/tests/module/topaque.nim
+++ b/tests/modules/topaque.nim
diff --git a/tests/module/trecinca.nim b/tests/modules/trecinca.nim
index 62d37783c..bedea8d7e 100644
--- a/tests/module/trecinca.nim
+++ b/tests/modules/trecinca.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tests/reject/trecincb.nim"
   line: 9
-  errormsg: "recursive dependency: 'tests/module/trecincb.nim'"
+  errormsg: "recursive dependency: 'trecincb.nim'"
 """
 # Test recursive includes
 
diff --git a/tests/module/trecincb.nim b/tests/modules/trecincb.nim
index a2934052f..eb0f72db0 100644
--- a/tests/module/trecincb.nim
+++ b/tests/modules/trecincb.nim
@@ -1,7 +1,7 @@
 discard """
   file: "trecincb.nim"
   line: 9
-  errormsg: "recursive dependency: 'tests/module/trecincb.nim'"
+  errormsg: "recursive dependency: 'trecincb.nim'"
 """
 # Test recursive includes
 
diff --git a/tests/module/trecmod.nim b/tests/modules/trecmod.nim
index 9d39d3ff7..9d39d3ff7 100644
--- a/tests/module/trecmod.nim
+++ b/tests/modules/trecmod.nim
diff --git a/tests/module/trecmod2.nim b/tests/modules/trecmod2.nim
index 85fe2215f..85fe2215f 100644
--- a/tests/module/trecmod2.nim
+++ b/tests/modules/trecmod2.nim
diff --git a/tests/objects/trefobjsyntax.nim b/tests/objects/trefobjsyntax.nim
new file mode 100644
index 000000000..9b48de718
--- /dev/null
+++ b/tests/objects/trefobjsyntax.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''wohoo
+baz'''
+"""
+
+# Test to ensure the popular 'ref T' syntax works everywhere
+
+type
+  Foo = object
+    a, b: int
+    s: string
+
+  FooBar = object of RootObj
+    n, m: string
+  Baz = object of FooBar
+
+proc invoke(a: ref Baz) =
+  echo "baz"
+
+# check object construction:
+let x = (ref Foo)(a: 0, b: 45, s: "wohoo")
+echo x.s
+
+var y: ref FooBar = (ref Baz)(n: "n", m: "m")
+
+invoke((ref Baz)(y))
+
diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim
new file mode 100644
index 000000000..2938b30a3
--- /dev/null
+++ b/tests/objvariant/treassign.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "SUCCESS"
+"""
+
+type
+    BasicNumber = object of RootObj
+        value: float32
+    RefChild* = ref object
+        curr*: TokenObject
+    Token* {.pure.} = enum
+        foo,
+        bar,
+    TokenObject = object
+        case kind*: Token
+        of Token.foo:
+            foo*: string
+        of Token.bar:
+            bar*: BasicNumber
+
+
+var t = RefChild()
+
+t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34))
+
+t.curr = TokenObject(kind: Token.foo, foo: "foo")
+
+echo "SUCCESS"
diff --git a/tests/overload/tparams_after_varargs.nim b/tests/overload/tparams_after_varargs.nim
new file mode 100644
index 000000000..a93e280b9
--- /dev/null
+++ b/tests/overload/tparams_after_varargs.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''a 1 b 2 x @[3, 4, 5] y 6 z 7
+yay
+12'''
+"""
+
+proc test(a, b: int, x: varargs[int]; y, z: int) =
+  echo "a ", a, " b ", b, " x ", @x, " y ", y, " z ", z
+
+test 1, 2, 3, 4, 5, 6, 7
+
+template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+  blck
+  echo a, b
+
+takesBlock 1, 2, "some", 0.90, "random stuff":
+  echo "yay"
diff --git a/tests/stdlib/tircbot.nim b/tests/stdlib/tircbot.nim
deleted file mode 100644
index 6b209dce3..000000000
--- a/tests/stdlib/tircbot.nim
+++ /dev/null
@@ -1,453 +0,0 @@
-import irc, sockets, asyncio, json, os, strutils, times, redis
-
-type
-  TDb* = object
-    r*: Redis
-    lastPing: float
-
-  TBuildResult* = enum
-    bUnknown, bFail, bSuccess
-
-  TTestResult* = enum
-    tUnknown, tFail, tSuccess
-
-  TEntry* = tuple[c: TCommit, p: seq[TPlatform]]
-  
-  TCommit* = object
-    commitMsg*, username*, hash*: string
-    date*: Time
-
-  TPlatform* = object
-    buildResult*: TBuildResult
-    testResult*: TTestResult
-    failReason*, platform*: string
-    total*, passed*, skipped*, failed*: BiggestInt
-    csources*: bool
-
-const
-  listName = "commits"
-  failOnExisting = false
-
-proc open*(host = "localhost", port: Port): TDb =
-  result.r = redis.open(host, port)
-  result.lastPing = epochTime()
-
-discard """proc customHSet(database: TDb, name, field, value: string) =
-  if database.r.hSet(name, field, value).int == 0:
-    if failOnExisting:
-      assert(false)
-    else:
-      echo("[Warning:REDIS] ", field, " already exists in ", name)"""
-
-proc updateProperty*(database: TDb, commitHash, platform, property,
-                    value: string) =
-  var name = platform & ":" & commitHash
-  if database.r.hSet(name, property, value).int == 0:
-    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
-  else:
-    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
-
-proc globalProperty*(database: TDb, commitHash, property, value: string) =
-  if database.r.hSet(commitHash, property, value).int == 0:
-    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
-  else:
-    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
-
-proc addCommit*(database: TDb, commitHash, commitMsg, user: string) =
-  # Add the commit hash to the `commits` list.
-  discard database.r.lPush(listName, commitHash)
-  # Add the commit message, current date and username as a property
-  globalProperty(database, commitHash, "commitMsg", commitMsg)
-  globalProperty(database, commitHash, "date", $int(getTime()))
-  globalProperty(database, commitHash, "username", user)
-
-proc keepAlive*(database: var TDb) =
-  ## Keep the connection alive. Ping redis in this case. This functions does
-  ## not guarantee that redis will be pinged.
-  var t = epochTime()
-  if t - database.lastPing >= 60.0:
-    echo("PING -> redis")
-    assert(database.r.ping() == "PONG")
-    database.lastPing = t
-    
-proc getCommits*(database: TDb,
-                 plStr: var seq[string]): seq[TEntry] =
-  result = @[]
-  var commitsRaw = database.r.lrange("commits", 0, -1)
-  for c in items(commitsRaw):
-    var commit: TCommit
-    commit.hash = c
-    for key, value in database.r.hPairs(c):
-      case normalize(key)
-      of "commitmsg": commit.commitMsg = value
-      of "date": commit.date = Time(parseInt(value))
-      of "username": commit.username = value
-      else:
-        echo(key)
-        assert(false)
-
-    var platformsRaw = database.r.lrange(c & ":platforms", 0, -1)
-    var platforms: seq[TPlatform] = @[]
-    for p in items(platformsRaw):
-      var platform: TPlatform
-      for key, value in database.r.hPairs(p & ":" & c):
-        case normalize(key)
-        of "buildresult":
-          platform.buildResult = parseInt(value).TBuildResult
-        of "testresult":
-          platform.testResult = parseInt(value).TTestResult
-        of "failreason":
-          platform.failReason = value
-        of "total":
-          platform.total = parseBiggestInt(value)
-        of "passed":
-          platform.passed = parseBiggestInt(value)
-        of "skipped":
-          platform.skipped = parseBiggestInt(value)
-        of "failed":
-          platform.failed = parseBiggestInt(value)
-        of "csources":
-          platform.csources = if value == "t": true else: false
-        else:
-          echo(normalize(key))
-          assert(false)
-      
-      platform.platform = p
-      
-      platforms.add(platform)
-      if p notin plStr:
-        plStr.add(p)
-    result.add((commit, platforms))
-
-proc commitExists*(database: TDb, commit: string, starts = false): bool =
-  # TODO: Consider making the 'commits' list a set.
-  for c in items(database.r.lrange("commits", 0, -1)):
-    if starts:
-      if c.startsWith(commit): return true
-    else:
-      if c == commit: return true
-  return false
-
-proc platformExists*(database: TDb, commit: string, platform: string): bool =
-  for p in items(database.r.lrange(commit & ":" & "platforms", 0, -1)):
-    if p == platform: return true
-
-proc expandHash*(database: TDb, commit: string): string =
-  for c in items(database.r.lrange("commits", 0, -1)):
-    if c.startsWith(commit): return c
-  assert false
-
-proc isNewest*(database: TDb, commit: string): bool =
-  return database.r.lIndex("commits", 0) == commit
-
-proc getNewest*(database: TDb): string =
-  return database.r.lIndex("commits", 0)
-
-proc addPlatform*(database: TDb, commit: string, platform: string) =
-  assert database.commitExists(commit)
-  assert (not database.platformExists(commit, platform))
-  var name = platform & ":" & commit
-  if database.r.exists(name):
-    if failOnExisting: quit("[FAIL] " & name & " already exists!", 1)
-    else: echo("[Warning] " & name & " already exists!")
-
-  discard database.r.lPush(commit & ":" & "platforms", platform)
-
-proc `[]`*(p: seq[TPlatform], name: string): TPlatform =
-  for platform in items(p):
-    if platform.platform == name:
-      return platform
-  raise newException(ValueError, name & " platforms not found in commits.")
-  
-proc contains*(p: seq[TPlatform], s: string): bool =
-  for i in items(p):
-    if i.platform == s:
-      return true
-    
-
-type
-  PState = ref TState
-  TState = object of RootObj
-    dispatcher: Dispatcher
-    sock: AsyncSocket
-    ircClient: PAsyncIRC
-    hubPort: Port
-    database: TDb
-    dbConnected: bool
-
-  TSeenType = enum
-    PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit
-  
-  TSeen = object
-    nick: string
-    channel: string
-    timestamp: Time
-    case kind*: TSeenType
-    of PSeenJoin: nil
-    of PSeenPart, PSeenQuit, PSeenMsg:
-      msg: string
-    of PSeenNick:
-      newNick: string
-
-const
-  ircServer = "irc.freenode.net"
-  joinChans = @["#nim"]
-  botNickname = "NimBot"
-
-proc setSeen(d: TDb, s: TSeen) =
-  discard d.r.del("seen:" & s.nick)
-
-  var hashToSet = @[("type", $s.kind.int), ("channel", s.channel),
-                    ("timestamp", $s.timestamp.int)]
-  case s.kind
-  of PSeenJoin: discard
-  of PSeenPart, PSeenMsg, PSeenQuit:
-    hashToSet.add(("msg", s.msg))
-  of PSeenNick:
-    hashToSet.add(("newnick", s.newNick))
-  
-  d.r.hMSet("seen:" & s.nick, hashToSet)
-
-proc getSeen(d: TDb, nick: string, s: var TSeen): bool =
-  if d.r.exists("seen:" & nick):
-    result = true
-    s.nick = nick
-    # Get the type first
-    s.kind = d.r.hGet("seen:" & nick, "type").parseInt.TSeenType
-    
-    for key, value in d.r.hPairs("seen:" & nick):
-      case normalize(key)
-      of "type":
-        discard
-        #s.kind = value.parseInt.TSeenType
-      of "channel":
-        s.channel = value
-      of "timestamp":
-        s.timestamp = Time(value.parseInt)
-      of "msg":
-        s.msg = value
-      of "newnick":
-        s.newNick = value
-
-template createSeen(typ: TSeenType, n, c: string): stmt {.immediate, dirty.} =
-  var seenNick: TSeen
-  seenNick.kind = typ
-  seenNick.nick = n
-  seenNick.channel = c
-  seenNick.timestamp = getTime()
-
-proc parseReply(line: string, expect: string): bool =
-  var jsonDoc = parseJson(line)
-  return jsonDoc["reply"].str == expect
-
-proc limitCommitMsg(m: string): string =
-  ## Limits the message to 300 chars and adds ellipsis.
-  var m1 = m
-  if NewLines in m1:
-    m1 = m1.splitLines()[0]
-  
-  if m1.len >= 300:
-    m1 = m1[0..300]
-
-  if m1.len >= 300 or NewLines in m: m1.add("... ")
-
-  if NewLines in m: m1.add($m.splitLines().len & " more lines")
-
-  return m1
-
-proc handleWebMessage(state: PState, line: string) =
-  echo("Got message from hub: " & line)
-  var json = parseJson(line)
-  if json.hasKey("payload"):
-    for i in 0..min(4, json["payload"]["commits"].len-1):
-      var commit = json["payload"]["commits"][i]
-      # Create the message
-      var message = ""
-      message.add(json["payload"]["repository"]["owner"]["name"].str & "/" &
-                  json["payload"]["repository"]["name"].str & " ")
-      message.add(commit["id"].str[0..6] & " ")
-      message.add(commit["author"]["name"].str & " ")
-      message.add("[+" & $commit["added"].len & " ")
-      message.add("±" & $commit["modified"].len & " ")
-      message.add("-" & $commit["removed"].len & "]: ")
-      message.add(limitCommitMsg(commit["message"].str))
-
-      # Send message to #nim.
-      discard state.ircClient.privmsg(joinChans[0], message)
-  elif json.hasKey("redisinfo"):
-    assert json["redisinfo"].hasKey("port")
-    #let redisPort = json["redisinfo"]["port"].num
-    state.dbConnected = true
-
-proc hubConnect(state: PState)
-proc handleConnect(s: AsyncSocket, state: PState) =
-  try:
-    # Send greeting
-    var obj = newJObject()
-    obj["name"] = newJString("irc")
-    obj["platform"] = newJString("?")
-    state.sock.send($obj & "\c\L")
-
-    # Wait for reply.
-    var line = ""
-    sleep(1500)
-    if state.sock.recvLine(line):
-      assert(line != "")
-      doAssert parseReply(line, "OK")
-      echo("The hub accepted me!")
-    else:
-      raise newException(ValueError,
-                         "Hub didn't accept me. Waited 1.5 seconds.")
-    
-    # ask for the redis info
-    var riobj = newJObject()
-    riobj["do"] = newJString("redisinfo")
-    state.sock.send($riobj & "\c\L")
-    
-  except OsError:
-    echo(getCurrentExceptionMsg())
-    s.close()
-    echo("Waiting 5 seconds...")
-    sleep(5000)
-    state.hubConnect()
-
-proc handleRead(s: AsyncSocket, state: PState) =
-  var line = ""
-  if state.sock.recvLine(line):
-    if line != "":
-      # Handle the message
-      state.handleWebMessage(line)
-    else:
-      echo("Disconnected from hub: ", osErrorMsg())
-      s.close()
-      echo("Reconnecting...")
-      state.hubConnect()
-  else:
-    echo(osErrorMsg())
-
-proc hubConnect(state: PState) =
-  state.sock = asyncSocket()
-  state.sock.connect("127.0.0.1", state.hubPort)
-  state.sock.handleConnect =
-    proc (s: AsyncSocket) =
-      handleConnect(s, state)
-  state.sock.handleRead =
-    proc (s: AsyncSocket) =
-      handleRead(s, state)
-
-  state.dispatcher.register(state.sock)
-
-proc handleIrc(irc: PAsyncIRC, event: TIRCEvent, state: PState) =
-  case event.typ
-  of EvConnected: discard
-  of EvDisconnected:
-    while not state.ircClient.isConnected:
-      try:
-        state.ircClient.connect()
-      except:
-        echo("Error reconnecting: ", getCurrentExceptionMsg())
-      
-      echo("Waiting 5 seconds...")
-      sleep(5000)
-    echo("Reconnected successfully!")
-  of EvMsg:
-    echo("< ", event.raw)
-    case event.cmd
-    of MPrivMsg:
-      let msg = event.params[event.params.len-1]
-      let words = msg.split(' ')
-      template pm(msg: string): stmt =
-        state.ircClient.privmsg(event.origin, msg)
-      case words[0]
-      of "!ping": pm("pong")
-      of "!lag":
-        if state.ircClient.getLag != -1.0:
-          var lag = state.ircClient.getLag
-          lag = lag * 1000.0
-          pm($int(lag) & "ms between me and the server.")
-        else:
-          pm("Unknown.")
-      of "!seen":
-        if words.len > 1:
-          let nick = words[1]
-          if nick == botNickname:
-            pm("Yes, I see myself.")
-          echo(nick)
-          var seenInfo: TSeen
-          if state.database.getSeen(nick, seenInfo):
-            #var mSend = ""
-            case seenInfo.kind
-            of PSeenMsg:
-              pm("$1 was last seen on $2 in $3 saying: $4" %
-                    [seenInfo.nick, $seenInfo.timestamp,
-                     seenInfo.channel, seenInfo.msg])
-            of PSeenJoin:
-              pm("$1 was last seen on $2 joining $3" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel])
-            of PSeenPart:
-              pm("$1 was last seen on $2 leaving $3 with message: $4" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel,
-                         seenInfo.msg])
-            of PSeenQuit:
-              pm("$1 was last seen on $2 quitting with message: $3" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.msg])
-            of PSeenNick:
-              pm("$1 was last seen on $2 changing nick to $3" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.newNick])
-            
-          else:
-            pm("I have not seen " & nick)
-        else:
-          pm("Syntax: !seen <nick>")
-
-      # TODO: ... commands
-
-      # -- Seen
-      # Log this as activity.
-      createSeen(PSeenMsg, event.nick, event.origin)
-      seenNick.msg = msg
-      state.database.setSeen(seenNick)
-    of MJoin:
-      createSeen(PSeenJoin, event.nick, event.origin)
-      state.database.setSeen(seenNick)
-    of MPart:
-      createSeen(PSeenPart, event.nick, event.origin)
-      let msg = event.params[event.params.high]
-      seenNick.msg = msg
-      state.database.setSeen(seenNick)
-    of MQuit:
-      createSeen(PSeenQuit, event.nick, event.origin)
-      let msg = event.params[event.params.high]
-      seenNick.msg = msg
-      state.database.setSeen(seenNick)
-    of MNick:
-      createSeen(PSeenNick, event.nick, "#nim")
-      seenNick.newNick = event.params[0]
-      state.database.setSeen(seenNick)
-    else:
-      discard # TODO: ?
-
-proc open(port: Port = Port(5123)): PState =
-  var res: PState
-  new(res)
-  res.dispatcher = newDispatcher()
-  
-  res.hubPort = port
-  res.hubConnect()
-  let hirc =
-    proc (a: PAsyncIRC, ev: TIRCEvent) =
-      handleIrc(a, ev, res)
-  # Connect to the irc server.
-  res.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
-                 joinChans = joinChans, ircEvent = hirc)
-  res.ircClient.connect()
-  res.dispatcher.register(res.ircClient)
-
-  res.dbConnected = false
-  result = res
-
-var state = tircbot.open() # Connect to the website and the IRC server.
-
-while state.dispatcher.poll():
-  if state.dbConnected:
-    state.database.keepAlive()
diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim
index bf67d2b7b..2c0a0392a 100644
--- a/tests/stdlib/tmitems.nim
+++ b/tests/stdlib/tmitems.nim
@@ -11,7 +11,7 @@ fpqeew
 [11, 12, 13]
 [11, 12, 13]
 [11, 12, 13]
-{ "key1": 11,  "key2": 12,  "key3": 13}
+{"key1": 11, "key2": 12, "key3": 13}
 [11, 12, 13]
 <Students>
   <Student Name="Aprilfoo" />
diff --git a/tests/table/ttables.nim b/tests/table/ttables.nim
deleted file mode 100644
index de4aaed5e..000000000
--- a/tests/table/ttables.nim
+++ /dev/null
@@ -1,128 +0,0 @@
-discard """
-  output: '''true'''
-"""
-
-import hashes, tables
-
-const
-  data = {
-    "34": 123456, "12": 789,
-    "90": 343, "0": 34404,
-    "1": 344004, "2": 344774,
-    "3": 342244, "4": 3412344,
-    "5": 341232144, "6": 34214544,
-    "7": 3434544, "8": 344544,
-    "9": 34435644, "---00": 346677844,
-    "10": 34484, "11": 34474, "19": 34464,
-    "20": 34454, "30": 34141244, "40": 344114,
-    "50": 344490, "60": 344491, "70": 344492,
-    "80": 344497}
-
-  sorteddata = {
-    "---00": 346677844,
-    "0": 34404,
-    "1": 344004,
-    "10": 34484, 
-    "11": 34474,
-    "12": 789,
-    "19": 34464,
-    "2": 344774, "20": 34454, 
-    "3": 342244, "30": 34141244,
-    "34": 123456,
-    "4": 3412344, "40": 344114,
-    "5": 341232144, "50": 344490, 
-    "6": 34214544, "60": 344491,
-    "7": 3434544, "70": 344492,
-    "8": 344544, "80": 344497,
-    "9": 34435644,
-    "90": 343}
-
-block tableTest1:
-  var t = initTable[tuple[x, y: int], string]()
-  t[(0,0)] = "00"
-  t[(1,0)] = "10"
-  t[(0,1)] = "01"
-  t[(1,1)] = "11"
-  for x in 0..1:
-    for y in 0..1:
-      assert t[(x,y)] == $x & $y
-  assert($t == 
-    "{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
-
-block tableTest2:
-  var t = initTable[string, float]()
-  t["test"] = 1.2345
-  t["111"] = 1.000043
-  t["123"] = 1.23
-  t.del("111")
-  
-  t["012"] = 67.9
-  t["123"] = 1.5 # test overwriting
-  
-  assert t["123"] == 1.5
-  assert t["111"] == 0.0 # deleted
-  assert(not hasKey(t, "111"))
-  
-  for key, val in items(data): t[key] = val.toFloat
-  for key, val in items(data): assert t[key] == val.toFloat
-  
-
-block orderedTableTest1:
-  var t = initOrderedTable[string, int](2)
-  for key, val in items(data): t[key] = val
-  for key, val in items(data): assert t[key] == val
-  var i = 0
-  # `pairs` needs to yield in insertion order:
-  for key, val in pairs(t):
-    assert key == data[i][0]
-    assert val == data[i][1]
-    inc(i)
-
-  for key, val in mpairs(t): val = 99
-  for val in mvalues(t): assert val == 99
-
-block countTableTest1:
-  var s = data.toTable
-  var t = initCountTable[string]()
-  for k in s.keys: t.inc(k)
-  for k in t.keys: assert t[k] == 1
-  t.inc("90", 3)
-  t.inc("12", 2)
-  t.inc("34", 1)
-  assert t.largest()[0] == "90"
-
-  t.sort()
-  var i = 0
-  for k, v in t.pairs:
-    case i
-    of 0: assert k == "90" and v == 4
-    of 1: assert k == "12" and v == 3
-    of 2: assert k == "34" and v == 2
-    else: break
-    inc i
-
-block SyntaxTest:
-  var x = toTable[int, string]({:})
-
-proc orderedTableSortTest() =
-  var t = initOrderedTable[string, int](2)
-  for key, val in items(data): t[key] = val
-  for key, val in items(data): assert t[key] == val
-  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
-  var i = 0
-  # `pairs` needs to yield in sorted order:
-  for key, val in pairs(t):
-    doAssert key == sorteddata[i][0]
-    doAssert val == sorteddata[i][1]
-    inc(i)
-
-  # check that lookup still works:
-  for key, val in pairs(t):
-    doAssert val == t[key]
-  # check that insert still works:
-  t["newKeyHere"] = 80
-
-
-orderedTableSortTest()
-echo "true"
-
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 54e962693..ed4d27cab 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -120,7 +120,8 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
                   " --gc:markAndSweep", cat, actionRun)
     testSpec r, makeTest("tests/gc" / filename, options &
                   " -d:release --gc:markAndSweep", cat, actionRun)
-  
+
+  test "growobjcrash"
   test "gcbench"
   test "gcleak"
   test "gcleak2"
diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim
index f8d22bdb8..2b07ba679 100644
--- a/tests/types/temptyseqs.nim
+++ b/tests/types/temptyseqs.nim
@@ -5,7 +5,7 @@ discard """
 # bug #1708
 let foo = {
   "1" : (bar: @["1"]),
-  "2" : (baz: @[])
+  "2" : (bar: @[])
 }
 
 # bug #871
diff --git a/todo.txt b/todo.txt
index 252699bf1..408bfefe5 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,11 +1,10 @@
 version 0.10.4
 ==============
 
-- make 'nil' work for 'add' and 'len'
 - improve GC-unsafety warnings
+- make 'nil' work for 'add' and 'len'
 - get rid of 'mget'; aka priority of 'var' needs to be 'var{lvalue}'
-- improve documentation (theindex!)
-- fix the getUniqueType() bug
+- 'result' shadowing warning
 
 
 version 1.0
@@ -43,7 +42,6 @@ Misc
 - make tuple unpacking work in a non-var/let context
 - built-in 'getImpl'
 - prevent 'alloc(TypeWithGCedMemory)'
-- some table related tests are wrong (memory usage checks)
 
 
 Bugs
@@ -67,7 +65,6 @@ version 0.9.x
 - memory manager: add a measure of fragmentation
 - implement 'bits' pragmas
 - we need a magic thisModule symbol
-- ensure (ref T)(a, b) works as a type conversion and type constructor
 - optimize 'genericReset'; 'newException' leads to code bloat
 - The 'do' notation might be trimmed so that its only purpose is to pass
   multiple multi line constructs to a macro.
@@ -96,4 +93,3 @@ CGEN
 ====
 - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
 - ``restrict`` pragma + backend support
-- 'const' objects including case objects
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index e74daf98f..8213cf418 100644
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -319,7 +319,7 @@ proc buildAddDoc(c: var TConfigData, destPath: string) =
   # build additional documentation (without the index):
   var commands = newSeq[string](c.webdoc.len)
   for i, doc in pairs(c.webdoc):
-    commands[i] = "nim doc $# --docSeeSrcUrl:$#/$#/$# -o:$# $#" %
+    commands[i] = "nim doc2 $# --docSeeSrcUrl:$#/$#/$# -o:$# $#" %
       [c.nimArgs, c.gitRepo, c.gitCommit, doc.pathPart,
       destPath / changeFileExt(splitFile(doc).name, "html"), doc]
   mexec(commands, c.numProcessors)
diff --git a/web/news.txt b/web/news.txt
index 5cc3a6ed6..7ead5a70e 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -43,6 +43,18 @@ News
       foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
 
 
+  - Ordinary parameters can follow after a varargs parameter. This means the
+    following is finally accepted by the compiler:
+
+  .. code-block:: nim  
+    template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+      blck
+      echo a, b
+
+    takesBlock 1, 2, "some", 0.90, "random stuff":
+      echo "yay"
+  
+
 2014-12-29 Version 0.10.2 released
 ==================================
 
diff --git a/web/nim.ini b/web/website.ini
index 0190416b2..c0a648c56 100644
--- a/web/nim.ini
+++ b/web/website.ini
@@ -27,19 +27,6 @@ news: news
 [Ticker]
 file: ticker.txt
 
-[Quotations]
-# Page: quote - Person
-# Bad things will happen if you use multiple dashes here.
-index: """Is it so bad, then, to be misunderstood? Pythagoras was misunderstood,
-and Socrates, and Jesus, and Luther, and Copernicus, and Galileo, and Newton,
-and every pure and wise spirit that ever took flesh. To be great is to be
-misunderstood. - Ralph Waldo Emerson"""
-documentation: """Incorrect documentation is often worse than no documentation. 
-- Bertrand Meyer"""
-download: """There are two major products that come out of Berkeley: LSD and
-UNIX. We don't believe this to be a coincidence. - Jeremy S. Anderson."""
-learn: """Repetition renders the ridiculous reasonable. - Norman Wildberger"""
-
 [Documentation]
 doc: "endb;intern;apis;lib;manual.txt;tut1;tut2;nimc;overview;filters"
 doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
@@ -61,7 +48,7 @@ srcdoc2: "pure/httpserver;pure/httpclient;pure/smtp;impure/ssl;pure/fsmonitor"
 srcdoc2: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser"
 srcdoc2: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes"
 srcdoc2: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics"
-srcdoc2: "impure/rdstdin;wrappers/sphinx"
+srcdoc2: "impure/rdstdin"
 srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
 srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
 srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
@@ -71,19 +58,15 @@ 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: "wrappers/expat;wrappers/readline/history"
-srcdoc2: "wrappers/libsvm.nim;wrappers/libuv"
-srcdoc2: "wrappers/zip/zlib;wrappers/zip/libzip"
-srcdoc2: "pure/md5;wrappers/mysql;wrappers/iup"
-srcdoc2: "posix/posix;wrappers/odbcsql"
-srcdoc2: "wrappers/tre;wrappers/openssl;wrappers/pcre"
-srcdoc2: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"
-srcdoc2: "wrappers/readline/readline;wrappers/readline/rltypedefs"
-srcdoc2: "wrappers/joyent_http_parser"
+srcdoc2: "pure/md5"
+srcdoc2: "posix/posix"
 srcdoc2: "pure/fenv"
 
-webdoc: "pure/md5;wrappers/mysql;wrappers/iup"
-webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"
+; Note: everything under 'webdoc' doesn't get listed in the index, so wrappers
+; should live here
+
+webdoc: "wrappers/mysql;wrappers/iup;wrappers/sphinx"
+webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc;wrappers/odbcsql"
 webdoc: "wrappers/expat;wrappers/pcre"
 webdoc: "wrappers/tre;wrappers/openssl"
 webdoc: "wrappers/libuv;wrappers/joyent_http_parser"