summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--[-rwxr-xr-x]build.sh0
-rw-r--r--compiler/ccgexprs.nim10
-rw-r--r--compiler/ccgstmts.nim2
-rw-r--r--compiler/commands.nim18
-rw-r--r--compiler/extccomp.nim22
-rw-r--r--compiler/parser.nim1
-rw-r--r--compiler/semexprs.nim11
-rw-r--r--compiler/sigmatch.nim12
-rw-r--r--config/nim.cfg12
-rw-r--r--doc/lib.txt9
-rw-r--r--lib/posix/posix.nim15
-rw-r--r--lib/pure/basic3d.nim2
-rw-r--r--lib/pure/collections/sets.nim14
-rw-r--r--lib/pure/collections/tables.nim218
-rw-r--r--lib/pure/matchers.nim2
-rw-r--r--lib/pure/os.nim12
-rw-r--r--lib/windows/winlean.nim8
-rw-r--r--readme.md2
-rw-r--r--tests/collections/ttables.nim2
-rw-r--r--tests/manyloc/argument_parser/argument_parser.nim2
-rw-r--r--tests/metatype/tstaticvector.nim17
-rw-r--r--tests/parser/twhen_in_enum.nim11
-rw-r--r--tests/tuples/tgeneric_tuple.nim9
-rw-r--r--tests/types/tauto_canbe_void.nim9
-rw-r--r--web/website.ini1
25 files changed, 289 insertions, 132 deletions
diff --git a/build.sh b/build.sh
index 139c28359..139c28359 100755..100644
--- a/build.sh
+++ b/build.sh
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 9b45c4492..6ed4d361c 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2107,17 +2107,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     discard
   of nkPragma: genPragma(p, n)
   of nkPragmaBlock: expr(p, n.lastSon, d)
-  of nkProcDef, nkMethodDef, nkConverterDef: 
-    if (n.sons[genericParamsPos].kind == nkEmpty):
+  of nkProcDef, nkMethodDef, nkConverterDef:
+    if n.sons[genericParamsPos].kind == nkEmpty:
       var prc = n.sons[namePos].sym
       # due to a bug/limitation in the lambda lifting, unused inner procs
       # are not transformed correctly. We work around this issue (#411) here
       # by ensuring it's no inner proc (owner is a module):
-      #
-      # We also check whether the proc captures its environment here to
-      # prevent issue #1642.
-      if prc.skipGenericOwner.kind == skModule and
-         tfCapturesEnv in prc.typ.flags:
+      if prc.skipGenericOwner.kind == skModule:
         if (optDeadCodeElim notin gGlobalOptions and
             sfDeadCodeElim notin getModule(prc).flags) or
             ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 18705c974..61568c9e6 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -48,7 +48,7 @@ proc genVarTuple(p: BProc, n: PNode) =
     return
   genLineDir(p, n)
   initLocExpr(p, n.sons[L-1], tup)
-  var t = tup.t
+  var t = tup.t.getUniqueType
   for i in countup(0, L-3): 
     var v = n.sons[i].sym
     if sfCompileTime in v.flags: continue
diff --git a/compiler/commands.nim b/compiler/commands.nim
index c81b81d19..c52515c76 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -141,7 +141,7 @@ proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
   
 proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, 
-                         info: TLineInfo) = 
+                         info: TLineInfo; orig: string) = 
   var id = ""  # arg = "X]:on|off"
   var i = 0
   var n = hintMin
@@ -149,17 +149,17 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
     add(id, arg[i])
     inc(i)
   if i < len(arg) and (arg[i] == ']'): inc(i)
-  else: invalidCmdLineOption(pass, arg, info)
+  else: invalidCmdLineOption(pass, orig, info)
   if i < len(arg) and (arg[i] in {':', '='}): inc(i)
-  else: invalidCmdLineOption(pass, arg, info)
-  if state == wHint: 
+  else: invalidCmdLineOption(pass, orig, info)
+  if state == wHint:
     var x = findStr(msgs.HintsToStr, id)
     if x >= 0: n = TNoteKind(x + ord(hintMin))
-    else: invalidCmdLineOption(pass, arg, info)
-  else: 
+    else: localError(info, "unknown hint: " & id)
+  else:
     var x = findStr(msgs.WarningsToStr, id)
     if x >= 0: n = TNoteKind(x + ord(warnMin))
