summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim6
-rw-r--r--compiler/astalgo.nim33
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/lookups.nim14
-rw-r--r--compiler/parser.nim23
-rw-r--r--compiler/sem.nim4
-rw-r--r--compiler/semdata.nim1
-rw-r--r--compiler/semstmts.nim4
-rw-r--r--compiler/semtypes.nim41
-rw-r--r--compiler/semtypinst.nim2
-rw-r--r--compiler/sigmatch.nim19
-rw-r--r--compiler/types.nim4
-rw-r--r--compiler/vm.nim5
-rw-r--r--compiler/vmgen.nim25
-rw-r--r--doc/manual.txt2
-rw-r--r--doc/tut2.txt4
-rw-r--r--lib/impure/db_mongo.nim4
-rw-r--r--lib/pure/asyncio.nim2
-rw-r--r--lib/pure/collections/tables.nim10
-rw-r--r--lib/pure/htmlparser.nim4
-rw-r--r--lib/pure/irc.nim4
-rw-r--r--lib/pure/matchers.nim2
-rw-r--r--lib/pure/oids.nim2
-rw-r--r--lib/pure/os.nim4
-rw-r--r--lib/pure/osproc.nim4
-rw-r--r--lib/pure/parsecsv.nim2
-rw-r--r--lib/pure/parsesql.nim6
-rw-r--r--lib/pure/xmlparser.nim4
-rw-r--r--lib/windows/winlean.nim6
-rw-r--r--lib/wrappers/mongo.nim52
-rw-r--r--tests/collections/ttables.nim22
-rw-r--r--tests/exprs/tstmtexprs.nim7
-rw-r--r--tests/gc/gcleak4.nim2
-rw-r--r--tests/gc/gcleak5.nim25
-rw-r--r--tests/macros/tdebugstmt.nim29
-rw-r--r--tests/stdlib/talgorithm.nim18
-rw-r--r--tests/template/tprefer_immediate.nim17
-rw-r--r--tests/testament/categories.nim5
-rw-r--r--todo.txt9
39 files changed, 306 insertions, 123 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 7138b5f52..cd002eef1 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1129,7 +1129,7 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
   result.align = 2            # default alignment
   result.id = getID()
   when debugIds:
-    RegisterId(result)
+    registerId(result)
   #if result.id < 2000 then
   #  MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
   
@@ -1166,7 +1166,7 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
   if keepId: 
     result.id = t.id
   else: 
-    when debugIds: RegisterId(result)
+    when debugIds: registerId(result)
   result.sym = t.sym          # backend-info should not be copied
   
 proc copySym(s: PSym, keepId: bool = false): PSym = 
@@ -1177,7 +1177,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
     result.id = s.id
   else: 
     result.id = getID()
-    when debugIds: RegisterId(result)
+    when debugIds: registerId(result)
   result.flags = s.flags
   result.magic = s.magic
   if s.kind == skModule:
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 2505bc687..64c1b717c 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -561,14 +561,31 @@ proc strTableContains(t: TStrTable, n: PSym): bool =
 
 proc strTableRawInsert(data: var TSymSeq, n: PSym) = 
   var h: THash = n.name.h and high(data)
-  while data[h] != nil: 
-    if data[h] == n:
-      # allowed for 'export' feature:
-      #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
-      return
-    h = nextTry(h, high(data))
-  assert(data[h] == nil)
-  data[h] = n
+  if sfImmediate notin n.flags:
+    # fast path:
+    while data[h] != nil:
+      if data[h] == n:
+        # allowed for 'export' feature:
+        #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
+        return
+      h = nextTry(h, high(data))
+    assert(data[h] == nil)
+    data[h] = n
+  else:
+    # slow path; we have to ensure immediate symbols are preferred for
+    # symbol lookups.
+    # consider the chain: foo (immediate), foo, bar, bar (immediate)
+    # then bar (immediate) gets replaced with foo (immediate) and the non
+    # immediate foo is picked! Thus we need to replace it with the first
+    # slot that has in fact the same identifier stored in it!
+    var favPos = -1
+    while data[h] != nil:
+      if data[h] == n: return
+      if favPos < 0 and data[h].name.id == n.name.id: favPos = h
+      h = nextTry(h, high(data))
+    assert(data[h] == nil)
+    data[h] = n
+    if favPos >= 0: swap data[h], data[favPos]
 
 proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
   assert prevSym.name.h == newSym.name.h
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index be47ac0c4..031ab8d70 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1049,7 +1049,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
     app(tmp2.r, field.loc.r)
     tmp2.k = locTemp
     tmp2.t = field.loc.t
-    tmp2.s = OnHeap
+    tmp2.s = if isRef: OnHeap else: OnStack
     tmp2.heapRoot = tmp.r
     expr(p, it.sons[1], tmp2)
   if d.k == locNone:
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 6dfd25968..c31eb3121 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -339,4 +339,16 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
                                    n.sons[0].sym.name, o.inSymChoice)
   
   if result != nil and result.kind == skStub: loadStub(result)
