summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgcalls.nim2
-rw-r--r--compiler/ccgstmts.nim3
-rw-r--r--compiler/ccgutils.nim48
-rw-r--r--compiler/nimsuggest/nimsuggest.nim10
-rw-r--r--compiler/seminst.nim21
-rw-r--r--compiler/semtempl.nim2
-rw-r--r--compiler/semtypes.nim10
-rw-r--r--compiler/semtypinst.nim1
-rw-r--r--compiler/sigmatch.nim3
-rw-r--r--compiler/vmdeps.nim9
-rw-r--r--doc/gc.txt4
-rw-r--r--doc/manual/typedesc.txt2
-rw-r--r--koch.nim7
-rw-r--r--lib/core/macros.nim6
-rw-r--r--lib/pure/httpserver.nim2
-rw-r--r--lib/pure/net.nim2
-rw-r--r--lib/pure/selectors.nim13
-rw-r--r--lib/pure/sockets.nim2
-rw-r--r--lib/system/sysio.nim2
-rw-r--r--tests/casestmt/tcase_emptyset_when.nim24
-rw-r--r--tests/macros/tmacrotypes.nim14
-rw-r--r--tests/macros/tnimnode_for_runtime.nim (renamed from tests/macros/tnimrodnode_for_runtime.nim)1
-rw-r--r--tests/macros/tsame_name_497.nim4
-rw-r--r--tests/macros/typesapi.nim17
-rw-r--r--tests/template/tparams_gensymed.nim29
-rw-r--r--tests/testament/specs.nim4
-rw-r--r--tests/testament/tester.nim15
-rw-r--r--todo.txt1
28 files changed, 190 insertions, 68 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index fb878a83e..200ff91e0 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -133,7 +133,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
     var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
     result = openArrayLoc(p, n)
   elif ccgIntroducedPtr(param):
-    initLocExprSingleUse(p, n, a)
+    initLocExpr(p, n, a)
     result = addrLoc(a)
   elif p.module.compileToCpp and param.typ.kind == tyVar and 
       n.kind == nkHiddenAddr:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 61568c9e6..a4938c9ac 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -203,7 +203,8 @@ proc genSingleVar(p: BProc, a: PNode) =
     registerGcRoot(p, v)
   else:
     let imm = isAssignedImmediately(a.sons[2])
-    if imm and p.module.compileToCpp and p.splitDecls == 0:
+    if imm and p.module.compileToCpp and p.splitDecls == 0 and
+        not containsHiddenPointer(v.typ):
       # C++ really doesn't like things like 'Foo f; f = x' as that invokes a
       # parameterless constructor followed by an assignment operator. So we
       # generate better code here:
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index e4ce0aa6c..134619d4a 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -69,7 +69,20 @@ when false:
   proc echoStats*() =
     for i in countup(low(TTypeKind), high(TTypeKind)): 
       echo i, " ", gTypeTable[i].counter
-  
+
+proc slowSearch(key: PType; k: TTypeKind): PType =
+  # tuples are quite horrible as C does not support them directly and
+  # tuple[string, string] is a (strange) subtype of
+  # tuple[nameA, nameB: string]. This bites us here, so we
+  # use 'sameBackendType' instead of 'sameType'.
+  if idTableHasObjectAsKey(gTypeTable[k], key): return key
+  for h in countup(0, high(gTypeTable[k].data)):
+    var t = PType(gTypeTable[k].data[h].key)
+    if t != nil and sameBackendType(t, key): 
+      return t
+  idTablePut(gTypeTable[k], key, key)
+  result = key
+
 proc getUniqueType*(key: PType): PType = 
   # this is a hotspot in the compiler!
   if key == nil: return 
@@ -96,23 +109,20 @@ proc getUniqueType*(key: PType): PType =
     #if obj.sym != nil and obj.sym.name.s == "TOption":
     #  echo "for ", typeToString(key), " I returned "
     #  debug result
+  of tyPtr, tyRef, tyVar:
+    let elemType = lastSon(key)
+    if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}:
+      # no canonicalization for integral types, so that e.g. ``ptr pid_t`` is
+      # produced instead of ``ptr NI``.
+      result = key
+    else:
+      result = slowSearch(key, k)
   of tyArrayConstr, tyGenericInvocation, tyGenericBody,
      tyOpenArray, tyArray, tySet, tyRange, tyTuple,