-    else: invalidCmdLineOption(pass, arg, info)
+    else: localError(info, "unknown warning: " & id)
   case whichKeyword(substr(arg, i))
   of wOn: incl(gNotes, n)
   of wOff: excl(gNotes, n)
@@ -368,8 +368,8 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
       defineSymbol("nogc")
     else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
   of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
-  of "warning": processSpecificNote(arg, wWarning, pass, info)
-  of "hint": processSpecificNote(arg, wHint, pass, info)
+  of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
+  of "hint": processSpecificNote(arg, wHint, pass, info, switch)
   of "hints": processOnOffSwitch({optHints}, arg, pass, info)
   of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
   of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 1083b7590..546849c0b 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -380,7 +380,7 @@ proc setCC*(ccname: string) =
   cCompiler = nameToCC(ccname)
   if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
   compileOptions = getConfigVar(cCompiler, ".options.always")
-  linkOptions = getConfigVar(cCompiler, ".options.linker")
+  linkOptions = ""
   ccompilerpath = getConfigVar(cCompiler, ".path")
   for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
   defineSymbol(CC[cCompiler].name)
@@ -389,8 +389,8 @@ proc addOpt(dest: var string, src: string) =
   if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
   add(dest, src)
 
-proc addLinkOption*(option: string) = 
-  if find(linkOptions, option, 0) < 0: addOpt(linkOptions, option)
+proc addLinkOption*(option: string) =
+  addOpt(linkOptions, option)
 
 proc addCompileOption*(option: string) = 
   if strutils.find(compileOptions, option, 0) < 0: 
@@ -401,7 +401,7 @@ proc initVars*() =
   for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
   defineSymbol(CC[cCompiler].name)
   addCompileOption(getConfigVar(cCompiler, ".options.always"))
-  addLinkOption(getConfigVar(cCompiler, ".options.linker"))
+  #addLinkOption(getConfigVar(cCompiler, ".options.linker"))
   if len(ccompilerpath) == 0:
     ccompilerpath = getConfigVar(cCompiler, ".path")
 
@@ -553,13 +553,13 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
   cfile = quoteShell(cfile)
   result = quoteShell(compilePattern % [
     "file", cfile, "objfile", objfile, "options", options,
-    "include", includeCmd, "nimrod", getPrefixDir(),
+    "include", includeCmd, "nim", getPrefixDir(),
     "nim", getPrefixDir(), "lib", libpath])
   add(result, ' ')
   addf(result, CC[c].compileTmpl, [
     "file", cfile, "objfile", objfile,
     "options", options, "include", includeCmd,
-    "nimrod", quoteShell(getPrefixDir()),
+    "nim", quoteShell(getPrefixDir()),
     "nim", quoteShell(getPrefixDir()),
     "lib", quoteShell(libpath)])
 
@@ -679,15 +679,16 @@ proc callCCompiler*(projectfile: string) =
         if not exefile.isAbsolute():
           exefile = joinPath(splitFile(projectfile).dir, exefile)
       exefile = quoteShell(exefile)
-      let linkOptions = getLinkOptions()
+      let linkOptions = getLinkOptions() & " " & 
+                        getConfigVar(cCompiler, ".options.linker")
       linkCmd = quoteShell(linkCmd % ["builddll", builddll,
           "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
-          "exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
+          "exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
       linkCmd.add ' '
       addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
           "buildgui", buildgui, "options", linkOptions,
           "objfiles", objfiles, "exefile", exefile,
-          "nimrod", quoteShell(getPrefixDir()),
+          "nim", quoteShell(getPrefixDir()),
           "lib", quoteShell(libpath)])
     if optCompileOnly notin gGlobalOptions:
       if gVerbosity == 1:
@@ -716,7 +717,8 @@ proc writeMapping*(gSymbolMapping: PRope) =
   app(code, strutils.escape(getCompileOptions()))
   
   app(code, "\n[Linker]\nFlags=")
-  app(code, strutils.escape(getLinkOptions()))
+  app(code, strutils.escape(getLinkOptions() & " " & 
+                            getConfigVar(cCompiler, ".options.linker")))
 
   app(code, "\n[Environment]\nlibpath=")
   app(code, strutils.escape(libpath))
diff --git a/compiler/parser.nim b/compiler/parser.nim
index f249b37c8..8fbf033d8 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1597,6 +1597,7 @@ proc parseEnum(p: var TParser): PNode =
   optInd(p, result)
   while true:
     var a = parseSymbol(p)