-  
+
+when false:
+  proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
+                                       flags = {checkUndeclared}): PSym =
+    var o: TOverloadIter
+    result = initOverloadIter(o, c, n)
+    var a = result
+    while a != nil:
+      if sfImmediate in a.flags: return a
+      a = nextOverloadIter(o, c, n)
+    if result == nil and checkUndeclared in flags: 
+      localError(n.info, errUndeclaredIdentifier, n.considerAcc.s)
+      result = errorSym(c, n)
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 7c740559c..ff3324b47 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -35,6 +35,7 @@ type
     lex*: TLexer              # the lexer that is used for parsing
     tok*: TToken              # the current token
     inPragma: int
+    inSemiStmtList: int
 
 proc parseAll*(p: var TParser): PNode
 proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
@@ -455,11 +456,13 @@ proc complexOrSimpleStmt(p: var TParser): PNode
 proc simpleExpr(p: var TParser, mode = pmNormal): PNode
 
 proc semiStmtList(p: var TParser, result: PNode) =
+  inc p.inSemiStmtList
   result.add(complexOrSimpleStmt(p))
   while p.tok.tokType == tkSemiColon:
     getTok(p)
     optInd(p, result)
     result.add(complexOrSimpleStmt(p))
+  dec p.inSemiStmtList
   result.kind = nkStmtListExpr
 
 proc parsePar(p: var TParser): PNode =
@@ -1881,14 +1884,18 @@ proc parseStmt(p: var TParser): PNode =
       parMessage(p, errComplexStmtRequiresInd)
       result = ast.emptyNode
     else:
-      result = newNodeP(nkStmtList, p)
-      while true:
-        if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)     
-        let a = simpleStmt(p)
-        if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
-        result.add(a)
-        if p.tok.tokType != tkSemiColon: break
-        getTok(p)
+      if p.inSemiStmtList > 0:
+        result = simpleStmt(p)
+        if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
+      else:
+        result = newNodeP(nkStmtList, p)
+        while true:
+          if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)     
+          let a = simpleStmt(p)
+          if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
+          result.add(a)
+          if p.tok.tokType != tkSemiColon: break
+          getTok(p)
   
 proc parseAll(p: var TParser): PNode = 
   result = newNodeP(nkStmtList, p)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index e89e32f4e..00ac79716 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -83,7 +83,9 @@ proc commonType*(x, y: PType): PType =
   elif a.kind == tyTypeDesc:
     # turn any concrete typedesc into the abstract typedesc type
     if a.sons == nil: result = a
-    else: result = newType(tyTypeDesc, a.owner)
+    else:
+      result = newType(tyTypeDesc, a.owner)
+      rawAddSon(result, newType(tyNone, a.owner))
   elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and 
       a.kind == b.kind:
     # check for seq[empty] vs. seq[int]
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 8b97f3685..c9d95e1bf 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -211,6 +211,7 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
 
 proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
   let typedesc = makeTypeDesc(c, typ)
+  rawAddSon(typedesc, newTypeS(tyNone, c))
   let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
   return newSymNode(sym, info)
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index d3cc1a12e..0871b7fb7 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -740,7 +740,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       # we fill it out later. For magic generics like 'seq', it won't be filled
       # so we use tyEmpty instead of nil to not crash for strange conversions
       # like: mydata.seq
-      rawAddSon(s.typ, newTypeS(tyEmpty, c))
+      rawAddSon(s.typ, newTypeS(tyNone, c))
       s.ast = a
       inc c.inGenericContext
       var body = semTypeNode(c, a.sons[2], nil)
@@ -748,7 +748,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       if body != nil:
         body.sym = s
         body.size = -1 # could not be computed properly
-      s.typ.sons[sonsLen(s.typ) - 1] = body
+        s.typ.sons[sonsLen(s.typ) - 1] = body
       popOwner()
       closeScope(c)
     elif a.sons[2].kind != nkEmpty: 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 408b1b62e..44e414e9c 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -681,12 +681,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   of tySequence, tySet, tyArray, tyOpenArray,
      tyVar, tyPtr, tyRef, tyProc:
     # XXX: this is a bit strange, but proc(s: seq)
-    # produces tySequence(tyGenericParam, null).
+    # produces tySequence(tyGenericParam, tyNone).
     # This also seems to be true when creating aliases
     # like: type myseq = distinct seq.
     # Maybe there is another better place to associate
     # the seq type class with the seq identifier.
-    if paramType.kind == tySequence and paramType.lastSon == nil:
+    if paramType.kind == tySequence and paramType.lastSon.kind == tyNone:
       let typ = c.newTypeWithSons(tyBuiltInTypeClass,
                                   @[newTypeS(paramType.kind, c)])
       result = addImplicitGeneric(typ)
@@ -885,8 +885,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     for i in countup(1, sonsLen(n)-1):
       var elem = semGenericParamInInvokation(c, n.sons[i])
       addToResult(elem)
+  elif s.typ.kind != tyGenericBody:
+    #we likely got code of the form TypeA[TypeB] where TypeA is
+    #not generic.
+    localError(n.info, errNoGenericParamsAllowedForX, s.name.s)
+    return newOrPrevType(tyError, prev, c)
   else:
-    internalAssert s.typ.kind == tyGenericBody
 
     var m = newCandidate(c, s, n)
     matches(c, n, copyTree(n), m)
@@ -1133,15 +1137,26 @@ proc processMagicType(c: PContext, m: PSym) =
   of mNil: setMagicType(m, tyNil, ptrSize)
   of mExpr: setMagicType(m, tyExpr, 0)
   of mStmt: setMagicType(m, tyStmt, 0)
-  of mTypeDesc: setMagicType(m, tyTypeDesc, 0)
+  of mTypeDesc: 
+    setMagicType(m, tyTypeDesc, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
   of mVoidType: setMagicType(m, tyEmpty, 0)
-  of mArray: setMagicType(m, tyArray, 0)
-  of mOpenArray: setMagicType(m, tyOpenArray, 0)
-  of mVarargs: setMagicType(m, tyVarargs, 0)
-  of mRange: setMagicType(m, tyRange, 0)
-  of mSet: setMagicType(m, tySet, 0) 
-  of mSeq: setMagicType(m, tySequence, 0)
-  of mOrdinal: setMagicType(m, tyOrdinal, 0)
+  of mArray:
+    setMagicType(m, tyArray, 0)
+  of mOpenArray:
+    setMagicType(m, tyOpenArray, 0)
+  of mVarargs:
+    setMagicType(m, tyVarargs, 0)
+  of mRange:
+    setMagicType(m, tyRange, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
+  of mSet:
+    setMagicType(m, tySet, 0) 
+  of mSeq: 
+    setMagicType(m, tySequence, 0)
+  of mOrdinal:
+    setMagicType(m, tyOrdinal, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
   of mPNimrodNode: discard
   else: localError(m.info, errTypeExpected)
   
@@ -1165,8 +1180,8 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
       typ = semTypeNode(c, constraint, nil)
       if typ.kind != tyStatic or typ.len == 0:
         if typ.kind == tyTypeDesc:
-          if typ.len == 0:
-            typ = newTypeS(tyTypeDesc, c)
+          if typ.sons[0].kind == tyNone:
+            typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
         else:
           typ = semGenericConstraints(c, typ)
     
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 1158335a8..a07d91241 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -358,7 +358,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
     if lookup != nil:
       result = lookup
       if tfUnresolved in t.flags: result = result.base
-    elif t.sonsLen > 0:
+    elif t.sons[0].kind != tyNone:
       result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
  
   of tyUserTypeClass:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index d269e9e69..f9200ea0c 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -562,10 +562,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       #if result < isGeneric: result = isNone
       if result notin {isNone, isGeneric}:
         result = typeRangeRel(f, a)
-    elif skipTypes(f, {tyRange}).kind == a.kind:
-      result = isIntConv
-    elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
-      result = isConvertible  # a convertible to f
+    else:
+      if skipTypes(f, {tyRange}).kind == a.kind:
+        result = isIntConv
+      elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
+        result = isConvertible  # a convertible to f
   of tyInt:      result = handleRange(f, a, tyInt8, tyInt32)
   of tyInt8:     result = handleRange(f, a, tyInt8, tyInt8)
   of tyInt16:    result = handleRange(f, a, tyInt8, tyInt16)
@@ -636,7 +637,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyOrdinal:
     if isOrdinalType(a):
       var x = if a.kind == tyOrdinal: a.sons[0] else: a
-      if f.sonsLen == 0:
+      if f.sons[0].kind == tyNone:
         result = isGeneric
       else:
         result = typeRel(c, f.sons[0], x)
@@ -736,7 +737,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyGenericInst:
     let roota = a.skipGenericAlias
     let rootf = f.skipGenericAlias
-    if a.kind == tyGenericInst and roota.base == rootf.base :
+    if a.kind == tyGenericInst and roota.base == rootf.base:
       for i in 1 .. rootf.sonsLen-2:
         let ff = rootf.sons[i]
         let aa = roota.sons[i]
@@ -845,7 +846,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         # by a tyTypeDesc params. Unfortunately, this requires more substantial
         # changes in semtypinst and elsewhere.
         if a.kind == tyTypeDesc:
-          if f.sons == nil or f.sons.len == 0:
+          if f.sonsLen == 0:
             result = isGeneric
           else:
             internalAssert a.sons != nil and a.sons.len > 0
@@ -854,7 +855,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         else:
           result = isNone
       else:
-        if f.sonsLen > 0:
+        if f.sonsLen > 0 and f.sons[0].kind != tyNone:
           result = typeRel(c, f.lastSon, a)
         else:
           result = isGeneric
@@ -883,7 +884,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     var prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
       if a.kind == tyTypeDesc:
-        if f.sonsLen == 0:
+        if f.sons[0].kind == tyNone:
           result = isGeneric
         else:
           result = typeRel(c, f.sons[0], a.sons[0])
diff --git a/compiler/types.nim b/compiler/types.nim
index 812cd4e93..db75cd3c0 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -47,7 +47,7 @@ proc equalParams*(a, b: PNode): TParamsEquality
   # returns whether the parameter lists of the procs a, b are exactly the same
 proc isOrdinalType*(t: PType): bool
 proc enumHasHoles*(t: PType): bool
-# XXX it is WRONG to include tyTypeDesc here as that might not have any child!
+
 const
   abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
                    tyConst, tyMutable, tyTypeDesc}
@@ -1258,7 +1258,7 @@ proc containsGenericTypeIter(t: PType, closure: PObject): bool =
     return true
 
   if t.kind == tyTypeDesc:
-    if t.sonsLen == 0: return true
+    if t.sons[0].kind == tyNone: return true
     if containsGenericTypeIter(t.base, closure): return true
     return false
   
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 61881a897..10ac7aaaf 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -14,7 +14,7 @@ import ast except getstr
 
 import
   strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
-  parser, vmdeps, idents, trees, renderer, options
+  parser, vmdeps, idents, trees, renderer, options, transf
 
 from semfold import leValueConv, ordinalValToString
 from evaltempl import evalTemplate
@@ -1078,6 +1078,7 @@ proc execute(c: PCtx, start: int): PNode =
   result = rawExecute(c, start, tos)
 
 proc evalStmt*(c: PCtx, n: PNode) =
+  let n = transformExpr(c.module, n)
   let start = genStmt(c, n)
   # execute new instructions; this redundant opcEof check saves us lots
   # of allocations in 'execute':
@@ -1085,6 +1086,7 @@ proc evalStmt*(c: PCtx, n: PNode) =
     discard execute(c, start)
 
 proc evalExpr*(c: PCtx, n: PNode): PNode =
+  let n = transformExpr(c.module, n)
   let start = genExpr(c, n)
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
@@ -1127,6 +1129,7 @@ proc myProcess(c: PPassContext, n: PNode): PNode =
 const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
 
 proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
+  let n = transformExpr(module, n)
   setupGlobalCtx(module)
   var c = globalCtx
   c.mode = mode
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index be32f990f..d0e8dacf3 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -946,6 +946,14 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
 
 template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
 
+proc setSlot(c: PCtx; v: PSym) =
+  # XXX generate type initialization here?
+  if v.position == 0:
+    v.position = c.prc.maxSlots
+    c.prc.slots[v.position] = (inUse: true,
+        kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
+    inc c.prc.maxSlots
+
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
@@ -973,8 +981,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
         gen(c, ri, tmp)
         c.gABx(le, whichAsgnOpc(le, opcWrGlobal), tmp, s.position)
     else:
+      if s.kind == skForVar and c.mode == emRepl: c.setSlot s
       internalAssert s.position > 0 or (s.position == 0 and
-                                        s.kind in {skParam,skResult,skForVar})
+                                        s.kind in {skParam,skResult})
       var dest: TRegister = s.position + ord(s.kind == skParam)
       gen(c, ri, dest)
   else:
@@ -1024,7 +1033,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
   if s.isGlobal:
     if sfCompileTime in s.flags or c.mode == emRepl:
       discard
-    else:
+    elif s.position == 0:
       cannotEval(n)
     if s.position == 0:
       if sfImportc in s.flags: c.importcSym(n.info, s)
@@ -1035,8 +1044,9 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
     else:
       c.gABx(n, opcLdGlobal, dest, s.position)
   else:
+    if s.kind == skForVar and c.mode == emRepl: c.setSlot s
     if s.position > 0 or (s.position == 0 and
-                          s.kind in {skParam,skResult,skForVar}):
+                          s.kind in {skParam,skResult}):
       if dest < 0:
         dest = s.position + ord(s.kind == skParam)
       else:
@@ -1045,7 +1055,6 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
     else:
       # see tests/t99bott for an example that triggers it:
       cannotEval(n)
-      #InternalError(n.info, s.name.s & " " & $s.position)
 
 proc genAccess(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
                flags: TGenFlags) =
@@ -1123,14 +1132,6 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     result = newNodeIT(nkCurly, info, t)
   else: internalError("getNullValue: " & $t.kind)
 
-proc setSlot(c: PCtx; v: PSym) =
-  # XXX generate type initialization here?
-  if v.position == 0:
-    v.position = c.prc.maxSlots
-    c.prc.slots[v.position] = (inUse: true,
-        kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
-    inc c.prc.maxSlots
-
 proc genVarSection(c: PCtx; n: PNode) =
   for a in n:
     if a.kind == nkCommentStmt: continue
diff --git a/doc/manual.txt b/doc/manual.txt
index da229d169..520e4f62e 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2231,6 +2231,8 @@ Instead of:
 Using statement
 ---------------
 
+**Warning**: The ``using`` statement is highly experimental!
+
 The `using statement`:idx: provides syntactic convenience for procs that
 heavily use a single contextual parameter. When applied to a variable or a
 constant, it will instruct Nimrod to automatically consider the used symbol as
diff --git a/doc/tut2.txt b/doc/tut2.txt
index 581239cc7..6738c5551 100644
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -528,7 +528,7 @@ containers:
   proc newNode*[T](data: T): PBinaryTree[T] =
     # constructor for a node
     new(result)
-    result.dat = data
+    result.data = data
 
   proc add*[T](root: var PBinaryTree[T], n: PBinaryTree[T]) =
     # insert a node into the tree
@@ -569,7 +569,7 @@ containers:
       
   var
     root: PBinaryTree[string] # instantiate a PBinaryTree with ``string``
-  add(root, newNode("hallo")) # instantiates ``newNode`` and ``add``
+  add(root, newNode("hello")) # instantiates ``newNode`` and ``add``
   add(root, "world")          # instantiates the second ``add`` proc
   for str in preorder(root):
     stdout.writeln(str)
diff --git a/lib/impure/db_mongo.nim b/lib/impure/db_mongo.nim
index d012f677f..dc8a808f2 100644
--- a/lib/impure/db_mongo.nim
+++ b/lib/impure/db_mongo.nim
@@ -58,7 +58,7 @@ proc open*(host: string = defaultHost, port: int = defaultPort): TDbConn {.
   ## be established.
   init(result)
   
-  let x = connect(result, host, port.cint)
+  let x = client(result, host, port.cint)
   if x != 0'i32:
     dbError(result, "cannot open: " & host)
 
@@ -119,7 +119,7 @@ proc insertId*(db: var TDbConn, namespace: string, data: PJsonNode): TOid {.
   ## the generated OID for the ``_id`` field.
   result = genOid()
   var x = jsonToBSon(data, result)
-  insert(db, namespace, x)
+  insert(db, namespace, x, nil)
   destroy(x)
 
 proc insert*(db: var TDbConn, namespace: string, data: PJsonNode) {.
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index f13cadaa2..96afc6f4f 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -689,5 +689,5 @@ when isMainModule:
   server.listen()
   d.register(server)
   
-  while d.poll(-1): nil
+  while d.poll(-1): discard
     
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 73da274b9..40ae57b5a 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -189,6 +189,16 @@ template dollarImpl(): stmt {.dirty.} =
 proc `$`*[A, B](t: TTable[A, B]): string =
   ## The `$` operator for hash tables.
   dollarImpl()
+  
+proc `==`*[A, B](s, t: TTable[A, B]): bool =
+  s.counter == t.counter and s.data == t.data
+  
+proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): TTable[C, B] =
+  ## Index the collection with the proc provided.
+  # TODO: As soon as supported, change collection: A to collection: A[B]
+  result = initTable[C, B]()
+  for item in collection:
+    result[index(item)] = item
 
 # ------------------------------ ordered table ------------------------------
 
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index 060f0e386..c38eb7063 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -480,7 +480,7 @@ proc untilElementEnd(x: var TXmlParser, result: PXmlNode,
         if htmlTag(x.elemName) in {tagOption, tagOptgroup}:
           errors.add(expected(x, result))
           break
-      else: nil
+      else: discard
       result.addNode(parse(x, errors))
     of xmlElementEnd: 
       if cmpIgnoreCase(x.elemName, result.tag) == 0: 
@@ -547,7 +547,7 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
     var u = entityToUtf8(x.rawData)
     if u.len != 0: result = newText(u)
     next(x)
-  of xmlEof: nil
+  of xmlEof: discard
 
 proc parseHtml*(s: PStream, filename: string, 
                 errors: var seq[string]): PXmlNode = 
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index 750c98516..c1b519b0b 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -476,12 +476,12 @@ when isMainModule:
   var client = irc("amber.tenthbit.net", nick="TestBot1234",
                    joinChans = @["#flood"])
   client.connect()
-  while True:
+  while true:
     var event: TIRCEvent
     if client.poll(event):
       case event.typ
       of EvConnected:
-        nil
+        discard
       of EvDisconnected:
         break
       of EvMsg:
diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim
index b57e0c45a..2db7fa660 100644
--- a/lib/pure/matchers.nim
+++ b/lib/pure/matchers.nim
@@ -54,7 +54,7 @@ proc parseInt*(s: string, value: var int, validRange: TSlice[int]) {.
   try:
     discard parseutils.parseInt(s, x, 0)
   except EOverflow:
-    nil
+    discard
   if x in validRange: value = x
 
 when isMainModule:
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index fbe0dda95..b3e74d2a1 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -28,7 +28,7 @@ proc hexbyte*(hex: char): int =
   of '0'..'9': result = (ord(hex) - ord('0'))
   of 'a'..'f': result = (ord(hex) - ord('a') + 10)
   of 'A'..'F': result = (ord(hex) - ord('A') + 10)
-  else: nil
+  else: discard
 
 proc parseOid*(str: cstring): TOid =
   ## parses an OID.
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 245a8446b..bb70f28b6 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1078,9 +1078,9 @@ when defined(windows):
         while true:
           var eend = strEnd(e)
           add(environment, $e)
-          e = cast[CString](cast[TAddress](eend)+1)
+          e = cast[cstring](cast[TAddress](eend)+1)
           if eend[1] == '\0': break
-        discard FreeEnvironmentStringsA(env)
+        discard freeEnvironmentStringsA(env)
       envComputed = true
 
 else:
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 9975bfcb3..6df85bbc6 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -455,7 +455,7 @@ when defined(Windows) and not defined(useNimRtl):
         ee, wwd, si, procInfo)
     else:
       success = winlean.createProcessA(nil,
-        cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
+        cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, si, procInfo)
     let lastError = osLastError()
 
     if poParentStreams notin options:
@@ -534,7 +534,7 @@ when defined(Windows) and not defined(useNimRtl):
         NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
     else:
       var res = winlean.createProcessA(nil, command, nil, nil, 0,
-        NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
+        NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
     if res == 0:
       osError(osLastError())
     else:
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index 5970f2090..4b25babec 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -149,7 +149,7 @@ proc readRow*(my: var TCsvParser, columns = 0): bool =
           of '\c': my.bufpos = handleCR(my, my.bufpos)
           of '\l': my.bufpos = handleLF(my, my.bufpos)
           else: break
-      of '\0': nil
+      of '\0': discard
       else: error(my, my.bufpos, my.sep & " expected")
       break
   
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index 31951e966..3f9686e1e 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -79,7 +79,7 @@ proc handleHexChar(c: var TSqlLexer, xi: var int) =
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
   else: 
-    nil
+    discard
 
 proc handleOctChar(c: var TSqlLexer, xi: var int) = 
   if c.buf[c.bufpos] in {'0'..'7'}:
@@ -373,7 +373,7 @@ proc getOperator(c: var TSqlLexer, tok: var TToken) =
     of '+':
       if not trailingPlusMinus and buf[pos+1] notin operators and
            tok.literal.len > 0: break
-    of '*', '<', '>', '=': nil
+    of '*', '<', '>', '=': discard
     else: break
     add(tok.literal, buf[pos])
     inc(pos)
@@ -1120,7 +1120,7 @@ proc rs(n: PSqlNode, s: var string, indent: int,
 proc ra(n: PSqlNode, s: var string, indent: int) =
   if n == nil: return
   case n.kind
-  of nkNone: nil
+  of nkNone: discard
   of nkIdent:
     if allCharsInSet(n.strVal, {'\33'..'\127'}):
       s.add(n.strVal)
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 16bbe1455..8b8bb3b03 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -96,7 +96,7 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
     ## &entity;
     errors.add(errorMsg(x, "unknown entity: " & x.entityName))
     next(x)
-  of xmlEof: nil
+  of xmlEof: discard
 
 proc parseXml*(s: PStream, filename: string, 
                errors: var seq[string]): PXmlNode = 
@@ -110,7 +110,7 @@ proc parseXml*(s: PStream, filename: string,
     of xmlElementOpen, xmlElementStart: 
       result = parse(x, errors)
       break
-    of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: nil # just skip it
+    of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: discard # just skip it
     of xmlError:
       errors.add(errorMsg(x))
     else:
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index ee5fe0647..5b641185e 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -195,14 +195,14 @@ else:
     importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
   proc setCurrentDirectoryA*(lpPathName: cstring): int32 {.
     importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
-  proc createDirectoryA*(pathName: cstring, security: Pointer=nil): int32 {.
+  proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {.
     importc: "CreateDirectoryA", dynlib: "kernel32", stdcall.}
   proc removeDirectoryA*(lpPathName: cstring): int32 {.
     importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall.}
   proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
     stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}
 
-  proc getModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {.
+  proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {.
     importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
 
 when useWinUnicode:
@@ -300,7 +300,7 @@ else:
                            dwFileAttributes: int32): WINBOOL {.
       stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
 
-  proc copyFileA*(lpExistingFileName, lpNewFileName: CString,
+  proc copyFileA*(lpExistingFileName, lpNewFileName: cstring,
                  bFailIfExists: cint): cint {.
     importc: "CopyFileA", stdcall, dynlib: "kernel32".}
 
diff --git a/lib/wrappers/mongo.nim b/lib/wrappers/mongo.nim
index 6673e8ddf..098b4f4d3 100644
--- a/lib/wrappers/mongo.nim
+++ b/lib/wrappers/mongo.nim
@@ -109,11 +109,12 @@ type
     cur*: cstring
     dataSize*: cint
     finished*: TBsonBool
-    stack*: array[0..32 - 1, cint]
+    ownsData*: TBsonBool
+    err*: cint
+    stackSize*: cint
     stackPos*: cint
-    err*: cint       ## Bitfield representing errors or warnings on this buffer 
-    errstr*: cstring ## A string representation of the most recent error
-                     ## or warning. 
+    stackPtr*: ptr csize
+    stack*: array[0..32 - 1, csize]
   
   TDate* = int64
 
@@ -141,6 +142,7 @@ proc print*(TBson: cstring, depth: cint) {.stdcall,
     importc: "bson_print_raw", dynlib: bsondll.}
   ## Print a string representation of a BSON object up to `depth`.
 
+
 proc data*(b: var TBson): cstring{.stdcall, importc: "bson_data", 
                                    dynlib: bsondll.}
   ## Return a pointer to the raw buffer stored by this bson object.
@@ -590,19 +592,30 @@ type
     hosts*: ptr THostPort    ## List of host/ports given by the replica set 
     name*: cstring           ## Name of the replica set. 
     primary_connected*: TBsonBool ## Primary node connection status. 
+
+  TWriteConcern*{.pure, final.} = object ## mongo_write_concern
+    w*: cint
+    wtimeout*: cint
+    j*: cint
+    fsync*: cint
+    mode*: cstring
+    cmd*: TBSon
   
   TMongo*{.pure, final.} = object ## mongo
-    primary*: ptr THostPort   ## Primary connection info. 
-    replset*: ptr TReplSet    ## replset object if connected to a replica set. 
-    sock*: cint               ## Socket file descriptor. 
-    flags*: cint              ## Flags on this connection object. 
-    conn_timeout_ms*: cint    ## Connection timeout in milliseconds. 
-    op_timeout_ms*: cint      ## Read and write timeout in milliseconds. 
-    connected*: TBsonBool     ## Connection status. 
-    err*: TError              ## Most recent driver error code. 
-    errstr*: array[0..128 - 1, char] ## String version of most recent driver error code. 
-    lasterrcode*: cint        ## getlasterror code given by the server on error. 
-    lasterrstr*: cstring      ## getlasterror string generated by server. 
+    primary*: ptr THostPort              ## Primary connection info. 
+    replset*: ptr TReplSet               ## replset object if connected to a replica set. 
+    sock*: cint                          ## Socket file descriptor. 
+    flags*: cint                         ## Flags on this connection object. 
+    conn_timeout_ms*: cint               ## Connection timeout in milliseconds. 
+    op_timeout_ms*: cint                 ## Read and write timeout in milliseconds. 
+    max_bson_size*: cint                 ## Largest BSON object allowed on this connection. 
+    connected*: TBsonBool                ## Connection status. 
+    write_concern*: TWriteConcern        ## The default write concern.
+    err*: TError                         ## Most recent driver error code. 
+    errcode*: cint                       ## Most recent errno or WSAGetLastError().
+    errstr*: array[0..128 - 1, char]     ## String version of most recent driver error code. 
+    lasterrcode*: cint                   ## getlasterror code given by the server on error. 
+    lasterrstr*: array[0..128 - 1, char] ## getlasterror string generated by server. 
   
   TCursor*{.pure, final.} = object ## cursor
     reply*: ptr TReply        ## reply is owned by cursor 
@@ -654,7 +667,11 @@ proc init*(conn: var TMongo){.stdcall, importc: "mongo_init", dynlib: mongodll.}
 
 proc connect*(conn: var TMongo, host: cstring = defaultHost, 
               port: cint = defaultPort): cint {.stdcall, 
-    importc: "mongo_connect", dynlib: mongodll.}
+    importc: "mongo_connect", dynlib: mongodll, deprecated.}
+  ## Connect to a single MongoDB server.
+proc client*(conn: var TMongo, host: cstring = defaultHost, 
+              port: cint = defaultPort): cint {.stdcall, 
+    importc: "mongo_client", dynlib: mongodll.}
   ## Connect to a single MongoDB server.
 
 proc replsetInit*(conn: var TMongo, name: cstring){.stdcall, 
@@ -714,7 +731,8 @@ proc destroy*(conn: var TMongo){.stdcall, importc: "mongo_destroy",
   ## You must always call this function when finished with the connection
   ## object.
 
-proc insert*(conn: var TMongo, ns: cstring, data: var TBson): cint{.stdcall, 
+proc insert*(conn: var TMongo, ns: cstring, data: var TBson,
+             custom_write_concern: ptr TWriteConcern): cint{.stdcall, 
     importc: "mongo_insert", dynlib: mongodll, discardable.}
   ## Insert a BSON document into a MongoDB server. This function
   ## will fail if the supplied BSON struct is not UTF-8 or if
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
new file mode 100644
index 000000000..f374d5504
--- /dev/null
+++ b/tests/collections/ttables.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/exprs/tstmtexprs.nim b/tests/exprs/tstmtexprs.nim
index 8149ec4b8..816e58cb1 100644
--- a/tests/exprs/tstmtexprs.nim
+++ b/tests/exprs/tstmtexprs.nim
@@ -1,5 +1,6 @@
 discard """
-  output: '''(bar: bar)
+  output: '''24
+(bar: bar)
 1244
 6
 abcdefghijklmnopqrstuvwxyz
@@ -8,6 +9,10 @@ abcdefghijklmnopqrstuvwxyz
 
 import strutils
 
+const fac4 = (var x = 1; for i in 1..4: x *= i; x)
+
+echo fac4
+
 when true:
   proc test(foo: proc (x, y: int): bool) =
     echo foo(5, 5)
diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim
index bd7bded28..6f2b8a1fe 100644
--- a/tests/gc/gcleak4.nim
+++ b/tests/gc/gcleak4.nim
@@ -6,7 +6,7 @@ when defined(GC_setMaxPause):
   GC_setMaxPause 2_000
 
 type
-  TExpr = object ## abstract base class for an expression
+  TExpr = object {.inheritable.} ## abstract base class for an expression
   PLiteral = ref TLiteral
   TLiteral = object of TExpr
     x: int
diff --git a/tests/gc/gcleak5.nim b/tests/gc/gcleak5.nim
new file mode 100644
index 000000000..9e2948729
--- /dev/null
+++ b/tests/gc/gcleak5.nim
@@ -0,0 +1,25 @@
+discard """
+  output: "success"
+"""
+
+import os, times
+
+proc main =
+  var i = 0
+  for ii in 0..50_000:
+    #while true:
+    var t = getTime()
+    var g = t.getGMTime()
+    #echo isOnStack(addr g)
+    
+    if i mod 100 == 0:
+      let om = getOccupiedMem()
+      #echo "memory: ", om
+      if om > 100_000: quit "leak"
+     
+    inc(i)
+    sleep(1)
+
+  echo "success"
+
+main()
diff --git a/tests/macros/tdebugstmt.nim b/tests/macros/tdebugstmt.nim
new file mode 100644
index 000000000..865dc436a
--- /dev/null
+++ b/tests/macros/tdebugstmt.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''a[0]: 42
+a[1]: 45
+x: some string'''
+"""
+
+import macros
+
+macro debug(n: varargs[expr]): stmt =
+  # `n` is a Nimrod AST that contains the whole macro invocation
+  # this macro returns a list of statements:
+  result = newNimNode(nnkStmtList, n)
+  # iterate over any argument that is passed to this macro:
+  for i in 0..n.len-1:
+    # add a call to the statement list that writes the expression;
+    # `toStrLit` converts an AST to its string representation:
+    add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+    # add a call to the statement list that writes ": "
+    add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+    # add a call to the statement list that writes the expressions value:
+    add(result, newCall("writeln", newIdentNode("stdout"), n[i]))
+
+var
+  a: array [0..10, int]
+  x = "some string"
+a[0] = 42
+a[1] = 45
+
+debug(a[0], a[1], x)
diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim
index 37de1262f..7ab652c82 100644
--- a/tests/stdlib/talgorithm.nim
+++ b/tests/stdlib/talgorithm.nim
@@ -1,14 +1,8 @@
-import unittest
 import algorithm
 
-suite "product":
-  test "empty input":
-    check product[int](newSeq[seq[int]]()) == newSeq[seq[int]]()
-  test "bit more empty input":
-    check product[int](@[newSeq[int](), @[], @[]]) == newSeq[seq[int]]()
-  test "a simple case of one element":
-    check product(@[@[1,2]]) == @[@[1,2]]
-  test "two elements":
-    check product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]]
-  test "three elements":
-    check product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]]
+doAssert product[int](newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
+doAssert product[int](@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
+doAssert product(@[@[1,2]]) == @[@[1,2]], "a simple case of one element"
+doAssert product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]], "two elements"
+doAssert product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]], "three elements"
+doAssert product(@[@[1,2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
diff --git a/tests/template/tprefer_immediate.nim b/tests/template/tprefer_immediate.nim
new file mode 100644
index 000000000..578f447b0
--- /dev/null
+++ b/tests/template/tprefer_immediate.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''immediate'''
+"""
+
+# Test that immediate templates are preferred over non-immediate templates
+
+template foo(a, b: expr) = echo "foo expr"
+
+template foo(a, b: int) = echo "foo int"
+template foo(a, b: float) = echo "foo float"
+template foo(a, b: string) = echo "foo string"
+template foo(a, b: expr) {.immediate.} = echo "immediate"
+template foo(a, b: bool) = echo "foo bool"
+template foo(a, b: char) = echo "foo char"
+
+foo(undeclaredIdentifier, undeclaredIdentifier2)
+
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 5dd841447..442dd1212 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -123,9 +123,14 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
   test "gcleak2"
   test "gctest"
   test "gcleak3"
+  test "gcleak4"
+  test "gcleak5"
   test "weakrefs"
   test "cycleleak"
   test "closureleak"
+  test "refarrayleak"
+  test "stackrefleak"
+  
 
 # ------------------------- threading tests -----------------------------------
 
diff --git a/todo.txt b/todo.txt
index fd424ad5e..738e9b3fa 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,13 +1,11 @@
 version 0.9.4
 =============
 
-- fix macros\tstringinterp.nim
-- test and fix showoff; add debug example to showoff
-- test and fix stdlib
-- test and fix misc
 - fix GC issues
+- fix macros\tstringinterp.nim
+- test and fix showoff
 - test C source code generation
-- test and fix closures
+- fix closures
 - test and fix exception handling
 - implement 'union' and 'bits' pragmas
 
@@ -22,7 +20,6 @@ Bugs
 - compilation of niminst takes way too long. looks like a regression
 - docgen: sometimes effects are listed twice
 - 'result' is not properly cleaned for NRVO --> use uninit checking instead
-- sneaking with qualifiedLookup() is really broken!
 - blocks can "export" an identifier but the CCG generates {} for them ...
 - osproc execProcesses can deadlock if all processes fail (as experienced
   in c++ mode)