-     tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
-    # tuples are quite horrible as C does not support them directly and
-    # tuple[string, string] is a (strange) subtype of
-    # tuple[nameA, nameB: string]. This bites us here, so we 
-    # use 'sameBackendType' instead of 'sameType'.
-
+     tySequence, tyForward, tyVarargs, tyProxy:
     # we have to do a slow linear search because types may need
     # to be compared by their structure:
-    if idTableHasObjectAsKey(gTypeTable[k], key): return key 
-    for h in countup(0, high(gTypeTable[k].data)): 
-      var t = PType(gTypeTable[k].data[h].key)
-      if t != nil and sameBackendType(t, key): 
-        return t
-    idTablePut(gTypeTable[k], key, key)
-    result = key
+    result = slowSearch(key, k)
   of tyObject:
     if tfFromGeneric notin key.flags:
       # fast case; lookup per id suffices:
@@ -139,14 +149,8 @@ proc getUniqueType*(key: PType): PType =
       result = key
     else:
       # ugh, we need the canon here:
-      if idTableHasObjectAsKey(gTypeTable[k], key): return key 
-      for h in countup(0, high(gTypeTable[k].data)): 
-        var t = PType(gTypeTable[k].data[h].key)
-        if t != nil and sameBackendType(t, key): 
-          return t
-      idTablePut(gTypeTable[k], key, key)
-      result = key
-      
+      result = slowSearch(key, k)
+
 proc tableGetType*(tab: TIdTable, key: PType): RootRef = 
   # returns nil if we need to declare this type
   result = idTableGet(tab, key)
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
index cac078127..b45ca475c 100644
--- a/compiler/nimsuggest/nimsuggest.nim
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -120,13 +120,17 @@ proc serve() =
     server.bindAddr(gPort, gAddress)
     var inp = "".TaintedString
     server.listen()
-    var stdoutSocket = newSocket()
-    msgs.writelnHook = proc (line: string) =
-      stdoutSocket.send(line & "\c\L")
+
     while true:
+      var stdoutSocket = newSocket()
+      msgs.writelnHook = proc (line: string) =
+        stdoutSocket.send(line & "\c\L")
+
       accept(server, stdoutSocket)
+
       stdoutSocket.readLine(inp)
       action inp.string
+
       stdoutSocket.send("\c\L")
       stdoutSocket.close()
 
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index d74584096..a10f27519 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -80,13 +80,9 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
     let s = n.sym
     var x = PSym(idTableGet(symMap, s))
     if x == nil:
-      if s.kind == skParam:
-        x = owner.typ.n[s.position+1].sym
-        internalAssert x.kind == skParam
-      else:
-        x = copySym(s, false)
-        x.owner = owner
-        idTablePut(symMap, s, x)
+      x = copySym(s, false)
+      x.owner = owner
+      idTablePut(symMap, s, x)
     n.sym = x
   else:
     for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
@@ -104,13 +100,18 @@ proc addProcDecls(c: PContext, fn: PSym) =
   
   maybeAddResult(c, fn, fn.ast)
 
-proc instantiateBody(c: PContext, n: PNode, result: PSym) =
+proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
   if n.sons[bodyPos].kind != nkEmpty:
     inc c.inGenericInst
     # add it here, so that recursive generic procs are possible:
     var b = n.sons[bodyPos]
     var symMap: TIdTable
     initIdTable symMap
+    if params != nil:
+      for i in 1 .. <params.len:
+        let param = params[i].sym
+        if sfGenSym in param.flags:
+          idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
     freshGenSyms(b, result, symMap)
     b = semProcBody(c, b)
     b = hloBody(c, b)
@@ -127,7 +128,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       openScope(c)
       var n = oldPrc.ast
       n.sons[bodyPos] = copyTree(s.getBody)
-      instantiateBody(c, n, oldPrc)
+      instantiateBody(c, n, nil, oldPrc)
       closeScope(c)
       popInfoContext()
 
@@ -249,7 +250,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
       pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
     if isNil(n.sons[bodyPos]):
       n.sons[bodyPos] = copyTree(fn.getBody)
-    instantiateBody(c, n, result)
+    instantiateBody(c, n, fn.typ.n, result)
     sideEffectsCheck(c, result)
     paramsTypeCheck(c, result.typ)
   else:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 47602368a..a48f045a2 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -494,7 +494,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
     semParamList(c, n.sons[paramsPos], gp, s)
     # a template's parameters are not gensym'ed even if that was originally the
     # case as we determine whether it's a template parameter in the template