+    if a.kind == nkEmpty: return
     if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
       add(result, a)
       break
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 55d2656e0..10e17d59a 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -686,7 +686,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     # implicit statics.
     if n.len > 1:
       for i in 1 .. <n.len:
-        if n[i].typ.kind != tyStatic or tfUnresolved notin n[i].typ.flags:
+        # see bug #2113, it's possible that n[i].typ for errornous code:
+        if n[i].typ.isNil or n[i].typ.kind != tyStatic or
+            tfUnresolved notin n[i].typ.flags:
           break maybeLabelAsStatic
       n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
       n.typ.flags.incl tfUnresolved
@@ -1337,7 +1339,12 @@ proc semProcBody(c: PContext, n: PNode): PNode =
   
   if c.p.owner.kind notin {skMacro, skTemplate} and
      c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
-    localError(c.p.resultSym.info, errCannotInferReturnType)
+    if isEmptyType(result.typ):
+      # we inferred a 'void' return type:
+      c.p.resultSym.typ = nil
+      c.p.owner.typ.sons[0] = nil
+    else:
+      localError(c.p.resultSym.info, errCannotInferReturnType)
 
   closeScope(c)
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 00802e69b..7fbf0f165 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1016,9 +1016,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         if result != isNone: put(c.bindings, f, aOrig)
       else:
         result = isNone
+    elif prev.kind == tyStatic:
+      if aOrig.kind == tyStatic:
+        result = typeRel(c, prev.lastSon, a)
+        if result != isNone and prev.n != nil:
+          if not exprStructuralEquivalent(prev.n, aOrig.n):
+            result = isNone
+      else: result = isNone
     else:
-      result = typeRel(c, prev, aOrig)
-      
+      # XXX endless recursion?
+      #result = typeRel(c, prev, aOrig)
+      result = isNone
   of tyTypeDesc:
     var prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
diff --git a/config/nim.cfg b/config/nim.cfg
index 8f5d7e8e7..ba0f4c581 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -10,6 +10,12 @@
 
 cc = gcc
 
+# additional options always passed to the compiler:
+--parallel_build: "0" # 0 to auto-detect number of processors
+
+hint[LineTooLong]=off
+#hint[XDeclaredButNotUsed]=off
+
 # example of how to setup a cross-compiler:
 arm.linux.gcc.exe = "arm-linux-gcc"
 arm.linux.gcc.linkerexe = "arm-linux-gcc"
@@ -66,12 +72,6 @@ path="$lib/pure/unidecode"
   opt:speed
 @end
 
-# additional options always passed to the compiler:
---parallel_build: "0" # 0 to auto-detect number of processors
-
-hint[LineTooLong]=off
-#hint[XDeclaredButNotUsed]=off
-
 @if unix:
   @if not bsd:
     # -fopenmp
diff --git a/doc/lib.txt b/doc/lib.txt
index b7c94b505..4185e6f74 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -189,6 +189,12 @@ Math libraries
   Floating-point environment. Handling of floating-point rounding and
   exceptions (overflow, zero-devide, etc.).
 
+* `basic2d <basic2d.html>`_
+  Basic 2d support with vectors, points, matrices and some basic utilities.
+
+* `basic3d <basic3d.html>`_
+  Basic 3d support with vectors, points, matrices and some basic utilities.
+
 
 Internet Protocols and Support
 ------------------------------
@@ -218,9 +224,6 @@ Internet Protocols and Support
 * `smtp <smtp.html>`_
   This module implement a simple SMTP client. 
 
-* `irc <irc.html>`_
-  This module implements an asynchronous IRC client.
-
 * `ftpclient <ftpclient.html>`_
   This module implements an FTP client.
 
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index fbd07ca25..52bef6de4 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -70,17 +70,10 @@ const
   STDIN_FILENO* = 0  ## File number of stdin;
   STDOUT_FILENO* = 1 ## File number of stdout;
 
-when defined(endb):
-  # to not break bootstrapping again ...
-  type
-    TDIR* {.importc: "DIR", header: "<dirent.h>",
-            final, pure, incompleteStruct.} = object
-      ## A type representing a directory stream.
-else:
-  type
-    TDIR* {.importc: "DIR", header: "<dirent.h>",
-            final, pure.} = object
-      ## A type representing a directory stream.
+type
+  TDIR* {.importc: "DIR", header: "<dirent.h>",
+          incompleteStruct.} = object
+    ## A type representing a directory stream.
 
 type
   SocketHandle* = distinct cint # The type used to represent socket descriptors
diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim
index c00764fc5..9a8e006ec 100644
--- a/lib/pure/basic3d.nim
+++ b/lib/pure/basic3d.nim
@@ -812,7 +812,7 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
   ## Computes the bisector between v1 and v2 as a normalized vector.
   ## If one of the input vectors has zero length, a normalized version
   ## of the other is returned. If both input vectors has zero length, 
-  ## an arbitrary normalized vector `v1`is returned.
+  ## an arbitrary normalized vector `v1` is returned.
   var
     vmag1=v1.len
     vmag2=v2.len
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 33fec1a18..4a20d00a4 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -276,7 +276,7 @@ proc excl*[A](s: var HashSet[A], key: A) =
         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
+      shallowCopy(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`.
@@ -313,9 +313,9 @@ proc init*[A](s: var HashSet[A], initialSize=64) =
   ## Initializes a hash set.
   ##
   ## 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()
+  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
+  ## guarantee that at runtime. All set variables must be initialized before
+  ## use with other procs from this module with the exception of `isValid()
   ## <#isValid,TSet[A]>`_ and `len() <#len,TSet[A]>`_.
   ##
   ## You can call this proc on a previously initialized hash set, which will
@@ -719,9 +719,9 @@ proc init*[A](s: var OrderedSet[A], initialSize=64) =
   ## Initializes an ordered hash set.
   ##
   ## 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()
+  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
+  ## guarantee that at runtime. All set variables must be initialized before
+  ## use with other procs from this module with the exception of `isValid()
   ## <#isValid,TOrderedSet[A]>`_ and `len() <#len,TOrderedSet[A]>`_.
   ##
   ## You can call this proc on a previously initialized ordered hash set to
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 671f767cf..25fe306c0 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -71,8 +71,7 @@ import
 {.pragma: myShallow.}
 
 type
-  SlotEnum = enum seEmpty, seFilled, seDeleted
-  KeyValuePair[A, B] = tuple[slot: SlotEnum, key: A, val: B]
+  KeyValuePair[A, B] = tuple[hcode: THash, key: A, val: B]
   KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
   Table* {.myShallow.}[A, B] = object ## generic hash table
     data: KeyValuePairSeq[A, B]
@@ -84,6 +83,14 @@ type
 when not defined(nimhygiene):
   {.pragma: dirty.}
 
+# 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 len*[A, B](t: Table[A, B]): int =
   ## returns the number of keys in `t`.
   result = t.counter
@@ -91,28 +98,28 @@ proc len*[A, B](t: Table[A, B]): int =
 iterator pairs*[A, B](t: Table[A, B]): tuple[key: A, val: B] =
   ## iterates over any (key, value) pair in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
 iterator mpairs*[A, B](t: var Table[A, B]): tuple[key: A, val: var B] =
   ## iterates over any (key, value) pair in the table `t`. The values
   ## can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].slot): yield (t.data[h].key, t.data[h].val)
 
 iterator keys*[A, B](t: Table[A, B]): A =
   ## iterates over any key in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].key
+    if isFilled(t.data[h].hcode): yield t.data[h].key
 
 iterator values*[A, B](t: Table[A, B]): B =
   ## iterates over any value in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 iterator mvalues*[A, B](t: var Table[A, B]): var B =
   ## iterates over any value in the table `t`. The values can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 const
   growthFactor = 2
@@ -121,26 +128,57 @@ proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
+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)
+
 proc nextTry(h, maxHash: THash): THash {.inline.} =
-  result = ((5 * h) + 1) and maxHash
+  result = (h + 1) and maxHash
+
+template rawGetKnownHCImpl() {.dirty.} =
+  var h: THash = hc and high(t.data)   # start with real hash value
+  while isFilled(t.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 t.data[h].hcode == hc and t.data[h].key == key:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
 
 template rawGetImpl() {.dirty.} =
-  var h: THash = hash(key) and high(t.data) # start with real hash value
-  while t.data[h].slot != seEmpty:
-    if t.data[h].key == key and t.data[h].slot == seFilled:
-      return h
+  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 rawGetDeepImpl() {.dirty.} =   # Search algo for unconditional add
+  hc = hash(key)
+  if hc == 0:
+    hc = 314159265
+  var h: THash = hc and high(t.data)
+  while isFilled(t.data[h].hcode):
     h = nextTry(h, high(t.data))
-  result = -1
+  result = h
 
 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].val = val
-  data[h].slot = seFilled
+  data[h].hcode = hc
+
+proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
+  rawGetDeepImpl()
 
-proc rawGet[A, B](t: Table[A, B], key: A): int =
+proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
   rawGetImpl()
 
 proc `[]`*[A, B](t: Table[A, B], key: A): B =
@@ -148,55 +186,68 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B =
   ## default empty value for the type `B` is returned
   ## and no exception is raised. One can check with ``hasKey`` whether the key
   ## exists.
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
 
 proc mget*[A, B](t: var Table[A, B], key: A): var B =
   ## retrieves the value at ``t[key]``. The value can be modified.
   ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
   else: raise newException(KeyError, "key not found: " & $key)
 
 iterator allValues*[A, B](t: Table[A, B]; key: A): B =
   ## iterates over any value in the table `t` that belongs to the given `key`.
   var h: THash = hash(key) and high(t.data)
-  while t.data[h].slot != seEmpty:
-    if t.data[h].key == key and t.data[h].slot == seFilled:
+  while isFilled(t.data[h].hcode):
+    if t.data[h].key == key:
       yield t.data[h].val
     h = nextTry(h, high(t.data))
 
 proc hasKey*[A, B](t: Table[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
-  result = rawGet(t, key) >= 0
+  var hc: THash
+  result = rawGet(t, key, hc) >= 0
 
 proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
-                     key: A, val: B) =
+                     key: A, val: B, hc: THash, h: THash) =
   rawInsertImpl()
 
 proc enlarge[A, B](t: var Table[A, B]) =
   var n: KeyValuePairSeq[A, B]
   newSeq(n, len(t.data) * growthFactor)
-  for i in countup(0, high(t.data)):
-    if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val)
   swap(t.data, n)
+  for i in countup(0, high(n)):
+    if isFilled(n[i].hcode):
+      var j = -1 - rawGetKnownHC(t, n[i].key, n[i].hcode)
+      rawInsert(t, t.data, n[i].key, n[i].val, n[i].hcode, j)
 
 template addImpl() {.dirty.} =
   if mustRehash(len(t.data), t.counter): enlarge(t)
-  rawInsert(t, t.data, key, val)
+  var hc: THash
+  var j = rawGetDeep(t, key, hc)
+  rawInsert(t, t.data, key, val, hc, j)
   inc(t.counter)
 
 template putImpl() {.dirty.} =
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0:
     t.data[index].val = val
   else:
-    addImpl()
+    if mustRehash(len(t.data), t.counter):
+        enlarge(t)
+        index = rawGetKnownHC(t, key, hc)
+    rawInsert(t, t.data, key, val, hc, -1 - index)
+    inc(t.counter)
 
 when false:
   # not yet used:
   template hasKeyOrPutImpl() {.dirty.} =
-    var index = rawGet(t, key)
+    var hc: THash
+    var index = rawGet(t, key, hc)
     if index >= 0:
       t.data[index].val = val
       result = true
@@ -213,20 +264,37 @@ proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
 proc add*[A, B](t: var Table[A, B], key: A, val: B) =
   ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
   addImpl()
-  
+
+template doWhile(a: expr, b: stmt): stmt =
+  while true:
+    b
+    if not a: break
+
 proc del*[A, B](t: var Table[A, B], key: A) =
   ## deletes `key` from hash table `t`.