-    # body by the absence of the skGenSym flag:
+    # body by the absence of the sfGenSym flag:
     for i in 1 .. s.typ.n.len-1:
       s.typ.n.sons[i].sym.flags.excl sfGenSym
     if sonsLen(gp) > 0:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index d9c7b6c92..4e3823f42 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -452,6 +452,7 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
 
 proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, 
                    covered: var BiggestInt) = 
+  
   for i in countup(0, sonsLen(branch) - 2): 
     var b = branch.sons[i]
     if b.kind == nkRange:
@@ -461,8 +462,11 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
     else:
       # constant sets and arrays are allowed:
       var r = semConstExpr(c, b)
-      # for ``{}`` we want to trigger the type mismatch in ``fitNode``:
-      if r.kind notin {nkCurly, nkBracket} or len(r) == 0:
+      if r.kind in {nkCurly, nkBracket} and len(r) == 0  and sonsLen(branch)==2:
+        # discarding ``{}`` and ``[]`` branches silently
+        delSon(branch, 0)
+        return
+      elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
         checkMinSonsLen(t, 1)
         branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
         inc(covered)
@@ -1189,7 +1193,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = typeExpr.typ.base
       if result.isMetaType:
         var preprocessed = semGenericStmt(c, n)
-        result = makeTypeFromExpr(c, preprocessed)
+        result = makeTypeFromExpr(c, preprocessed.copyTree)
   of nkIdent, nkAccQuoted:
     var s = semTypeIdent(c, n)
     if s.typ == nil: 
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 12fce1b84..452942ec0 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -369,6 +369,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
 
   of tyFromExpr:
     if cl.allowMetaTypes: return
+    assert t.n.typ != t
     var n = prepareNode(cl, t.n)
     n = cl.c.semConstExpr(cl.c, n)
     if n.typ.kind == tyTypeDesc:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index a782658b6..30d51aa29 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1187,8 +1187,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
 
     if argType.kind == tyStatic:
       if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags:
-        result = newNodeI(nkType, argOrig.info)
-        result.typ = makeTypeFromExpr(c, arg)
+        result = newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
         return
     else:
       var evaluated = c.semTryConstExpr(c, arg)
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 7fa88de6e..11d839c41 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -51,7 +51,12 @@ proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
   result = newNodeIT(nkBracketExpr, info, t)
   result.add atomicTypeX(name, t, info)
   for i in 0 .. < t.len:
-    result.add mapTypeToAst(t.sons[i], info)
+    if t.sons[i] == nil:
+      let void = atomicTypeX("void", t, info)
+      void.typ = newType(tyEmpty, t.owner)
+      result.add void
+    else:
+      result.add mapTypeToAst(t.sons[i], info)
 
 proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
   template atomicType(name): expr = atomicTypeX(name, t, info)
@@ -101,7 +106,7 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
   of tyPtr: result = mapTypeToBracket("ptr", t, info)
   of tyRef: result = mapTypeToBracket("ref", t, info)
   of tyVar: result = mapTypeToBracket("var", t, info)
-  of tySequence: result = mapTypeToBracket("sequence", t, info)
+  of tySequence: result = mapTypeToBracket("seq", t, info)
   of tyProc: result = mapTypeToBracket("proc", t, info)
   of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
   of tyRange:
diff --git a/doc/gc.txt b/doc/gc.txt
index ac8d46cfa..f51421bcd 100644
--- a/doc/gc.txt
+++ b/doc/gc.txt
@@ -87,14 +87,14 @@ is triggered.
 Time measurement
 ----------------
 
-The GC's way of measing time uses (see ``lib/system/timers.nim`` for the 
+The GC's way of measuring time uses (see ``lib/system/timers.nim`` for the 
 implementation):
 
 1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows.
 2) ``mach_absolute_time`` on Mac OS X.
 3) ``gettimeofday`` on Posix systems.
 
-As such it supports a resolution of nano seconds internally; however the API
+As such it supports a resolution of nanoseconds internally; however the API
 uses microseconds for convenience. 
 
 
diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt
index 97ab18b56..5087c1204 100644
--- a/doc/manual/typedesc.txt
+++ b/doc/manual/typedesc.txt
@@ -25,7 +25,7 @@ For the purposes of code generation, all static params are treated as
 generic params - the proc will be compiled separately for each unique
 supplied value (or combination of values). 
 
-Furthermore, the system module defines a `semistatic[T]` type than can be
+Furthermore, the system module defines a `semistatic[T]` type that can be
 used to declare procs accepting both static and run-time values, which can
 optimize their body according to the supplied param using the `isStatic(p)`
 predicate:
diff --git a/koch.nim b/koch.nim
index 535dae5ba..d365262c1 100644
--- a/koch.nim
+++ b/koch.nim
@@ -139,9 +139,6 @@ proc pdf(args="") =
 
 # -------------- boot ---------------------------------------------------------
 
-const
-  bootOptions = "" # options to pass to the bootstrap process
-
 proc findStartNim: string = 
   # we try several things before giving up:
   # * bin/nim
@@ -180,11 +177,13 @@ proc thVersion(i: int): string =
 proc boot(args: string) =
   var output = "compiler" / "nim".exe
   var finalDest = "bin" / "nim".exe
+  # default to use the 'c' command:
+  let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
   
   copyExe(findStartNim(), 0.thVersion)
   for i in 0..2:
     echo "iteration: ", i+1
-    exec i.thVersion & " c $# $# compiler" / "nim.nim" % [bootOptions, args]
+    exec i.thVersion & " $# $# compiler" / "nim.nim" % [bootOptions, args]
     if sameFileContent(output, i.thVersion):
       copyExe(output, finalDest)
       echo "executables are equal: SUCCESS!"
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index c6453aeaa..dbfb2ceb3 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -120,6 +120,8 @@ const
   nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
                    nnkCallStrLit}
 
+{.push warning[deprecated]: off.}
+
 proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild", noSideEffect.}
   ## get `n`'s `i`'th child.
 
@@ -808,3 +810,5 @@ when not defined(booting):
     macro payload: stmt {.gensym.} =
       result = parseStmt(e)
     payload()
+
+{.pop.}
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 38a068ea1..5efdbe297 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -363,7 +363,7 @@ proc run*(handleRequest: proc (client: Socket,
           port = Port(80)) =
   ## encapsulates the server object and main loop
   var s: TServer
-  open(s, port)
+  open(s, port, reuseAddr = true)
   #echo("httpserver running on port ", s.port)
   while true:
     next(s)
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 5e5c4f8ec..bed751542 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -454,6 +454,8 @@ proc close*(socket: Socket) =
         # shutdown i.e not wait for the peers "close notify" alert with a second
         # call to SSLShutdown
         let res = SSLShutdown(socket.sslHandle)
+        SSLFree(socket.sslHandle)
+        socket.sslHandle = nil
         if res == 0:
           discard
         elif res != 1:
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 2ed53ef3f..b6bc9dd3a 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -48,12 +48,21 @@ when defined(nimdoc):
                events: set[Event]): SelectorKey {.discardable.} =
     ## Updates the events which ``fd`` wants notifications for.
 
+  proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} =
+    ## Unregisters file descriptor ``fd`` from selector ``s``.
+
+  proc close*(s: Selector) =
+    ## Closes the selector
+
   proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
     ## The ``events`` field of the returned ``key`` contains the original events
     ## for which the ``fd`` was bound. This is contrary to the ``events`` field
     ## of the ``TReadyInfo`` tuple which determines which events are ready
     ## on the ``fd``.
 
+  proc newSelector*(): Selector =
+    ## Creates a new selector
+
   proc contains*(s: Selector, fd: SocketHandle): bool =
     ## Determines whether selector contains a file descriptor.
 
@@ -78,8 +87,6 @@ elif defined(linux):
   
   proc register*(s: Selector, fd: SocketHandle, events: set[Event],
       data: RootRef): SelectorKey {.discardable.} =
-    ## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
-    ## ``events``.
     var event = createEventStruct(events, fd)
     if events != {}:
       if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
@@ -92,7 +99,6 @@ elif defined(linux):
   
   proc update*(s: Selector, fd: SocketHandle,
       events: set[Event]): SelectorKey {.discardable.} =
-    ## Updates the events which ``fd`` wants notifications for.
     if s.fds[fd].events != events:
       if events == {}:
         # This fd is idle -- it should not be registered to epoll.
@@ -204,7 +210,6 @@ elif not defined(nimdoc):
 
   proc update*(s: Selector, fd: SocketHandle,
       events: set[Event]): SelectorKey {.discardable.} =
-    ## Updates the events which ``fd`` wants notifications for.
     if not s.fds.hasKey(fd):
       raise newException(ValueError, "File descriptor not found.")
 
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 8ac5d4f09..3afb545c8 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -657,6 +657,8 @@ proc close*(socket: Socket) =
   when defined(ssl):
     if socket.isSSL:
       discard SSLShutdown(socket.sslHandle)