-  let index = rawGet(t, key)
-  if index >= 0:
-    t.data[index].slot = seDeleted
+  var hc: THash
+  var i = rawGet(t, key, hc)
+  let msk = high(t.data)
+  if i >= 0:
+    t.data[i].hcode = 0
     dec(t.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.
+      t.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(t.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = t.data[i].hcode and msk    # "home" location of key@i
+      shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
 
 proc initTable*[A, B](initialSize=64): Table[A, B] =
   ## creates a new hash table that is empty.
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
   assert isPowerOfTwo(initialSize)
   result.counter = 0
   newSeq(result.data, initialSize)
@@ -234,7 +302,7 @@ proc initTable*[A, B](initialSize=64): Table[A, B] =
 proc toTable*[A, B](pairs: openArray[tuple[key: A, 
                     val: B]]): Table[A, B] =
   ## creates a new hash table that contains the given `pairs`.
-  result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
+  result = initTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
 template dollarImpl(): stmt {.dirty.} =
@@ -252,7 +320,7 @@ template dollarImpl(): stmt {.dirty.} =
 proc `$`*[A, B](t: Table[A, B]): string =
   ## The `$` operator for hash tables.
   dollarImpl()
-  
+
 template equalsImpl() =
   if s.counter == t.counter:
     # different insertion orders mean different 'data' seqs, so we have
@@ -262,10 +330,10 @@ template equalsImpl() =
       if not t.hasKey(key): return false
       if t[key] != val: return false
     return true
-  
+
 proc `==`*[A, B](s, t: Table[A, B]): bool =
   equalsImpl()
-  
+
 proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] =
   ## Index the collection with the proc provided.
   # TODO: As soon as supported, change collection: A to collection: A[B]
@@ -280,28 +348,28 @@ proc len*[A, B](t: TableRef[A, B]): int =
 iterator pairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: B] =
   ## iterates over any (key, value) pair in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
 iterator mpairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: var B] =
   ## iterates over any (key, value) pair in the table `t`. The values
   ## can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
 iterator keys*[A, B](t: TableRef[A, B]): A =
   ## iterates over any key in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].key
+    if isFilled(t.data[h].hcode): yield t.data[h].key
 
 iterator values*[A, B](t: TableRef[A, B]): B =
   ## iterates over any value in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 iterator mvalues*[A, B](t: TableRef[A, B]): var B =
   ## iterates over any value in the table `t`. The values can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 proc `[]`*[A, B](t: TableRef[A, B], key: A): B =
   ## retrieves the value at ``t[key]``. If `key` is not in `t`,
@@ -326,7 +394,7 @@ proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
 proc add*[A, B](t: TableRef[A, B], key: A, val: B) =
   ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
   t[].add(key, val)
-  
+
 proc del*[A, B](t: TableRef[A, B], key: A) =
   ## deletes `key` from hash table `t`.
   t[].del(key)
@@ -360,7 +428,7 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B]
 
 type
   OrderedKeyValuePair[A, B] = tuple[
-    slot: SlotEnum, next: int, key: A, val: B]
+    hcode: THash, next: int, key: A, val: B]
   OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
   OrderedTable* {.
       myShallow.}[A, B] = object ## table that remembers insertion order
@@ -378,7 +446,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
   var h = t.first
   while h >= 0:
     var nxt = t.data[h].next
-    if t.data[h].slot == seFilled: yieldStmt
+    if isFilled(t.data[h].hcode): yieldStmt
     h = nxt
 
 iterator pairs*[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] =
@@ -409,7 +477,13 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
   forAllOrderedPairs:
     yield t.data[h].val
 
-proc rawGet[A, B](t: OrderedTable[A, B], key: A): int =
+proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: THash): int =
+  rawGetKnownHCImpl()
+
+proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inline.} =
+  rawGetDeepImpl()
+
+proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int =
   rawGetImpl()
 
 proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
@@ -417,23 +491,26 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
   ## default empty value for the type `B` is returned
   ## and no exception is raised. One can check with ``hasKey`` whether the key
   ## exists.
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
 
 proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
   ## retrieves the value at ``t[key]``. The value can be modified.
   ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
   else: raise newException(KeyError, "key not found: " & $key)
 
 proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
-  result = rawGet(t, key) >= 0
+  var hc: THash
+  result = rawGet(t, key, hc) >= 0
 
 proc rawInsert[A, B](t: var OrderedTable[A, B], 
                      data: var OrderedKeyValuePairSeq[A, B],
-                     key: A, val: B) =
+                     key: A, val: B, hc: THash, h: THash) =
   rawInsertImpl()
   data[h].next = -1
   if t.first < 0: t.first = h
@@ -446,12 +523,13 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
   var h = t.first
   t.first = -1
   t.last = -1
+  swap(t.data, n)
   while h >= 0:
-    var nxt = t.data[h].next
-    if t.data[h].slot == seFilled: 
-      rawInsert(t, n, t.data[h].key, t.data[h].val)
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
+      rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
     h = nxt
-  swap(t.data, n)
 
 proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
@@ -466,7 +544,7 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
   assert isPowerOfTwo(initialSize)
   result.counter = 0
   result.first = -1
@@ -476,7 +554,7 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
 proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A, 
                            val: B]]): OrderedTable[A, B] =
   ## creates a new ordered hash table that contains the given `pairs`.
-  result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
+  result = initOrderedTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
 proc `$`*[A, B](t: OrderedTable[A, B]): string =
@@ -537,7 +615,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
   var h = t.first
   while h >= 0:
     var nxt = t.data[h].next
-    if t.data[h].slot == seFilled: yieldStmt
+    if isFilled(t.data[h].hcode): yieldStmt
     h = nxt
 
 iterator pairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: B] =
@@ -597,14 +675,14 @@ proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
   new(result)
   result[] = initOrderedTable[A, B]()
 
 proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A, 
                            val: B]]): OrderedTableRef[A, B] =
   ## creates a new ordered hash table that contains the given `pairs`.
-  result = newOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
+  result = newOrderedTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
 proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
@@ -665,7 +743,7 @@ proc rawGet[A](t: CountTable[A], key: A): int =
   while t.data[h].val != 0:
     if t.data[h].key == key: return h
     h = nextTry(h, high(t.data))
-  result = -1
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
 
 proc `[]`*[A](t: CountTable[A], key: A): int =
   ## retrieves the value at ``t[key]``. If `key` is not in `t`,
@@ -702,21 +780,27 @@ proc enlarge[A](t: var CountTable[A]) =
 proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
   ## puts a (key, value)-pair into `t`. `val` has to be positive.
   assert val > 0
-  putImpl()
+  var h = rawGet(t, key)
+  if h >= 0:
+    t.data[h].val = val
+  else:
+    h = -1 - h
+    t.data[h].key = key
+    t.data[h].val = val
 
 proc initCountTable*[A](initialSize=64): CountTable[A] =
   ## creates a new count table that is empty.
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc in this module.
   assert isPowerOfTwo(initialSize)
   result.counter = 0
   newSeq(result.data, initialSize)
 
 proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
   ## creates a new count table with every key in `keys` having a count of 1.
-  result = initCountTable[A](nextPowerOfTwo(keys.len+10))
+  result = initCountTable[A](rightSize(keys.len))
   for key in items(keys): result[key] = 1
 
 proc `$`*[A](t: CountTable[A]): string =