+      SSLFree(socket.sslHandle)
+      socket.sslHandle = nil
 
 proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
   ## Searches the database from the beginning and finds the first entry for 
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 5d68d112e..a05398a09 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -188,7 +188,7 @@ when defined(windows) and not defined(useWinAnsi):
     proc wfopen(filename, mode: WideCString): pointer {.
       importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
     proc wfreopen(filename, mode: WideCString, stream: File): File {.
-      importc: "_wfreopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
+      importcpp: "_wfreopen((const wchar_t*)#, (const wchar_t*)#, #)", nodecl.}
   else:
     proc wfopen(filename, mode: WideCString): pointer {.
       importc: "_wfopen", nodecl.}
diff --git a/tests/casestmt/tcase_emptyset_when.nim b/tests/casestmt/tcase_emptyset_when.nim
new file mode 100644
index 000000000..e9b1ec2df
--- /dev/null
+++ b/tests/casestmt/tcase_emptyset_when.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tcaseofwhen.nim"
+  outputsub: "compiles for 1\ni am always two\ndefault for 3\nset is 4 not 5\narray is 6 not 7\ndefault for 8"
+  exitcode: "0"
+"""
+
+proc whenCase(a: int) =
+  case a
+  of (when compiles(whenCase(1)): 1 else: {}): echo "compiles for 1"
+  of {}: echo "me not fail"
+  of 2: echo "i am always two"
+  of []: echo "me neither"
+  of {4,5}: echo "set is 4 not 5"
+  of [6,7]: echo "array is 6 not 7"
+  of (when compiles(neverCompilesIBet()): 3 else: {}): echo "compiles for 3"
+  #of {},[]: echo "me neither"
+  else: echo "default for ", a
+
+whenCase(1)
+whenCase(2)
+whenCase(3)
+whenCase(4)
+whenCase(6)
+whenCase(8)
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
index f19aa2ddb..991668930 100644
--- a/tests/macros/tmacrotypes.nim
+++ b/tests/macros/tmacrotypes.nim
@@ -1,16 +1,16 @@
 discard """
-  disabled: true
+  nimout: '''void
+int'''
 """
 
-import macros, typetraits
+import macros
 
-macro checkType(ex, expected: expr): stmt {.immediate.} =
-  var t = ex.typ
-  assert t.name == expected.strVal
+macro checkType(ex: stmt; expected: expr): stmt =
+  var t = ex.getType()
+  echo t
 
 proc voidProc = echo "hello"
-proc intProc(a, b): int = 10
+proc intProc(a: int, b: float): int = 10
 
 checkType(voidProc(), "void")
 checkType(intProc(10, 20.0), "int")
-checkType(noproc(10, 20.0), "Error Type")
diff --git a/tests/macros/tnimrodnode_for_runtime.nim b/tests/macros/tnimnode_for_runtime.nim
index e73c8430f..69c7aedd2 100644
--- a/tests/macros/tnimrodnode_for_runtime.nim
+++ b/tests/macros/tnimnode_for_runtime.nim
@@ -1,6 +1,5 @@
 discard """
   output: "bla"
-  disabled: true
 """
 
 import macros
diff --git a/tests/macros/tsame_name_497.nim b/tests/macros/tsame_name_497.nim
index e49f9f6d8..ed5d5c6d8 100644
--- a/tests/macros/tsame_name_497.nim
+++ b/tests/macros/tsame_name_497.nim
@@ -1,3 +1,7 @@
+discard """
+  disabled: true
+"""
+
 import macro_bug
 
 type TObj = object
diff --git a/tests/macros/typesapi.nim b/tests/macros/typesapi.nim
new file mode 100644
index 000000000..670b39c9e
--- /dev/null
+++ b/tests/macros/typesapi.nim
@@ -0,0 +1,17 @@
+discard """
+  nimout: '''proc (x: int): string => typeDesc[proc[string, int]]
+proc (x: int): void => typeDesc[proc[void, int]]
+proc (x: int) => typeDesc[proc[void, int]]'''
+"""
+
+#2211
+
+import macros
+
+macro showType(t:stmt): stmt =
+  let ty = t.getType
+  echo t.repr, " => ", ty.repr
+
+showType(proc(x:int): string)
+showType(proc(x:int): void)
+showType(proc(x:int))
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
index 33940874d..6c4413866 100644
--- a/tests/template/tparams_gensymed.nim
+++ b/tests/template/tparams_gensymed.nim
@@ -31,3 +31,32 @@ var x: Something
 testB(x)
 
 
+# bug #2215
+# Test that templates in generics still work (regression to fix the
+# regression...)
+
+template forStatic(index: expr, slice: Slice[int], predicate: stmt):
+                   stmt {.immediate.} =
+  const a = slice.a
+  const b = slice.b
+  when a <= b:
+    template iteration(i: int) =
+      block:
+        const index = i
+        predicate
+    template iterateStartingFrom(i: int): stmt =
+      when i <= b:
+        iteration i
+        iterateStartingFrom i + 1
+    iterateStartingFrom a
+
+proc concreteProc(x: int) =
+  forStatic i, 0..3:
+    echo i
+
+proc genericProc(x: any) =
+  forStatic i, 0..3:
+    echo i
+
+concreteProc(7) # This works
+genericProc(7)  # This doesn't compile
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
index e079eed62..2a8a4ea24 100644
--- a/tests/testament/specs.nim
+++ b/tests/testament/specs.nim
@@ -48,6 +48,7 @@ type
     err*: TResultEnum
     substr*, sortoutput*: bool
     targets*: set[TTarget]
+    nimout*: string
 
 const
   targetToExt*: array[TTarget, string] = ["c", "cpp", "m", "js"]
@@ -94,6 +95,7 @@ proc parseSpec*(filename: string): TSpec =
   result.file = filename
   result.msg = ""
   result.outp = ""
+  result.nimout = ""
   result.ccodeCheck = ""
   result.cmd = cmdTemplate
   parseSpecAux:
@@ -124,6 +126,8 @@ proc parseSpec*(filename: string): TSpec =
     of "errormsg":
       result.msg = e.value
       result.action = actionReject
+    of "nimout":
+      result.nimout = e.value
     of "disabled":
       if parseCfgBool(e.value): result.err = reIgnored
     of "cmd": result.cmd = e.value
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 45643be10..881a41ce6 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -64,7 +64,9 @@ proc callCompiler(cmdTemplate, filename, options: string,
   var suc = ""
   var err = ""
   var x = newStringOfCap(120)
+  result.nimout = ""
   while outp.readLine(x.TaintedString) or running(p):
+    result.nimout.add(x & "\n")
     if x =~ pegOfInterest:
       # `err` should contain the last error/warning message
       err = x
@@ -112,7 +114,9 @@ proc addResult(r: var TResults, test: TTest,
                           expected = expected,
                           given = given)
   r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success)
-  if success notin {reSuccess, reIgnored}:
+  if success == reIgnored:
+    styledEcho styleBright, name, fgYellow, " [", $success, "]"
+  elif success != reSuccess:
     styledEcho styleBright, name, fgRed, " [", $success, "]"
     echo"Expected:"
     styledEcho styleBright, expected
@@ -151,6 +155,13 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) =
     except IOError:
       given.err = reCodeNotFound
 
+proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) =
+  if expectedNimout.len > 0:
+    let exp = expectedNimout.strip.replace("\C\L", "\L")
+    let giv = given.nimout.strip.replace("\C\L", "\L")
+    if exp notin giv:
+      given.err = reMsgsDiffer
+
 proc makeDeterministic(s: string): string =
   var x = splitLines(s)
   sort(x, system.cmp)
@@ -172,6 +183,7 @@ proc testSpec(r: var TResults, test: TTest) =
                                test.target)
       if given.err == reSuccess:
         codegenCheck(test, expected.ccodeCheck, given)
+        nimoutCheck(test, expected.nimout, given)
       r.addResult(test, "", given.msg, given.err)
       if given.err == reSuccess: inc(r.passed)
     of actionRun:
@@ -205,6 +217,7 @@ proc testSpec(r: var TResults, test: TTest) =
                 given.err = reOutputsDiffer
             if given.err == reSuccess:
               codeGenCheck(test, expected.ccodeCheck, given)
+              nimoutCheck(test, expected.nimout, given)
             if given.err == reSuccess: inc(r.passed)
             r.addResult(test, expected.outp, buf.string, given.err)
         else:
diff --git a/todo.txt b/todo.txt
index 79fe9d05a..3fed10aeb 100644
--- a/todo.txt
+++ b/todo.txt
@@ -10,6 +10,7 @@ version 0.10.4
 version 1.0
 ===========
 
+- figure out why C++ bootstrapping is so much slower
 - nimsuggest: auto-completion needs to work in 'class' macros
 - improve the docs for inheritance
 - The bitwise 'not' operator will be renamed to 'bnot' to