@@ -827,13 +911,13 @@ proc newCountTable*[A](initialSize=64): CountTableRef[A] =
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` method in this module.
   new(result)
   result[] = initCountTable[A](initialSize)
 
 proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
   ## creates a new count table with every key in `keys` having a count of 1.
-  result = newCountTable[A](nextPowerOfTwo(keys.len+10))
+  result = newCountTable[A](rightSize(keys.len))
   for key in items(keys): result[key] = 1
 
 proc `$`*[A](t: CountTableRef[A]): string =
diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim
index 1188be4ca..d55963c15 100644
--- a/lib/pure/matchers.nim
+++ b/lib/pure/matchers.nim
@@ -42,7 +42,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
   case toLower(x)
   of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
      "aero", "jobs", "museum": return true
-  return false
+  else: return false
 
 proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
   noSideEffect, rtl, extern: "nmatchParseInt".} =
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 14cbe07bb..820800a1a 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1010,8 +1010,16 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
 proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
   tags: [ReadIOEffect, WriteIOEffect].} =
   ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
-  if c_rename(source, dest) != 0'i32:
-    raise newException(OSError, $strerror(errno))
+  when defined(Windows):
+    when useWinUnicode:
+      let s = newWideCString(source)
+      let d = newWideCString(dest)
+      if moveFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError())
+    else:
+      if moveFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError())
+  else:
+    if c_rename(source, dest) != 0'i32:
+      raise newException(OSError, $strerror(errno))
 
 when not declared(ENOENT) and not defined(Windows):
   when NoFakeVars:
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 51a12141b..584f7cf48 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -284,6 +284,10 @@ when useWinUnicode:
                  bFailIfExists: cint): cint {.
     importc: "CopyFileW", stdcall, dynlib: "kernel32".}
 
+  proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString,
+                 bFailIfExists: cint): cint {.
+    importc: "MoveFileW", stdcall, dynlib: "kernel32".}
+
   proc getEnvironmentStringsW*(): WideCString {.
     stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
   proc freeEnvironmentStringsW*(para1: WideCString): int32 {.
@@ -308,6 +312,10 @@ else:
                  bFailIfExists: cint): cint {.
     importc: "CopyFileA", stdcall, dynlib: "kernel32".}
 
+  proc moveFileA*(lpExistingFileName, lpNewFileName: cstring,
+                 bFailIfExists: cint): cint {.
+    importc: "MoveFileA", stdcall, dynlib: "kernel32".}
+
   proc getEnvironmentStringsA*(): cstring {.
     stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
   proc freeEnvironmentStringsA*(para1: cstring): int32 {.
diff --git a/readme.md b/readme.md
index b08fa2291..2252ea52b 100644
--- a/readme.md
+++ b/readme.md
@@ -62,7 +62,7 @@ allowing you to create commercial applications.
 
 Read copying.txt for more details.
 
-Copyright (c) 2006-2014 Andreas Rumpf.
+Copyright (c) 2006-2015 Andreas Rumpf.
 All rights reserved.
 
 # Build Status
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index de4aaed5e..8534e6767 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -47,7 +47,7 @@ block tableTest1:
     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}")
+    "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
 
 block tableTest2:
   var t = initTable[string, float]()
diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim
index af671cd85..a507a08e4 100644
--- a/tests/manyloc/argument_parser/argument_parser.nim
+++ b/tests/manyloc/argument_parser/argument_parser.nim
@@ -302,7 +302,7 @@ template build_specification_lookup():
   ## Returns the table used to keep pointers to all of the specifications.
   var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification]
   result = initOrderedTable[string, ptr Tparameter_specification](
-    nextPowerOfTwo(expected.len))
+    tables.rightSize(expected.len))
   for i in 0..expected.len-1:
     for param_to_detect in expected[i].names:
       if result.hasKey(param_to_detect):
diff --git a/tests/metatype/tstaticvector.nim b/tests/metatype/tstaticvector.nim
new file mode 100644
index 000000000..c9923f469
--- /dev/null
+++ b/tests/metatype/tstaticvector.nim
@@ -0,0 +1,17 @@
+
+type
+  RectArray*[R, C: static[int], T] = distinct array[R * C, T]
+   
+  StaticMatrix*[R, C: static[int], T] = object
+    elements*: RectArray[R, C, T]
+   
+  StaticVector*[N: static[int], T] = StaticMatrix[N, 1, T]
+ 
+proc foo*[N, T](a: StaticVector[N, T]): T = 0.T
+proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T
+ 
+ 
+var a: StaticVector[3, int]
+ 
+echo foo(a) # OK
+echo foobar(a, a) # <--- hangs compiler 
diff --git a/tests/parser/twhen_in_enum.nim b/tests/parser/twhen_in_enum.nim
new file mode 100644
index 000000000..d4a3ea56a
--- /dev/null
+++ b/tests/parser/twhen_in_enum.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "identifier expected, but found 'keyword when'"
+"""
+
+# bug #2123
+type num = enum
+    NUM_NONE = 0
+    NUM_ALL = 1
+    when defined(macosx): NUM_OSX = 10 # only this differs for real
+    NUM_XTRA = 20
+
diff --git a/tests/tuples/tgeneric_tuple.nim b/tests/tuples/tgeneric_tuple.nim
new file mode 100644
index 000000000..32f081596
--- /dev/null
+++ b/tests/tuples/tgeneric_tuple.nim
@@ -0,0 +1,9 @@
+# bug #2121
+
+type
+  Item[K,V] = tuple
+    key: K
+    value: V
+
+var q = newseq[Item[int,int]](0)
+let (x,y) = q[0]
diff --git a/tests/types/tauto_canbe_void.nim b/tests/types/tauto_canbe_void.nim
new file mode 100644
index 000000000..60e83c510
--- /dev/null
+++ b/tests/types/tauto_canbe_void.nim
@@ -0,0 +1,9 @@
+
+import future
+
+template tempo(s: expr) =
+  s("arg")
+
+tempo((s: string)->auto => echo(s))
+tempo((s: string) => echo(s))
+
diff --git a/web/website.ini b/web/website.ini
index c0a648c56..6757abcd8 100644
--- a/web/website.ini
+++ b/web/website.ini
@@ -61,6 +61,7 @@ srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/futu
 srcdoc2: "pure/md5"
 srcdoc2: "posix/posix"
 srcdoc2: "pure/fenv"
+srcdoc2: "pure/basic2d;pure/basic3d"
 
 ; Note: everything under 'webdoc' doesn't get listed in the index, so wrappers
 ; should live here