summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim396
-rw-r--r--compiler/ccgcalls.nim11
-rw-r--r--compiler/evalffi.nim1
-rw-r--r--compiler/evaltempl.nim10
-rw-r--r--compiler/guards.nim104
-rw-r--r--compiler/importer.nim2
-rw-r--r--compiler/jsgen.nim408
-rw-r--r--compiler/jstypes.nim2
-rw-r--r--compiler/lowerings.nim51
-rw-r--r--compiler/main.nim6
-rw-r--r--compiler/msgs.nim674
-rw-r--r--compiler/nim.nim.cfg1
-rw-r--r--compiler/parser.nim3
-rw-r--r--compiler/passes.nim98
-rw-r--r--compiler/renderer.nim484
-rw-r--r--compiler/semcall.nim81
-rw-r--r--compiler/semexprs.nim436
-rw-r--r--compiler/semgnrc.nim2
-rw-r--r--compiler/seminst.nim32
-rw-r--r--compiler/semparallel.nim4
-rw-r--r--compiler/sempass2.nim2
-rw-r--r--compiler/semstmts.nim191
-rw-r--r--compiler/semtypes.nim15
-rw-r--r--compiler/semtypinst.nim2
-rw-r--r--compiler/sigmatch.nim401
-rw-r--r--compiler/transf.nim265
-rw-r--r--compiler/types.nim501
-rw-r--r--compiler/typesrenderer.nim1
-rw-r--r--compiler/vm.nim2
-rw-r--r--config/nim.cfg4
-rw-r--r--doc/advopt.txt15
-rw-r--r--doc/basicopt.txt1
-rw-r--r--doc/lib.txt3
-rw-r--r--doc/manual/procs.txt4
-rw-r--r--lib/core/macros.nim2
-rw-r--r--lib/impure/osinfo_posix.nim87
-rw-r--r--lib/impure/osinfo_win.nim421
-rw-r--r--lib/impure/rdstdin.nim66
-rw-r--r--lib/nimbase.h2
-rw-r--r--lib/pure/algorithm.nim51
-rw-r--r--lib/pure/asyncdispatch.nim75
-rw-r--r--lib/pure/asyncfile.nim20
-rw-r--r--lib/pure/collections/sequtils.nim33
-rw-r--r--lib/pure/collections/tables.nim6
-rw-r--r--lib/pure/hashes.nim4
-rw-r--r--lib/pure/httpclient.nim10
-rw-r--r--lib/pure/logging.nim2
-rw-r--r--lib/pure/md5.nim6
-rw-r--r--lib/pure/net.nim49
-rw-r--r--lib/pure/os.nim2
-rw-r--r--lib/pure/parsexml.nim31
-rw-r--r--lib/pure/pegs.nim310
-rw-r--r--lib/pure/rawsockets.pretty.nim426
-rw-r--r--lib/pure/redis.nim16
-rw-r--r--lib/pure/terminal.nim18
-rw-r--r--lib/pure/times.nim22
-rw-r--r--lib/pure/unicode.nim22
-rw-r--r--lib/pure/uri.nim10
-rw-r--r--lib/system.nim251
-rw-r--r--lib/system/deepcopy.nim4
-rw-r--r--lib/system/gc.nim88
-rw-r--r--lib/system/gc2.nim20
-rw-r--r--lib/system/gc_ms.nim40
-rw-r--r--lib/system/mmdisp.nim60
-rw-r--r--lib/system/sysio.nim2
-rw-r--r--lib/system/sysstr.nim54
-rw-r--r--lib/wrappers/openssl.nim46
-rw-r--r--readme.md18
-rw-r--r--tests/assert/tfailedassert.nim2
-rw-r--r--tests/ccgbugs/tstringslice.nim24
-rw-r--r--tests/ccgbugs/tuple_canon.nim80
-rw-r--r--tests/deprecated/tdeprecated.nim4
-rw-r--r--tests/enum/tenumitems.nim2
-rw-r--r--tests/exprs/tresultwarning.nim6
-rw-r--r--tests/generics/tunique_type.nim7
-rw-r--r--tests/init/tuninit2.nim54
-rw-r--r--tests/manyloc/argument_parser/ex_wget.nim8
-rw-r--r--tests/misc/parsecomb.nim105
-rw-r--r--tests/misc/tissue710.nim2
-rw-r--r--tests/misc/tnoop.nim7
-rw-r--r--tests/misc/tparsecombnum.nim55
-rw-r--r--tests/modules/trecinca.nim4
-rw-r--r--tests/modules/trecincb.nim4
-rw-r--r--tests/objects/tobjconstr.nim26
-rw-r--r--tests/overload/toverprc.nim30
-rw-r--r--tests/overload/tprefer_specialized_generic.nim22
-rw-r--r--tests/overload/tprefer_tygenericinst.nim43
-rw-r--r--tests/overload/tsymtabchange_during_or.nim24
-rw-r--r--tests/overload/tsystemcmp.nim9
-rw-r--r--tests/parallel/tconvexhull.nim2
-rw-r--r--tests/parallel/tmissing_deepcopy.nim40
-rw-r--r--tests/parallel/tsimple_array_checks.nim41
-rw-r--r--tests/stdlib/tcount.nim29
-rw-r--r--tests/stdlib/tgetfileinfo.nim8
-rw-r--r--tests/stdlib/tnet.nim47
-rw-r--r--tests/template/texponential_eval.nim47
-rw-r--r--tests/template/twrongmapit.nim2
-rw-r--r--tests/template/utemplates.nim6
-rw-r--r--tests/testament/categories.nim11
-rw-r--r--tests/testament/htmlgen.nim39
-rw-r--r--tests/testament/tester.nim78
-rw-r--r--todo.txt3
-rw-r--r--tools/niminst/buildsh.tmpl2
-rw-r--r--web/question.txt5
-rw-r--r--web/website.ini1
105 files changed, 3745 insertions, 3621 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 1462d58d5..ab315877a 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -9,12 +9,12 @@
 
 # abstract syntax tree + symbol table
 
-import 
-  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, 
+import
+  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
   intsets, idgen
 
 type
-  TCallingConvention* = enum 
+  TCallingConvention* = enum
     ccDefault,                # proc has no explicit calling convention
     ccStdCall,                # procedure is stdcall
     ccCDecl,                  # cdecl
@@ -26,12 +26,12 @@ type
     ccClosure,                # proc has a closure
     ccNoConvention            # needed for generating proper C procs sometimes
 
-const 
-  CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", 
+const
+  CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
     "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
     "closure", "noconv"]
 
-type 
+type
   TNodeKind* = enum # order is extremely important, because ranges are used
                     # to check whether a node belongs to a certain class
     nkNone,               # unknown node kind: indicates an error
@@ -64,13 +64,13 @@ type
                           # end of atoms
     nkMetaNode_Obsolete,  # difficult to explain; represents itself
                           # (used for macros)
-    nkDotCall,            # used to temporarily flag a nkCall node; 
+    nkDotCall,            # used to temporarily flag a nkCall node;
                           # this is used
                           # for transforming ``s.len`` to ``len(s)``
 
     nkCommand,            # a call like ``p 2, 4`` without parenthesis
     nkCall,               # a call like p(x, y) or an operation like +(a, b)
-    nkCallStrLit,         # a call with a string literal 
+    nkCallStrLit,         # a call with a string literal
                           # x"abc" has two sons: nkIdent, nkRStrLit
                           # x"""abc""" has two sons: nkIdent, nkTripleStrLit
     nkInfix,              # a call like (a + b)
@@ -126,7 +126,7 @@ type
 
     nkAsgn,               # a = b
     nkFastAsgn,           # internal node for a fast ``a = b``
-                          # (no string copy) 
+                          # (no string copy)
     nkGenericParams,      # generic parameters
     nkFormalParams,       # formal parameters
     nkOfInherit,          # inherited from symbol
@@ -192,10 +192,11 @@ type
 
     nkWith,               # distinct with `foo`
     nkWithout,            # distinct without `foo`
-    
+
     nkTypeOfExpr,         # type(1+2)
     nkObjectTy,           # object body
     nkTupleTy,            # tuple body
+    nkTupleClassTy,       # tuple type class
     nkTypeClassTy,        # user-defined type class
     nkStaticTy,           # ``static[T]``
     nkRecList,            # list of object parts
@@ -226,7 +227,7 @@ type
   TSymFlag* = enum    # already 32 flags!
     sfUsed,           # read access of sym (for warnings) or simply used
     sfExported,       # symbol is exported from module
-    sfFromGeneric,    # symbol is instantiation of a generic; this is needed 
+    sfFromGeneric,    # symbol is instantiation of a generic; this is needed
                       # for symbol file generation; such symbols should always
                       # be written into the ROD file
     sfGlobal,         # symbol is at global scope
@@ -284,9 +285,9 @@ const
 
   sfAnon* = sfDiscardable
     # symbol name that was generated by the compiler
-    # the compiler will avoid printing such names 
+    # the compiler will avoid printing such names
     # in user messages.
-      
+
   sfNoForward* = sfRegister
     # forward declarations are not required (per module)
 
@@ -300,7 +301,7 @@ const
   # getting ready for the future expr/stmt merge
   nkWhen* = nkWhenStmt
   nkWhenExpr* = nkWhenStmt
-  nkEffectList* = nkArgList 
+  nkEffectList* = nkArgList
   # hacks ahead: an nkEffectList is a node with 4 children:
   exceptionEffects* = 0 # exceptions at position 0
   usesEffects* = 1      # read effects at position 1
@@ -321,7 +322,7 @@ type
                          # unless this is an instance of a generic alias type.
                          # then realInstance will be the tyGenericInst of the
                          # completely (recursively) resolved alias.
-                         
+
     tyGenericParam,      # ``a`` in the above patterns
     tyDistinct,
     tyEnum,
@@ -340,14 +341,14 @@ type
     tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
     tyFloat, tyFloat32, tyFloat64, tyFloat128,
     tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
-    tyBigNum, 
-    tyConst, tyMutable, tyVarargs, 
+    tyBigNum,
+    tyConst, tyMutable, tyVarargs,
     tyIter, # unused
     tyProxy # used as errornous type (for idetools)
-    
+
     tyBuiltInTypeClass #\
       # Type such as the catch-all object, tuple, seq, etc
-    
+
     tyUserTypeClass #\
       # the body of a user-defined type class
 
@@ -357,24 +358,24 @@ type
       # tyGenericInst represents concrete types, while
       # this is still a "generic param" that will bind types
       # and resolves them during sigmatch and instantiation.
-    
+
     tyCompositeTypeClass #\
       # Type such as seq[Number]
-      # The notes for tyUserTypeClassInst apply here as well 
+      # The notes for tyUserTypeClassInst apply here as well
       # sons[0]: the original expression used by the user.
       # sons[1]: fully expanded and instantiated meta type
       # (potentially following aliases)
-    
+
     tyAnd, tyOr, tyNot #\
       # boolean type classes such as `string|int`,`not seq`,
       # `Sortable and Enumable`, etc
-    
+
     tyAnything #\
       # a type class matching any type
-    
+
     tyStatic #\
       # a value known at compile type (the underlying type is .base)
-    
+
     tyFromExpr #\
       # This is a type representing an expression that depends
       # on generic parameters (the expression is stored in t.n)
@@ -390,7 +391,7 @@ type
       # sons[0]: type of containing object or tuple
       # sons[1]: field type
       # .n: nkDotExpr storing the field name
-    
+
 static:
   # remind us when TTypeKind stops to fit in a single 64-bit word
   assert TTypeKind.high.ord <= 63
@@ -408,7 +409,7 @@ const
                     tyAnd, tyOr, tyNot, tyAnything}
 
   tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
- 
+
 type
   TTypeKinds* = set[TTypeKind]
 
@@ -429,7 +430,7 @@ type
     nfExprCall  # this is an attempt to call a regular expression
     nfIsRef     # this node is a 'ref' node; used for the VM
     nfIsCursor  # this node is attached a cursor; used for idetools
- 
+
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 28)
     tfVarargs,        # procedure has C styled varargs
@@ -448,7 +449,7 @@ type
                       # proc foo(L: static[int]): array[L, int]
                       # can be attached to ranges to indicate that the range
                       # depends on unresolved static params.
-    tfRetType,        # marks return types in proc (used to detect type classes 
+    tfRetType,        # marks return types in proc (used to detect type classes
                       # used as return types for return type inference)
     tfCapturesEnv,    # whether proc really captures some environment
     tfByCopy,         # pass object/tuple by copy (C backend)
@@ -456,9 +457,9 @@ type
     tfIterator,       # type is really an iterator, not a tyProc
     tfShared,         # type is 'shared'
     tfNotNil,         # type cannot be 'nil'
-    
+
     tfNeedsInit,      # type constains a "not nil" constraint somewhere or some
-                      # other type so that it requires inititalization
+                      # other type so that it requires initalization
     tfVarIsPtr,       # 'var' type is translated like 'ptr' even in C++ mode
     tfHasMeta,        # type contains "wildcard" sub-types such as generic params
                       # or other type classes
@@ -520,7 +521,7 @@ const
   tfGcSafe* = tfThread
   tfObjHasKids* = tfEnumHasHoles
   skError* = skUnknown
-  
+
   # type flags that are essential for type equality:
   eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
 
@@ -531,29 +532,29 @@ type
     mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
     mEcho, mShallowCopy, mSlurp, mStaticExec,
     mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
-    mUnaryLt, mSucc, 
-    mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, 
-    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref, 
-    mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, 
+    mUnaryLt, mSucc,
+    mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
+    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
+    mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
     mDivI64, mModI64,
     mAddF64, mSubF64, mMulF64, mDivF64,
-    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, 
+    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
     mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
-    mMinF64, mMaxF64, mAddU, mSubU, mMulU, 
+    mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
-    mLtI, 
-    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, 
-    mLeU, mLtU, mLeU64, mLtU64, 
-    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, 
+    mLtI,
+    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mLeU, mLtU, mLeU64, mLtU64,
+    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
     mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
-    mUnaryMinusI64, mAbsI, mAbsI64, mNot, 
-    mUnaryPlusI, mBitnotI, mUnaryPlusI64, 
-    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, 
-    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, 
-    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, 
-    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, 
-    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, 
-    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, 
+    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryPlusI, mBitnotI, mUnaryPlusI64,
+    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
+    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
+    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
+    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
+    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
     mConTArr, mConTT, mSlice,
     mFields, mFieldPairs, mOmpParFor,
     mAppendStrCh, mAppendStrStr, mAppendSeqElem,
@@ -584,36 +585,36 @@ type
 
 # things that we can evaluate safely at compile time, even if not asked for it:
 const
-  ctfeWhitelist* = {mNone, mUnaryLt, mSucc, 
-    mPred, mInc, mDec, mOrd, mLengthOpenArray, 
-    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, 
-    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, 
+  ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
+    mPred, mInc, mDec, mOrd, mLengthOpenArray,
+    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
+    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
     mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
-    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, 
+    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
     mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
-    mMinF64, mMaxF64, mAddU, mSubU, mMulU, 
+    mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
-    mLtI, 
-    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, 
-    mLeU, mLtU, mLeU64, mLtU64, 
-    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, 
-    mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, 
-    mUnaryMinusI64, mAbsI, mAbsI64, mNot, 
-    mUnaryPlusI, mBitnotI, mUnaryPlusI64, 
-    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, 
-    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, 
-    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, 
-    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, 
-    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, 
-    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, 
+    mLtI,
+    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mLeU, mLtU, mLeU64, mLtU64,
+    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
+    mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
+    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryPlusI, mBitnotI, mUnaryPlusI64,
+    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
+    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
+    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
+    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
+    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
     mConTArr, mConTT,
-    mAppendStrCh, mAppendStrStr, mAppendSeqElem, 
+    mAppendStrCh, mAppendStrStr, mAppendSeqElem,
     mInRange, mInSet, mRepr,
     mCopyStr, mCopyStrLast}
   # magics that require special semantic checking and
   # thus cannot be overloaded (also documented in the spec!):
   SpecialSemMagics* = {
-    mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf, 
+    mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
     mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
 
 type
@@ -634,21 +635,21 @@ type
       floatVal*: BiggestFloat
     of nkStrLit..nkTripleStrLit:
       strVal*: string
-    of nkSym: 
+    of nkSym:
       sym*: PSym
-    of nkIdent: 
+    of nkIdent:
       ident*: PIdent
     else:
       sons*: TNodeSeq
     comment*: string
-  
+
   TSymSeq* = seq[PSym]
   TStrTable* = object         # a table[PIdent] of PSym
     counter*: int
     data*: TSymSeq
-  
+
   # -------------- backend information -------------------------------
-  TLocKind* = enum 
+  TLocKind* = enum
     locNone,                  # no location
     locTemp,                  # temporary location
     locLocalVar,              # location is a local variable
@@ -660,7 +661,7 @@ type
     locData,                  # location is a constant
     locCall,                  # location is a call expression
     locOther                  # location is something other
-  TLocFlag* = enum 
+  TLocFlag* = enum
     lfIndirect,               # backend introduced a pointer
     lfParamCopy,              # backend introduced a parameter copy (LLVM)
     lfNoDeepCopy,             # no need for a deep copy
@@ -670,13 +671,13 @@ type
     lfHeader,                 # include header file for symbol
     lfImportCompilerProc,     # ``importc`` of a compilerproc
     lfSingleUse               # no location yet and will only be used once
-  TStorageLoc* = enum 
+  TStorageLoc* = enum
     OnUnknown,                # location is unknown (stack, heap or static)
     OnStack,                  # location is on hardware stack
     OnHeap                    # location is on heap or global
                               # (reference counting needed)
   TLocFlags* = set[TLocFlag]
-  TLoc* = object     
+  TLoc* = object
     k*: TLocKind              # kind of location
     s*: TStorageLoc
     flags*: TLocFlags         # location's flags
@@ -688,7 +689,7 @@ type
 
   # ---------------- end of backend information ------------------------------
 
-  TLibKind* = enum 
+  TLibKind* = enum
     libHeader, libDynamic
   TLib* = object of lists.TListEntry # also misused for headers!
     kind*: TLibKind
@@ -696,17 +697,17 @@ type
     isOverriden*: bool
     name*: PRope
     path*: PNode              # can be a string literal!
-  
+
   TInstantiation* = object
     sym*: PSym
     concreteTypes*: seq[PType]
     usedBy*: seq[int32]       # list of modules using the generic
                               # needed in caas mode for purging the cache
-                              # XXX: it's possible to switch to a 
+                              # XXX: it's possible to switch to a
                               # simple ref count here
-  
+
   PInstantiation* = ref TInstantiation
- 
+
   TScope* = object
     depthLevel*: int
     symbols*: TStrTable
@@ -773,7 +774,7 @@ type
     constraint*: PNode        # additional constraints like 'lit|result'; also
                               # misused for the codegenDecl pragma in the hope
                               # it won't cause problems
-  
+
   TTypeSeq* = seq[PType]
   TLockLevel* = distinct int16
   TType* {.acyclic.} = object of TIdObj # \
@@ -806,45 +807,45 @@ type
     lockLevel*: TLockLevel    # lock level as required for deadlock checking
     loc*: TLoc
 
-  TPair*{.final.} = object 
+  TPair* = object
     key*, val*: RootRef
 
   TPairSeq* = seq[TPair]
-  TTable*{.final.} = object   # the same as table[PObject] of PObject
+  TTable* = object   # the same as table[PObject] of PObject
     counter*: int
     data*: TPairSeq
 
-  TIdPair*{.final.} = object 
+  TIdPair* = object
     key*: PIdObj
     val*: RootRef
 
   TIdPairSeq* = seq[TIdPair]
-  TIdTable*{.final.} = object # the same as table[PIdent] of PObject
+  TIdTable* = object # the same as table[PIdent] of PObject
     counter*: int
     data*: TIdPairSeq
 
-  TIdNodePair*{.final.} = object 
+  TIdNodePair* = object
     key*: PIdObj
     val*: PNode
 
   TIdNodePairSeq* = seq[TIdNodePair]
-  TIdNodeTable*{.final.} = object # the same as table[PIdObj] of PNode
+  TIdNodeTable* = object # the same as table[PIdObj] of PNode
     counter*: int
     data*: TIdNodePairSeq
 
-  TNodePair*{.final.} = object 
+  TNodePair* = object
     h*: THash                 # because it is expensive to compute!
     key*: PNode
     val*: int
 
   TNodePairSeq* = seq[TNodePair]
-  TNodeTable*{.final.} = object # the same as table[PNode] of int;
+  TNodeTable* = object # the same as table[PNode] of int;
                                 # nodes are compared by structure!
     counter*: int
     data*: TNodePairSeq
 
   TObjectSeq* = seq[RootRef]
-  TObjectSet*{.final.} = object 
+  TObjectSet* = object
     counter*: int
     data*: TObjectSeq
 
@@ -855,27 +856,27 @@ type
 # same name as an imported module. This is necessary because of
 # the poor naming choices in the standard library.
 
-const 
+const
   OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
     skConverter, skModule, skTemplate, skMacro}
 
-  GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody, 
+  GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
     tyGenericParam}
-  
-  StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, 
+
+  StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
     tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
     tyVarargs}
-  
+
   ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
                                  # var x = expr
-    tyBool, tyChar, tyEnum, tyArray, tyObject, 
+    tyBool, tyChar, tyEnum, tyArray, tyObject,
     tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
-    tyPointer, 
+    tyPointer,
     tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
     tyUInt..tyUInt64}
   IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
     tyFloat..tyFloat128, tyUInt..tyUInt64}
-  ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, 
+  ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
                                     tyTuple, tySequence}
   NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
     tyProc, tyString, tyError}
@@ -926,17 +927,17 @@ proc discardSons*(father: PNode)
 proc len*(n: PNode): int {.inline.} =
   if isNil(n.sons): result = 0
   else: result = len(n.sons)
-  
+
 proc safeLen*(n: PNode): int {.inline.} =
   ## works even for leaves.
   if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
   else: result = len(n.sons)
-  
+
 proc add*(father, son: PNode) =
   assert son != nil
   if isNil(father.sons): father.sons = @[]
   add(father.sons, son)
-  
+
 proc `[]`*(n: PNode, i: int): PNode {.inline.} =
   result = n.sons[i]
 
@@ -946,13 +947,10 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
   n.sons[i -| n] = s
 
 when defined(useNodeIds):
-  const nodeIdToDebug* = -1 # 884953 # 612794
-  #612840 # 612905 # 614635 # 614637 # 614641
-  # 423408
-  #429107 # 430443 # 441048 # 441090 # 441153
+  const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
   var gNodeId: int
 
-proc newNode*(kind: TNodeKind): PNode = 
+proc newNode*(kind: TNodeKind): PNode =
   new(result)
   result.kind = kind
   #result.info = UnknownLineInfo() inlined:
@@ -966,24 +964,24 @@ proc newNode*(kind: TNodeKind): PNode =
       writeStackTrace()
     inc gNodeId
 
-proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = 
+proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
   result = newNode(kind)
   result.intVal = intVal
 
-proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = 
+proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
   result = newIntNode(kind, intVal)
   result.typ = typ
 
-proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode = 
+proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
   result = newNode(kind)
   result.floatVal = floatVal
 
-proc newStrNode*(kind: TNodeKind, strVal: string): PNode = 
+proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
   result = newNode(kind)
   result.strVal = strVal
 
 proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
-             info: TLineInfo): PSym = 
+             info: TLineInfo): PSym =
   # generates a symbol and initializes the hash field too
   new(result)
   result.name = name
@@ -994,7 +992,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
   result.owner = owner
   result.offset = - 1
   result.id = getID()
-  when debugIds: 
+  when debugIds:
     registerId(result)
   #if result.id < 2000:
   #  MessageOut(name.s & " has id: " & toString(result.id))
@@ -1036,54 +1034,54 @@ proc appendToModule*(m: PSym, n: PNode) =
   else:
     assert m.ast.kind == nkStmtList
     m.ast.sons.add(n)
-  
+
 const                         # for all kind of hash tables:
   GrowthFactor* = 2           # must be power of 2, > 0
   StartSize* = 8              # must be power of 2, > 0
 
-proc copyStrTable*(dest: var TStrTable, src: TStrTable) = 
+proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   setLen(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc copyIdTable*(dest: var TIdTable, src: TIdTable) = 
+
+proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   newSeq(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc copyTable*(dest: var TTable, src: TTable) = 
+
+proc copyTable*(dest: var TTable, src: TTable) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   setLen(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = 
+
+proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   setLen(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc discardSons*(father: PNode) = 
+
+proc discardSons*(father: PNode) =
   father.sons = nil
 
 proc withInfo*(n: PNode, info: TLineInfo): PNode =
   n.info = info
   return n
 
-proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode = 
+proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
   result = newNode(nkIdent)
   result.ident = ident
   result.info = info
 
-proc newSymNode*(sym: PSym): PNode = 
+proc newSymNode*(sym: PSym): PNode =
   result = newNode(nkSym)
   result.sym = sym
   result.typ = sym.typ
   result.info = sym.info
 
-proc newSymNode*(sym: PSym, info: TLineInfo): PNode = 
+proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
   result = newNode(nkSym)
   result.sym = sym
   result.typ = sym.typ
@@ -1128,12 +1126,12 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
       writeStackTrace()
     inc gNodeId
 
-proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = 
+proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
   result = newNode(kind)
   result.info = info
   result.typ = typ
 
-proc addSon*(father, son: PNode) = 
+proc addSon*(father, son: PNode) =
   assert son != nil
   if isNil(father.sons): father.sons = @[]
   add(father.sons, son)
@@ -1159,7 +1157,7 @@ proc `$`*(x: TLockLevel): string =
   elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
   else: result = $int16(x)
 
-proc newType*(kind: TTypeKind, owner: PSym): PType = 
+proc newType*(kind: TTypeKind, owner: PSym): PType =
   new(result)
   result.kind = kind
   result.owner = owner
@@ -1171,7 +1169,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
     registerId(result)
   #if result.id < 2000:
   #  messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
-  
+
 proc mergeLoc(a: var TLoc, b: TLoc) =
   if a.k == low(a.k): a.k = b.k
   if a.s == low(a.s): a.s = b.s
@@ -1180,37 +1178,37 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
   if a.r == nil: a.r = b.r
   #if a.a == 0: a.a = b.a
 
-proc newSons*(father: PNode, length: int) = 
-  if isNil(father.sons): 
+proc newSons*(father: PNode, length: int) =
+  if isNil(father.sons):
     newSeq(father.sons, length)
   else:
     setLen(father.sons, length)
 
-proc newSons*(father: PType, length: int) = 
-  if isNil(father.sons): 
+proc newSons*(father: PType, length: int) =
+  if isNil(father.sons):
     newSeq(father.sons, length)
   else:
     setLen(father.sons, length)
 
-proc sonsLen*(n: PType): int = 
+proc sonsLen*(n: PType): int =
   if isNil(n.sons): result = 0
   else: result = len(n.sons)
 
-proc len*(n: PType): int = 
+proc len*(n: PType): int =
   if isNil(n.sons): result = 0
   else: result = len(n.sons)
-  
-proc sonsLen*(n: PNode): int = 
+
+proc sonsLen*(n: PNode): int =
   if isNil(n.sons): result = 0
   else: result = len(n.sons)
-  
-proc lastSon*(n: PNode): PNode = 
+
+proc lastSon*(n: PNode): PNode =
   result = n.sons[sonsLen(n) - 1]
 
-proc lastSon*(n: PType): PType = 
+proc lastSon*(n: PType): PType =
   result = n.sons[sonsLen(n) - 1]
 
-proc assignType*(dest, src: PType) = 
+proc assignType*(dest, src: PType) =
   dest.kind = src.kind
   dest.flags = src.flags
   dest.callConv = src.callConv
@@ -1230,23 +1228,23 @@ proc assignType*(dest, src: PType) =
       dest.sym = src.sym
   newSons(dest, sonsLen(src))
   for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
-  
-proc copyType*(t: PType, owner: PSym, keepId: bool): PType = 
+
+proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
   result = newType(t.kind, owner)
   assignType(result, t)
-  if keepId: 
+  if keepId:
     result.id = t.id
-  else: 
+  else:
     when debugIds: registerId(result)
   result.sym = t.sym          # backend-info should not be copied
-  
-proc copySym*(s: PSym, keepId: bool = false): PSym = 
+
+proc copySym*(s: PSym, keepId: bool = false): PSym =
   result = newSym(s.kind, s.name, s.owner, s.info)
   #result.ast = nil            # BUGFIX; was: s.ast which made problems
   result.typ = s.typ
   if keepId:
     result.id = s.id
-  else: 
+  else:
     result.id = getID()
     when debugIds: registerId(result)
   result.flags = s.flags
@@ -1273,19 +1271,19 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
   result.annex = s.annex
   # XXX once usedGenerics is used, ensure module aliases keep working!
   assert s.usedGenerics == nil
-  
-proc initStrTable*(x: var TStrTable) = 
+
+proc initStrTable*(x: var TStrTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
 proc newStrTable*: TStrTable =
   initStrTable(result)
 
-proc initTable(x: var TTable) = 
+proc initTable(x: var TTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc initIdTable*(x: var TIdTable) = 
+proc initIdTable*(x: var TIdTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
@@ -1295,15 +1293,15 @@ proc resetIdTable*(x: var TIdTable) =
   setLen(x.data, 0)
   setLen(x.data, StartSize)
 
-proc initObjectSet*(x: var TObjectSet) = 
+proc initObjectSet*(x: var TObjectSet) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc initIdNodeTable*(x: var TIdNodeTable) = 
+proc initIdNodeTable*(x: var TIdNodeTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc initNodeTable*(x: var TNodeTable) = 
+proc initNodeTable*(x: var TNodeTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
@@ -1320,18 +1318,18 @@ proc isGCedMem*(t: PType): bool {.inline.} =
            t.kind == tyProc and t.callConv == ccClosure
 
 proc propagateToOwner*(owner, elem: PType) =
-  const HaveTheirOwnEmpty = {tySequence, tySet}
+  const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc}
   owner.flags = owner.flags + (elem.flags * {tfHasMeta})
   if tfNotNil in elem.flags:
     if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
       owner.flags.incl tfNotNil
     elif owner.kind notin HaveTheirOwnEmpty:
       owner.flags.incl tfNeedsInit
-  
+
   if tfNeedsInit in elem.flags:
     if owner.kind in HaveTheirOwnEmpty: discard
     else: owner.flags.incl tfNeedsInit
-    
+
   if elem.isMetaType:
     owner.flags.incl tfHasMeta
 
@@ -1348,15 +1346,15 @@ proc addSonNilAllowed*(father, son: PNode) =
   if isNil(father.sons): father.sons = @[]
   add(father.sons, son)
 
-proc delSon*(father: PNode, idx: int) = 
-  if isNil(father.sons): return 
+proc delSon*(father: PNode, idx: int) =
+  if isNil(father.sons): return
   var length = sonsLen(father)
   for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
   setLen(father.sons, length - 1)
 
-proc copyNode*(src: PNode): PNode = 
+proc copyNode*(src: PNode): PNode =
   # does not copy its sons!
-  if src == nil: 
+  if src == nil:
     return nil
   result = newNode(src.kind)
   result.info = src.info
@@ -1373,7 +1371,7 @@ proc copyNode*(src: PNode): PNode =
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
   else: discard
 
-proc shallowCopy*(src: PNode): PNode = 
+proc shallowCopy*(src: PNode): PNode =
   # does not copy its sons, but provides space for them:
   if src == nil: return nil
   result = newNode(src.kind)
@@ -1391,9 +1389,9 @@ proc shallowCopy*(src: PNode): PNode =
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
   else: newSeq(result.sons, sonsLen(src))
 
-proc copyTree*(src: PNode): PNode = 
+proc copyTree*(src: PNode): PNode =
   # copy a whole syntax tree; performs deep copying
-  if src == nil: 
+  if src == nil:
     return nil
   result = newNode(src.kind)
   result.info = src.info
@@ -1408,20 +1406,20 @@ proc copyTree*(src: PNode): PNode =
   of nkSym: result.sym = src.sym
   of nkIdent: result.ident = src.ident
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
-  else: 
+  else:
     newSeq(result.sons, sonsLen(src))
-    for i in countup(0, sonsLen(src) - 1): 
+    for i in countup(0, sonsLen(src) - 1):
       result.sons[i] = copyTree(src.sons[i])
 
-proc hasSonWith*(n: PNode, kind: TNodeKind): bool = 
-  for i in countup(0, sonsLen(n) - 1): 
-    if n.sons[i].kind == kind: 
+proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i].kind == kind:
       return true
   result = false
 
-proc hasNilSon*(n: PNode): bool = 
-  for i in countup(0, safeLen(n) - 1): 
-    if n.sons[i] == nil: 
+proc hasNilSon*(n: PNode): bool =
+  for i in countup(0, safeLen(n) - 1):
+    if n.sons[i] == nil:
       return true
     elif hasNilSon(n.sons[i]):
       return true
@@ -1435,47 +1433,47 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
     for i in countup(0, sonsLen(n) - 1):
       if n.kind in kinds or containsNode(n.sons[i], kinds): return true
 
-proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool = 
+proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
   case n.kind
   of nkEmpty..nkNilLit: result = n.kind == kind
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
-      if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind): 
+  else:
+    for i in countup(0, sonsLen(n) - 1):
+      if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
         return true
     result = false
 
-proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) = 
-  for i in countup(0, sonsLen(n) - 1): 
+proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
+  for i in countup(0, sonsLen(n) - 1):
     if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
-  
-proc sonsNotNil(n: PNode): bool = 
-  for i in countup(0, sonsLen(n) - 1): 
-    if n.sons[i] == nil: 
+
+proc sonsNotNil(n: PNode): bool =
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i] == nil:
       return false
   result = true
 
-proc getInt*(a: PNode): BiggestInt = 
+proc getInt*(a: PNode): BiggestInt =
   case a.kind
   of nkIntLit..nkUInt64Lit: result = a.intVal
-  else: 
+  else:
     internalError(a.info, "getInt")
     result = 0
 
-proc getFloat*(a: PNode): BiggestFloat = 
+proc getFloat*(a: PNode): BiggestFloat =
   case a.kind
   of nkFloatLit..nkFloat128Lit: result = a.floatVal
-  else: 
+  else:
     internalError(a.info, "getFloat")
     result = 0.0
 
-proc getStr*(a: PNode): string = 
+proc getStr*(a: PNode): string =
   case a.kind
   of nkStrLit..nkTripleStrLit: result = a.strVal
-  else: 
+  else:
     internalError(a.info, "getStr")
     result = ""
 
-proc getStrOrChar*(a: PNode): string = 
+proc getStrOrChar*(a: PNode): string =
   case a.kind
   of nkStrLit..nkTripleStrLit: result = a.strVal
   of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
@@ -1483,7 +1481,7 @@ proc getStrOrChar*(a: PNode): string =
     internalError(a.info, "getStrOrChar")
     result = ""
 
-proc isGenericRoutine*(s: PSym): bool = 
+proc isGenericRoutine*(s: PSym): bool =
   case s.kind
   of skProcKinds:
     result = sfFromGeneric in s.flags or
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 200ff91e0..86f300aa0 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -135,14 +135,14 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
   elif ccgIntroducedPtr(param):
     initLocExpr(p, n, a)
     result = addrLoc(a)
-  elif p.module.compileToCpp and param.typ.kind == tyVar and 
+  elif p.module.compileToCpp and param.typ.kind == tyVar and
       n.kind == nkHiddenAddr:
     initLocExprSingleUse(p, n.sons[0], a)
     # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
     # means '*T'. See posix.nim for lots of examples that do that in the wild.
     let callee = call.sons[0]
     if callee.kind == nkSym and
-        {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and 
+        {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
         {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
       result = addrLoc(a)
     else:
@@ -192,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
   initLocExpr(p, ri.sons[0], op)
   var pl: PRope
-  
+
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
@@ -204,7 +204,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
     else:
       app(pl, genArgNoParam(p, ri.sons[i]))
     if i < length - 1: app(pl, ~", ")
-  
+
   template genCallPattern {.dirty.} =
     lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
 
@@ -339,7 +339,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
           let typ = skipTypes(ri.sons[0].typ, abstractInst)
           if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
           result.app(~"(")
-          result.app genOtherArg(p, ri, 1, typ)
+          if 1 < ri.len:
+            result.app genOtherArg(p, ri, 1, typ)
           for k in j+1 .. < ri.len:
             result.app(~", ")
             result.app genOtherArg(p, ri, k, typ)
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index b98679ac6..b1a23802d 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -164,6 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
       let field = getField(typ.n, i)
       pack(it, field.typ, res +! field.offset)
     else:
+      # XXX: todo
       globalError(x.info, "cannot pack unnamed tuple")
 
 const maxPackDepth = 20
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 29657a2ae..8959aa4df 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -10,7 +10,7 @@
 ## Template evaluation engine. Now hygienic.
 
 import
-  strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer, 
+  strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
   rodread
 
 type
@@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
     result.add copyNode(c, templ, actual)
   else:
     var res = copyNode(c, templ, actual)
-    for i in countup(0, sonsLen(templ) - 1): 
+    for i in countup(0, sonsLen(templ) - 1):
       evalTemplateAux(templ.sons[i], actual, c, res)
     result.add res
 
@@ -86,9 +86,9 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
   ctx.owner = tmpl
   ctx.genSymOwner = genSymOwner
   initIdTable(ctx.mapping)
-  
+
   let body = tmpl.getBody
-  if isAtom(body): 
+  if isAtom(body):
     result = newNodeI(nkPar, body.info)
     evalTemplateAux(body, args, ctx, result)
     if result.len == 1: result = result.sons[0]
@@ -102,5 +102,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
     if ctx.instLines: result.info = n.info
     for i in countup(0, safeLen(body) - 1):
       evalTemplateAux(body.sons[i], args, ctx, result)
-  
+
   dec(evalTemplateCounter)
diff --git a/compiler/guards.nim b/compiler/guards.nim
index 3255364c2..b0420cb75 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -15,11 +15,11 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
 const
   someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
     mEqUntracedRef, mEqStr, mEqSet, mEqCString}
-  
+
   # set excluded here as the semantics are vastly different:
   someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
             mLeCh, mLeB, mLePtr, mLeStr}
-  someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, 
+  someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
             mLtCh, mLtB, mLtPtr, mLtStr}
 
   someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
@@ -44,7 +44,7 @@ proc isLet(n: PNode): bool =
   if n.kind == nkSym:
     if n.sym.kind in {skLet, skTemp, skForVar}:
       result = true
-    elif n.sym.kind == skParam and skipTypes(n.sym.typ, 
+    elif n.sym.kind == skParam and skipTypes(n.sym.typ,
                                              abstractInst).kind != tyVar:
       result = true
 
@@ -117,7 +117,7 @@ proc neg(n: PNode): PNode =
     result.sons[0] = n.sons[0]
     result.sons[2] = n.sons[2]
     if t.kind == tyEnum:
-      var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)    
+      var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
       for e in t.n:
         let eAsNode = newIntNode(nkIntLit, e.sym.position)
         if not inSet(n.sons[1], eAsNode): s.add eAsNode
@@ -189,13 +189,17 @@ proc zero(): PNode = nkIntLit.newIntNode(0)
 proc one(): PNode = nkIntLit.newIntNode(1)
 proc minusOne(): PNode = nkIntLit.newIntNode(-1)
 
-proc lowBound*(x: PNode): PNode = 
+proc lowBound*(x: PNode): PNode =
   result = nkIntLit.newIntNode(firstOrd(x.typ))
   result.info = x.info
 
 proc highBound*(x: PNode): PNode =
-  result = if x.typ.skipTypes(abstractInst).kind == tyArray:
-             nkIntLit.newIntNode(lastOrd(x.typ))
+  let typ = x.typ.skipTypes(abstractInst)
+  result = if typ.kind in {tyArrayConstr, tyArray}:
+             nkIntLit.newIntNode(lastOrd(typ))
+           elif typ.kind == tySequence and x.kind == nkSym and
+               x.sym.kind == skConst:
+             nkIntLit.newIntNode(x.sym.ast.len-1)
            else:
              opAdd.buildCall(opLen.buildCall(x), minusOne())
   result.info = x.info
@@ -205,21 +209,32 @@ proc reassociation(n: PNode): PNode =
   # (foo+5)+5 --> foo+10;  same for '*'
   case result.getMagic
   of someAdd:
-    if result[2].isValue and 
+    if result[2].isValue and
         result[1].getMagic in someAdd and result[1][2].isValue:
       result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
   of someMul:
-    if result[2].isValue and 
+    if result[2].isValue and
         result[1].getMagic in someMul and result[1][2].isValue:
       result = opAdd.buildCall(result[1][1], result[1][2] |*| result[2])
   else: discard
 
+proc pred(n: PNode): PNode =
+  if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
+    result = copyNode(n)
+    dec result.intVal
+  else:
+    result = n
+
 proc canon*(n: PNode): PNode =
   # XXX for now only the new code in 'semparallel' uses this
   if n.safeLen >= 1:
     result = shallowCopy(n)
     for i in 0 .. < n.len:
       result.sons[i] = canon(n.sons[i])
+  elif n.kind == nkSym and n.sym.kind == skLet and
+      n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
+      someMax + someHigh + {mUnaryLt} + someSub + someLen):
+    result = n.sym.ast.copyTree
   else:
     result = n
   case result.getMagic
@@ -231,34 +246,40 @@ proc canon*(n: PNode): PNode =
   of someHigh:
     # high == len+(-1)
     result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
-  of mUnaryMinusI, mUnaryMinusI64:
+  of mUnaryLt:
     result = buildCall(opAdd, result[1], newIntNode(nkIntLit, -1))
   of someSub:
     # x - 4  -->  x + (-4)
     result = negate(result[1], result[2], result)
   of someLen:
     result.sons[0] = opLen.newSymNode
+  of someLt:
+    # x < y  same as x <= y-1:
+    let y = n[2].canon
+    let p = pred(y)
+    let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon
+    result = opLe.buildCall(n[1].canon, minus)
   else: discard
 
   result = skipConv(result)
   result = reassociation(result)
-  # most important rule: (x-4) < a.len -->  x < a.len+4
+  # most important rule: (x-4) <= a.len -->  x <= a.len+4
   case result.getMagic
-  of someLe, someLt:
+  of someLe:
     let x = result[1]
     let y = result[2]
-    if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and 
+    if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and
         isLetLocation(x[1], true):
       case x.getMagic
       of someSub:
-        result = buildCall(result[0].sym, x[1], 
+        result = buildCall(result[0].sym, x[1],
                            reassociation(opAdd.buildCall(y, x[2])))
       of someAdd:
         # Rule A:
         let plus = negate(y, x[2], nil).reassociation
         if plus != nil: result = buildCall(result[0].sym, x[1], plus)
       else: discard
-    elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and 
+    elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
         isLetLocation(y[1], true):
       # a.len < x-3
       case y.getMagic
@@ -317,7 +338,7 @@ proc usefulFact(n: PNode): PNode =
   of mOr:
     # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
     # with that knowledge...
-    # DeMorgan helps a little though: 
+    # DeMorgan helps a little though:
     #   not a or not b --> not (a and b)
     #  (x == 3) or (y == 2)  ---> not ( not (x==3) and not (y == 2))
     #  not (x != 3 and y != 2)
@@ -348,11 +369,11 @@ proc addFact*(m: var TModel, n: PNode) =
   let n = usefulFact(n)
   if n != nil: m.add n
 
-proc addFactNeg*(m: var TModel, n: PNode) = 
+proc addFactNeg*(m: var TModel, n: PNode) =
   let n = n.neg
   if n != nil: addFact(m, n)
 
-proc sameTree*(a, b: PNode): bool = 
+proc sameTree*(a, b: PNode): bool =
   result = false
   if a == b:
     result = true
@@ -382,8 +403,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
   # 'while p != nil: f(p); p = p.next'
   # This is actually quite easy to do:
   # Re-assignments (incl. pass to a 'var' param) trigger an invalidation
-  # of every fact that contains 'v'. 
-  # 
+  # of every fact that contains 'v'.
+  #
   #   if x < 4:
   #     if y < 5
   #       x = unknown()
@@ -402,16 +423,9 @@ proc valuesUnequal(a, b: PNode): bool =
   if a.isValue and b.isValue:
     result = not sameValue(a, b)
 
-proc pred(n: PNode): PNode =
-  if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
-    result = copyNode(n)
-    dec result.intVal
-  else:
-    result = n
-
 proc impliesEq(fact, eq: PNode): TImplication =
   let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
-  
+
   case fact.sons[0].sym.magic
   of someEq:
     if sameTree(fact.sons[1], eq.sons[loc]):
@@ -428,12 +442,12 @@ proc impliesEq(fact, eq: PNode): TImplication =
       else: result = impNo
   of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
   else: discard
-  
+
 proc leImpliesIn(x, c, aSet: PNode): TImplication =
   if c.kind in {nkCharLit..nkUInt64Lit}:
     # fact:  x <= 4;  question x in {56}?
     # --> true if every value <= 4 is in the set {56}
-    #   
+    #
     var value = newIntNode(c.kind, firstOrd(x.typ))
     # don't iterate too often:
     if c.intVal - value.intVal < 1000:
@@ -449,7 +463,7 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
   if c.kind in {nkCharLit..nkUInt64Lit}:
     # fact:  x >= 4;  question x in {56}?
     # --> true iff every value >= 4 is in the set {56}
-    #   
+    #
     var value = newIntNode(c.kind, c.intVal)
     let max = lastOrd(x.typ)
     # don't iterate too often:
@@ -568,19 +582,19 @@ proc impliesLe(fact, x, c: PNode): TImplication =
         # fact:  x < 4;  question x <= 2? --> we don't know
     elif sameTree(fact.sons[2], x):
       # fact: 3 < x; question: x <= 1 ?  --> false iff 1 <= 3
-      if isValue(fact.sons[1]) and isValue(c): 
+      if isValue(fact.sons[1]) and isValue(c):
         if leValue(c, fact.sons[1]): result = impNo
-    
+
   of someLe:
     if sameTree(fact.sons[1], x):
       if isValue(fact.sons[2]) and isValue(c):
         # fact:  x <= 4;  question x <= 56? --> true iff 4 <= 56
         if leValue(fact.sons[2], c): result = impYes
         # fact:  x <= 4;  question x <= 2? --> we don't know
-    
+
     elif sameTree(fact.sons[2], x):
       # fact: 3 <= x; question: x <= 2 ?  --> false iff 2 < 3
-      if isValue(fact.sons[1]) and isValue(c): 
+      if isValue(fact.sons[1]) and isValue(c):
         if leValue(c, fact.sons[1].pred): result = impNo
 
   of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
@@ -614,7 +628,7 @@ proc factImplies(fact, prop: PNode): TImplication =
     # it's provably wrong if every value > 4 is in the set {56}
     # That's because we compute the implication and  'a -> not b' cannot
     # be treated the same as 'not a -> b'
-    
+
     #  (not a) -> b  compute as  not (a -> b) ???
     #  == not a or not b == not (a and b)
     let arg = fact.sons[1]
@@ -635,7 +649,7 @@ proc factImplies(fact, prop: PNode): TImplication =
     if result != impUnknown: return result
     return factImplies(fact.sons[2], prop)
   else: discard
-  
+
   case prop.sons[0].sym.magic
   of mNot: result = ~fact.factImplies(prop.sons[1])
   of mIsNil: result = impliesIsNil(fact, prop)
@@ -671,6 +685,7 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication
 
 proc ple(m: TModel; a, b: PNode): TImplication =
   template `<=?`(a,b): expr = ple(m,a,b) == impYes
+
   #   0 <= 3
   if a.isValue and b.isValue:
     return if leValue(a, b): impYes else: impNo
@@ -744,16 +759,21 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
       # mark as used:
       m[i] = nil
       if ple(m, a, x) == impYes:
-        if ple(m, y, b) == impYes: return impYes
+        if ple(m, y, b) == impYes:
+          return impYes
         #if pleViaModelRec(m, y, b): return impYes
       # fact:  16 <= i
       #         x    y
       # question: i <= 15? no!
       result = impliesLe(fact, a, b)
-      if result != impUnknown: return result
-      if sameTree(y, a):
-        result = ple(m, b, x)
-        if result != impUnknown: return result
+      if result != impUnknown:
+        return result
+      when false:
+        # given: x <= y;  y==a;  x <= a this means: a <= b  if  x <= b
+        if sameTree(y, a):
+          result = ple(m, b, x)
+          if result != impUnknown:
+            return result
 
 proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
   # compute replacements:
diff --git a/compiler/importer.nim b/compiler/importer.nim
index fbf3be4f2..57a1e542b 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -27,7 +27,7 @@ proc getModuleName*(n: PNode): string =
     result = n.ident.s
   of nkSym:
     result = n.sym.name.s
-  of nkInfix:
+  of nkInfix, nkPrefix:
     if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
       # XXX hack ahead:
       n.kind = nkImportAs
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 87847204f..75c4ddfa0 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -62,13 +62,13 @@ type
     res: PRope               # result part; index if this is an
                              # (address, index)-tuple
     address: PRope           # address of an (address, index)-tuple
-  
-  TBlock = object 
+
+  TBlock = object
     id: int                  # the ID of the label; positive means that it
                              # has been used (i.e. the label should be emitted)
     isLoop: bool             # whether it's a 'block' or 'while'
-  
-  TGlobals = object 
+
+  TGlobals = object
     typeInfo, code: PRope
     forwarded: seq[PSym]
     generatedSyms: IntSet
@@ -98,7 +98,7 @@ proc newGlobals(): PGlobals =
   result.generatedSyms = initIntSet()
   result.typeInfoGenerated = initIntSet()
 
-proc initCompRes(r: var TCompRes) = 
+proc initCompRes(r: var TCompRes) =
   r.address = nil
   r.res = nil
   r.typ = etyNone
@@ -112,7 +112,7 @@ proc rdLoc(a: TCompRes): PRope {.inline.} =
     else:
       result = ropef("$1[$2]", a.address, a.res)
 
-proc newProc(globals: PGlobals, module: BModule, procDef: PNode, 
+proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
              options: TOptions): PProc =
   result = PProc(
     blocks: @[],
@@ -121,30 +121,30 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
     procDef: procDef,
     g: globals)
   if procDef != nil: result.prc = procDef.sons[namePos].sym
-  
-const 
-  MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, 
+
+const
+  MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
     tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
 
-proc mapType(typ: PType): TJSTypeKind = 
+proc mapType(typ: PType): TJSTypeKind =
   let t = skipTypes(typ, abstractInst)
   case t.kind
-  of tyVar, tyRef, tyPtr: 
-    if skipTypes(t.lastSon, abstractInst).kind in MappedToObject: 
+  of tyVar, tyRef, tyPtr:
+    if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
       result = etyObject
-    else: 
+    else:
       result = etyBaseIndex
   of tyPointer:
     # treat a tyPointer like a typed pointer to an array of bytes
     result = etyInt
-  of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy: 
+  of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy:
     result = mapType(t.sons[0])
   of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
   of tyBool: result = etyBool
   of tyFloat..tyFloat128: result = etyFloat
   of tySet: result = etyObject # map a set to a table
   of tyString, tySequence: result = etyInt # little hack to get right semantics
-  of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum, 
+  of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
      tyVarargs:
     result = etyObject
   of tyNil: result = etyNull
@@ -154,10 +154,10 @@ proc mapType(typ: PType): TJSTypeKind =
     result = etyNone
   of tyProc: result = etyProc
   of tyCString: result = etyString
-  
-proc mangleName(s: PSym): PRope = 
+
+proc mangleName(s: PSym): PRope =
   result = s.loc.r
-  if result == nil: 
+  if result == nil:
     result = toRope(mangle(s.name.s))
     app(result, "_")
     app(result, toRope(s.id))
@@ -166,7 +166,7 @@ proc mangleName(s: PSym): PRope =
 proc makeJSString(s: string): PRope = strutils.escape(s).toRope
 
 include jstypes
-  
+
 proc gen(p: PProc, n: PNode, r: var TCompRes)
 proc genStmt(p: PProc, n: PNode)
 proc genProc(oldProc: PProc, prc: PSym): PRope
@@ -341,14 +341,14 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "$1", "$1"],     # ToBiggestFloat
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
-    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], 
+    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
     ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
-      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", 
-      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr", 
-                                   "cstrToNimstr(($1)+\"\")", 
-                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", 
-      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"], 
-    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"], 
+      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
+      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
+                                   "cstrToNimstr(($1)+\"\")",
+                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
+      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
+    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
     ["", "", "$1", "$1"]]
 
   luaOps: TMagicOps = [
@@ -441,14 +441,14 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "$1", "$1"],     # ToBiggestFloat
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
-    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], 
+    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
     ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
-      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", 
-      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr", 
-                                   "cstrToNimstr(($1)+\"\")", 
-                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", 
-      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"], 
-    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"], 
+      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
+      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
+                                   "cstrToNimstr(($1)+\"\")",
+                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
+      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
+    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
     ["", "", "$1", "$1"]]
 
 proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
@@ -502,9 +502,9 @@ proc genLineDir(p: PProc, n: PNode) =
     appf(p.body, "endb($1);$n", [toRope(line)])
   elif ({optLineTrace, optStackTrace} * p.options ==
       {optLineTrace, optStackTrace}) and
-      ((p.prc == nil) or not (sfPure in p.prc.flags)): 
+      ((p.prc == nil) or not (sfPure in p.prc.flags)):
     appf(p.body, "F.line = $1;$n", [toRope(line)])
-  
+
 proc genWhileStmt(p: PProc, n: PNode) =
   var
     cond: TCompRes
@@ -533,7 +533,7 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
     src.kind = resNone
     src.res = nil
 
-proc genTry(p: PProc, n: PNode, r: var TCompRes) = 
+proc genTry(p: PProc, n: PNode, r: var TCompRes) =
   # code to generate:
   #
   #  var sp = {prev: excHandler, exc: null};
@@ -560,8 +560,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
   inc(p.unique)
   var safePoint = ropef("Tmp$1", [toRope(p.unique)])
   appf(p.body,
-       "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" | 
-       "local $1 = pcall(", 
+       "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
+       "local $1 = pcall(",
        [safePoint])
   if optStackTrace in p.options: app(p.body, "framePtr = F;" & tnl)
   appf(p.body, "try {$n" | "function()$n")
@@ -574,9 +574,9 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
     appf(p.body, "} catch (EXC) {$n  lastJSError = EXC;$n")
   elif p.target == targetLua:
     appf(p.body, "end)$n")
-  while i < length and n.sons[i].kind == nkExceptBranch: 
+  while i < length and n.sons[i].kind == nkExceptBranch:
     let blen = sonsLen(n.sons[i])
-    if blen == 1: 
+    if blen == 1:
       # general except section:
       if i > 1: appf(p.body, "else {$n" | "else$n")
       gen(p, n.sons[i].sons[0], a)
@@ -585,11 +585,11 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
     else:
       var orExpr: PRope = nil
       useMagic(p, "isObj")
-      for j in countup(0, blen - 2): 
-        if n.sons[i].sons[j].kind != nkType: 
+      for j in countup(0, blen - 2):
+        if n.sons[i].sons[j].kind != nkType:
           internalError(n.info, "genTryStmt")
         if orExpr != nil: app(orExpr, "||" | " or ")
-        appf(orExpr, "isObj($1.exc.m_type, $2)", 
+        appf(orExpr, "isObj($1.exc.m_type, $2)",
              [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
       if i > 1: app(p.body, "else ")
       appf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
@@ -622,13 +622,13 @@ proc genRaiseStmt(p: PProc, n: PNode) =
     useMagic(p, "reraiseException")
     app(p.body, "reraiseException();" & tnl)
 
-proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
   var
     cond, stmt: TCompRes
   genLineDir(p, n)
   gen(p, n.sons[0], cond)
   let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
-  if stringSwitch: 
+  if stringSwitch:
     useMagic(p, "toJSStr")
     appf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
   else:
@@ -636,25 +636,25 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
     case it.kind
-    of nkOfBranch: 
-      for j in countup(0, sonsLen(it) - 2): 
+    of nkOfBranch:
+      for j in countup(0, sonsLen(it) - 2):
         let e = it.sons[j]
-        if e.kind == nkRange: 
+        if e.kind == nkRange:
           var v = copyNode(e.sons[0])
-          while v.intVal <= e.sons[1].intVal: 
+          while v.intVal <= e.sons[1].intVal:
             gen(p, v, cond)
             appf(p.body, "case $1: ", [cond.rdLoc])
             inc(v.intVal)
         else:
-          if stringSwitch: 
+          if stringSwitch:
             case e.kind
-            of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ", 
+            of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ",
                 [makeJSString(e.strVal)])
             else: internalError(e.info, "jsgen.genCaseStmt: 2")
-          else: 
+          else:
             gen(p, e, cond)
             appf(p.body, "case $1: ", [cond.rdLoc])
       gen(p, lastSon(it), stmt)
@@ -668,7 +668,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
     else: internalError(it.info, "jsgen.genCaseStmt")
   appf(p.body, "}$n")
 
-proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
   var
     cond, stmt: TCompRes
   genLineDir(p, n)
@@ -681,13 +681,13 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
     case it.kind
     of nkOfBranch:
       if i != 1: appf(p.body, "$nelsif ")
       else: appf(p.body, "if ")
-      for j in countup(0, sonsLen(it) - 2): 
+      for j in countup(0, sonsLen(it) - 2):
         if j != 0: app(p.body, " or ")
         let e = it.sons[j]
         if e.kind == nkRange:
@@ -696,7 +696,7 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
           gen(p, e.sons[1], ib)
           appf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc])
         else:
-          if stringSwitch: 
+          if stringSwitch:
             case e.kind
             of nkStrLit..nkTripleStrLit: appf(p.body, "eqStr($1, $2)",
                 [tmp, makeJSString(e.strVal)])
@@ -713,11 +713,11 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
       moveInto(p, stmt, r)
     else: internalError(it.info, "jsgen.genCaseStmt")
   appf(p.body, "$nend$n")
-  
+
 proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
   inc(p.unique)
   let idx = len(p.blocks)
-  if n.sons[0].kind != nkEmpty: 
+  if n.sons[0].kind != nkEmpty:
     # named block?
     if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
     var sym = n.sons[0].sym
@@ -731,10 +731,10 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
   appf(p.body, "} while(false);$n" | "$n::L$#::$n", labl.toRope)
   setLen(p.blocks, idx)
 
-proc genBreakStmt(p: PProc, n: PNode) = 
+proc genBreakStmt(p: PProc, n: PNode) =
   var idx: int
   genLineDir(p, n)
-  if n.sons[0].kind != nkEmpty: 
+  if n.sons[0].kind != nkEmpty:
     # named break?
     assert(n.sons[0].kind == nkSym)
     let sym = n.sons[0].sym
@@ -749,24 +749,24 @@ proc genBreakStmt(p: PProc, n: PNode) =
   p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
   appf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [toRope(p.blocks[idx].id)])
 
-proc genAsmStmt(p: PProc, n: PNode) = 
+proc genAsmStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
   assert(n.kind == nkAsmStmt)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     case n.sons[i].kind
     of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal)
     of nkSym: app(p.body, mangleName(n.sons[i].sym))
     else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
-  
-proc genIf(p: PProc, n: PNode, r: var TCompRes) = 
+
+proc genIf(p: PProc, n: PNode, r: var TCompRes) =
   var cond, stmt: TCompRes
   var toClose = 0
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     let it = n.sons[i]
-    if sonsLen(it) != 1: 
+    if sonsLen(it) != 1:
       if i > 0:
         appf(p.body, "else {$n" | "else$n", [])
         inc(toClose)
@@ -793,18 +793,18 @@ proc generateHeader(p: PProc, typ: PType): PRope =
     if isCompileTimeOnly(param.typ): continue
     var name = mangleName(param)
     app(result, name)
-    if mapType(param.typ) == etyBaseIndex: 
+    if mapType(param.typ) == etyBaseIndex:
       app(result, ", ")
       app(result, name)
       app(result, "_Idx")
 
-const 
-  nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
-    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString, 
-    nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, 
+const
+  nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
+    nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
     nkCommand, nkHiddenCallConv, nkCallStrLit}
 
-proc needsNoCopy(y: PNode): bool = 
+proc needsNoCopy(y: PNode): bool =
   result = (y.kind in nodeKindsNeedNoCopy) or
       (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyVar})
 
@@ -820,22 +820,22 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
       useMagic(p, "nimCopy")
       appf(p.body, "$1 = nimCopy($2, $3);$n",
            [a.res, b.res, genTypeInfo(p, y.typ)])
-  of etyBaseIndex: 
-    if a.typ != etyBaseIndex or b.typ != etyBaseIndex: 
+  of etyBaseIndex:
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       internalError(x.info, "genAsgn")
     appf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
   else:
     appf(p.body, "$1 = $2;$n", [a.res, b.res])
 
-proc genAsgn(p: PProc, n: PNode) = 
+proc genAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
   genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
 
-proc genFastAsgn(p: PProc, n: PNode) = 
+proc genFastAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
   genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true)
 
-proc genSwap(p: PProc, n: PNode) = 
+proc genSwap(p: PProc, n: PNode) =
   var a, b: TCompRes
   gen(p, n.sons[1], a)
   gen(p, n.sons[2], b)
@@ -844,7 +844,7 @@ proc genSwap(p: PProc, n: PNode) =
   if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
     inc(p.unique)
     let tmp2 = ropef("Tmp$1", [toRope(p.unique)])
-    if a.typ != etyBaseIndex or b.typ != etyBaseIndex: 
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       internalError(n.info, "genSwap")
     appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
                  "local $1 = $2; $2 = $3; $3 = $1;$n", [
@@ -859,7 +859,7 @@ proc getFieldPosition(f: PNode): int =
   of nkSym: result = f.sym.position
   else: internalError(f.info, "genFieldPosition")
 
-proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = 
+proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   r.typ = etyBaseIndex
   let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
@@ -875,7 +875,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   r.address = a.res
   r.kind = resExpr
 
-proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = 
+proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
   r.typ = etyNone
   gen(p, n.sons[0], r)
   if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
@@ -887,14 +887,16 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
     r.res = ropef("$1.$2", [r.res, f.loc.r])
   r.kind = resExpr
 
-proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) = 
-  genFieldAddr(p, n.sons[0], r) # XXX
-  
-proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
+  let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
+  internalAssert m.kind == nkCheckedFieldExpr
+  genFieldAddr(p, m.sons[0], r) # XXX
+
+proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
   genFieldAccess(p, n.sons[0], r) # XXX
-  
-proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = 
-  var 
+
+proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
+  var
     a, b: TCompRes
     first: BiggestInt
   r.typ = etyBaseIndex
@@ -908,7 +910,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   else: first = 0
   if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
     useMagic(p, "chckIndx")
-    r.res = ropef("chckIndx($1, $2, $3.length)-$2", 
+    r.res = ropef("chckIndx($1, $2, $3.length)-$2",
                   [b.res, toRope(first), a.res])
   elif first != 0:
     r.res = ropef("($1)-$2", [b.res, toRope(first)])
@@ -916,14 +918,14 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
     r.res = b.res
   r.kind = resExpr
 
-proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = 
+proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
   var ty = skipTypes(n.sons[0].typ, abstractVarRange)
   if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
   case ty.kind
   of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
      tyVarargs:
     genArrayAddr(p, n, r)
-  of tyTuple: 
+  of tyTuple:
     genFieldAddr(p, n, r)
   else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
   r.typ = etyNone
@@ -967,12 +969,12 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
     of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
        tyVarargs:
       genArrayAddr(p, n, r)
-    of tyTuple: 
+    of tyTuple:
       genFieldAddr(p, n, r)
     else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
   else: internalError(n.info, "genAddr")
-  
-proc genSym(p: PProc, n: PNode, r: var TCompRes) = 
+
+proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   var s = n.sym
   case s.kind
   of skVar, skLet, skParam, skTemp, skResult:
@@ -1019,9 +1021,9 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
       internalError(n.info, "symbol has no generated name: " & s.name.s)
     r.res = s.loc.r
   r.kind = resVal
-  
-proc genDeref(p: PProc, n: PNode, r: var TCompRes) = 
-  if mapType(n.sons[0].typ) == etyObject: 
+
+proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
+  if mapType(n.sons[0].typ) == etyObject:
     gen(p, n.sons[0], r)
   else:
     var a: TCompRes
@@ -1041,15 +1043,15 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) =
 
 proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
   app(r.res, "(")
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
-    if it.typ.isCompileTimeOnly: continue  
+    if it.typ.isCompileTimeOnly: continue
     if i > 1: app(r.res, ", ")
     genArg(p, it, r)
   app(r.res, ")")
   r.kind = resExpr
 
-proc genCall(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCall(p: PProc, n: PNode, r: var TCompRes) =
   gen(p, n.sons[0], r)
   genArgs(p, n, r)
 
@@ -1065,7 +1067,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
   var op: TCompRes
   gen(p, n.sons[0], op)
   app(r.res, op.res)
-  
+
   app(r.res, "(")
   for i in countup(2, sonsLen(n) - 1):
     if i > 2: app(r.res, ", ")
@@ -1080,88 +1082,88 @@ proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
   internalAssert n.kind == nkBracket
   for i in countup(0, sonsLen(n) - 1):
     let it = n.sons[i]
-    if it.typ.isCompileTimeOnly: continue  
+    if it.typ.isCompileTimeOnly: continue
     if i > 0: app(r.res, ", ")
     genArg(p, it, r)
   app(r.res, ")")
   r.kind = resExpr
 
-proc putToSeq(s: string, indirect: bool): PRope = 
+proc putToSeq(s: string, indirect: bool): PRope =
   result = toRope(s)
   if indirect: result = ropef("[$1]", [result])
-  
+
 proc createVar(p: PProc, typ: PType, indirect: bool): PRope
-proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope = 
+proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope =
   result = nil
   case rec.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(rec) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(rec) - 1):
       app(result, createRecordVarAux(p, rec.sons[i], c))
-  of nkRecCase: 
+  of nkRecCase:
     app(result, createRecordVarAux(p, rec.sons[0], c))
-    for i in countup(1, sonsLen(rec) - 1): 
+    for i in countup(1, sonsLen(rec) - 1):
       app(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
-  of nkSym: 
+  of nkSym:
     if c > 0: app(result, ", ")
     app(result, mangleName(rec.sym))
     app(result, ": ")
     app(result, createVar(p, rec.sym.typ, false))
     inc(c)
   else: internalError(rec.info, "createRecordVarAux")
-  
-proc createVar(p: PProc, typ: PType, indirect: bool): PRope = 
+
+proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
   var t = skipTypes(typ, abstractInst)
   case t.kind
-  of tyInt..tyInt64, tyEnum, tyChar: 
+  of tyInt..tyInt64, tyEnum, tyChar:
     result = putToSeq("0", indirect)
-  of tyFloat..tyFloat128: 
+  of tyFloat..tyFloat128:
     result = putToSeq("0.0", indirect)
-  of tyRange, tyGenericInst: 
+  of tyRange, tyGenericInst:
     result = createVar(p, lastSon(typ), indirect)
-  of tySet: 
+  of tySet:
     result = toRope("{}")
-  of tyBool: 
+  of tyBool:
     result = putToSeq("false", indirect)
-  of tyArray, tyArrayConstr: 
+  of tyArray, tyArrayConstr:
     var length = int(lengthOrd(t))
     var e = elemType(t)
-    if length > 32: 
+    if length > 32:
       useMagic(p, "arrayConstr")
       # XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
       useMagic(p, "nimCopy")
-      result = ropef("arrayConstr($1, $2, $3)", [toRope(length), 
+      result = ropef("arrayConstr($1, $2, $3)", [toRope(length),
           createVar(p, e, false), genTypeInfo(p, e)])
-    else: 
+    else:
       result = toRope("[")
       var i = 0
-      while i < length: 
+      while i < length:
         if i > 0: app(result, ", ")
         app(result, createVar(p, e, false))
         inc(i)
       app(result, "]")
-  of tyTuple: 
+  of tyTuple:
     result = toRope("{")
     for i in 0.. <t.sonsLen:
       if i > 0: app(result, ", ")
-      appf(result, "Field$1: $2" | "Field$# = $#", i.toRope, 
+      appf(result, "Field$1: $2" | "Field$# = $#", i.toRope,
            createVar(p, t.sons[i], false))
     app(result, "}")
-  of tyObject: 
+  of tyObject:
     result = toRope("{")
     var c = 0
     if tfFinal notin t.flags or t.sons[0] != nil:
       inc(c)
       appf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
-    while t != nil: 
+    while t != nil:
       app(result, createRecordVarAux(p, t.n, c))
       t = t.sons[0]
     app(result, "}")
-  of tyVar, tyPtr, tyRef: 
+  of tyVar, tyPtr, tyRef:
     if mapType(t) == etyBaseIndex:
       result = putToSeq("[null, 0]" | "{nil, 0}", indirect)
     else:
       result = putToSeq("null" | "nil", indirect)
-  of tySequence, tyString, tyCString, tyPointer, tyProc: 
+  of tySequence, tyString, tyCString, tyPointer, tyProc:
     result = putToSeq("null" | "nil", indirect)
   else:
     internalError("createVar: " & $t.kind)
@@ -1172,42 +1174,42 @@ proc isIndirect(v: PSym): bool =
     (mapType(v.typ) != etyObject) and
     v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
 
-proc genVarInit(p: PProc, v: PSym, n: PNode) = 
-  var 
+proc genVarInit(p: PProc, v: PSym, n: PNode) =
+  var
     a: TCompRes
     s: PRope
-  if n.kind == nkEmpty: 
-    appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", 
+  if n.kind == nkEmpty:
+    appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n",
          [mangleName(v), createVar(p, v.typ, isIndirect(v))])
-  else: 
+  else:
     discard mangleName(v)
     gen(p, n, a)
     case mapType(v.typ)
-    of etyObject: 
-      if needsNoCopy(n): 
+    of etyObject:
+      if needsNoCopy(n):
         s = a.res
-      else: 
+      else:
         useMagic(p, "nimCopy")
         s = ropef("nimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)])
-    of etyBaseIndex: 
+    of etyBaseIndex:
       if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
-      if {sfAddrTaken, sfGlobal} * v.flags != {}: 
-        appf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n", 
+      if {sfAddrTaken, sfGlobal} * v.flags != {}:
+        appf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n",
             [v.loc.r, a.address, a.res])
       else:
-        appf(p.body, "var $1 = $2; var $1_Idx = $3;$n" | 
+        appf(p.body, "var $1 = $2; var $1_Idx = $3;$n" |
                      "local $1 = $2; local $1_Idx = $3;$n", [
              v.loc.r, a.address, a.res])
       return
     else:
       s = a.res
-    if isIndirect(v): 
+    if isIndirect(v):
       appf(p.body, "var $1 = [$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
-    else: 
+    else:
       appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
-  
-proc genVarStmt(p: PProc, n: PNode) = 
-  for i in countup(0, sonsLen(n) - 1): 
+
+proc genVarStmt(p: PProc, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if a.kind != nkCommentStmt:
       if a.kind == nkVarTuple:
@@ -1249,7 +1251,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
   of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r)
   of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)" | "toBool($#)")
   else: internalError(n.info, "genOrd")
-  
+
 proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
 
@@ -1282,7 +1284,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
     gen(p, n.sons[1], r)
     useMagic(p, "cstrToNimstr")
     r.kind = resExpr
-    r.res = ropef("cstrToNimstr($1.node.sons[$2].name)", 
+    r.res = ropef("cstrToNimstr($1.node.sons[$2].name)",
                  [genTypeInfo(p, t), r.res])
   else:
     # XXX:
@@ -1303,11 +1305,11 @@ proc genReset(p: PProc, n: PNode) =
   var x: TCompRes
   useMagic(p, "genericReset")
   gen(p, n.sons[1], x)
-  appf(p.body, "$1 = genericReset($1, $2);$n", [x.res, 
+  appf(p.body, "$1 = genericReset($1, $2);$n", [x.res,
                 genTypeInfo(p, n.sons[1].typ)])
 
 proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
-  var 
+  var
     a: TCompRes
     line, filen: PRope
   var op = n.sons[0].sym.magic
@@ -1384,34 +1386,34 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))")
   of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
   of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
-  of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")    
+  of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
   else:
     genCall(p, n, r)
     #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
-  
-proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = 
+
+proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
   var
     a, b: TCompRes
   useMagic(p, "SetConstr")
   r.res = toRope("SetConstr(")
   r.kind = resExpr
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     if i > 0: app(r.res, ", ")
     var it = n.sons[i]
-    if it.kind == nkRange: 
+    if it.kind == nkRange:
       gen(p, it.sons[0], a)
       gen(p, it.sons[1], b)
       appf(r.res, "[$1, $2]", [a.res, b.res])
-    else: 
+    else:
       gen(p, it, a)
       app(r.res, a.res)
   app(r.res, ")")
 
-proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = 
+proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   r.res = toRope("[")
   r.kind = resExpr
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     if i > 0: app(r.res, ", ")
     gen(p, n.sons[i], a)
     app(r.res, a.res)
@@ -1444,7 +1446,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
     appf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
   r.res.app("}")
 
-proc genConv(p: PProc, n: PNode, r: var TCompRes) = 
+proc genConv(p: PProc, n: PNode, r: var TCompRes) =
   var dest = skipTypes(n.typ, abstractVarRange)
   var src = skipTypes(n.sons[1].typ, abstractVarRange)
   gen(p, n.sons[1], r)
@@ -1460,24 +1462,24 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
   else:
     # TODO: What types must we handle here?
     discard
-  
-proc upConv(p: PProc, n: PNode, r: var TCompRes) = 
+
+proc upConv(p: PProc, n: PNode, r: var TCompRes) =
   gen(p, n.sons[0], r)        # XXX
-  
-proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = 
+
+proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
   var a, b: TCompRes
   gen(p, n.sons[0], r)
-  if optRangeCheck in p.options: 
+  if optRangeCheck in p.options:
     gen(p, n.sons[1], a)
     gen(p, n.sons[2], b)
     useMagic(p, "chckRange")
     r.res = ropef("chckRange($1, $2, $3)", [r.res, a.res, b.res])
     r.kind = resExpr
 
-proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) = 
+proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
   # we do an optimization here as this is likely to slow down
   # much of the code otherwise:
-  if n.sons[0].kind == nkCStringToString: 
+  if n.sons[0].kind == nkCStringToString:
     gen(p, n.sons[0].sons[0], r)
   else:
     gen(p, n.sons[0], r)
@@ -1486,22 +1488,22 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
     r.res = ropef("toJSStr($1)", [r.res])
     r.kind = resExpr
 
-proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) = 
+proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
   # we do an optimization here as this is likely to slow down
   # much of the code otherwise:
-  if n.sons[0].kind == nkStringToCString: 
+  if n.sons[0].kind == nkStringToCString:
     gen(p, n.sons[0].sons[0], r)
-  else: 
+  else:
     gen(p, n.sons[0], r)
     if r.res == nil: internalError(n.info, "convCStrToStr")
     useMagic(p, "cstrToNimstr")
     r.res = ropef("cstrToNimstr($1)", [r.res])
     r.kind = resExpr
 
-proc genReturnStmt(p: PProc, n: PNode) = 
+proc genReturnStmt(p: PProc, n: PNode) =
   if p.procDef == nil: internalError(n.info, "genReturnStmt")
   p.beforeRetNeeded = true
-  if (n.sons[0].kind != nkEmpty): 
+  if (n.sons[0].kind != nkEmpty):
     genStmt(p, n.sons[0])
   else:
     genLineDir(p, n)
@@ -1517,22 +1519,22 @@ proc genProcBody(p: PProc, prc: PSym): PRope =
   else:
     result = nil
   if p.beforeRetNeeded:
-    appf(result, "BeforeRet: do {$n$1} while (false); $n" | 
+    appf(result, "BeforeRet: do {$n$1} while (false); $n" |
                  "$#;::BeforeRet::$n", [p.body])
   else:
     app(result, p.body)
-  if prc.typ.callConv == ccSysCall and p.target == targetJS: 
+  if prc.typ.callConv == ccSysCall and p.target == targetJS:
     result = ropef("try {$n$1} catch (e) {$n" &
         " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}", [result])
-  if optStackTrace in prc.options: 
+  if optStackTrace in prc.options:
     app(result, "framePtr = framePtr.prev;" & tnl)
 
-proc genProc(oldProc: PProc, prc: PSym): PRope = 
+proc genProc(oldProc: PProc, prc: PSym): PRope =
   var
     resultSym: PSym
     name, returnStmt, resultAsgn, header: PRope
     a: TCompRes
-  #if gVerbosity >= 3: 
+  #if gVerbosity >= 3:
   #  echo "BEGIN generating code for: " & prc.name.s
   var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
   p.target = oldProc.target
@@ -1541,17 +1543,17 @@ proc genProc(oldProc: PProc, prc: PSym): PRope =
   resultAsgn = nil
   name = mangleName(prc)
   header = generateHeader(p, prc.typ)
-  if prc.typ.sons[0] != nil and sfPure notin prc.flags: 
+  if prc.typ.sons[0] != nil and sfPure notin prc.flags:
     resultSym = prc.ast.sons[resultPos].sym
     resultAsgn = ropef("var $# = $#;$n" | "local $# = $#;$n", [
-        mangleName(resultSym), 
+        mangleName(resultSym),
         createVar(p, resultSym.typ, isIndirect(resultSym))])
     gen(p, prc.ast.sons[resultPos], a)
     returnStmt = ropef("return $#;$n", [a.res])
   genStmt(p, prc.getBody)
   result = ropef("function $#($#) {$n$#$#$#$#}$n" |
                  "function $#($#) $n$#$#$#$#$nend$n",
-                [name, header, p.locals, resultAsgn, 
+                [name, header, p.locals, resultAsgn,
                  genProcBody(p, prc), returnStmt])
   #if gVerbosity >= 3:
   #  echo "END   generated code for: " & prc.name.s
@@ -1584,28 +1586,28 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
       r.res = toRope"null" | toRope"nil"
       r.kind = resExpr
   of nkStrLit..nkTripleStrLit:
-    if skipTypes(n.typ, abstractVarRange).kind == tyString: 
+    if skipTypes(n.typ, abstractVarRange).kind == tyString:
       useMagic(p, "cstrToNimstr")
       r.res = ropef("cstrToNimstr($1)", [makeJSString(n.strVal)])
-    else: 
+    else:
       r.res = makeJSString(n.strVal)
     r.kind = resExpr
-  of nkFloatLit..nkFloat64Lit: 
+  of nkFloatLit..nkFloat64Lit:
     let f = n.floatVal
     if f != f: r.res = toRope"NaN"
     elif f == 0.0: r.res = toRope"0.0"
-    elif f == 0.5 * f: 
+    elif f == 0.5 * f:
       if f > 0.0: r.res = toRope"Infinity"
       else: r.res = toRope"-Infinity"
     else: r.res = toRope(f.toStrMaxPrecision)
     r.kind = resExpr
   of nkCallKinds:
-    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): 
+    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
       genMagic(p, n, r)
     elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
         n.len >= 2:
       genInfixCall(p, n, r)
-    else: 
+    else:
       genCall(p, n, r)
   of nkCurly: genSetConstr(p, n, r)
   of nkBracket: genArrayConstr(p, n, r)
@@ -1626,7 +1628,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkStringToCString: convStrToCStr(p, n, r)
   of nkCStringToString: convCStrToStr(p, n, r)
   of nkEmpty: discard
-  of nkLambdaKinds: 
+  of nkLambdaKinds:
     let s = n.sons[namePos].sym
     discard mangleName(s)
     r.res = s.loc.r
@@ -1647,9 +1649,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkWhileStmt: genWhileStmt(p, n)
   of nkVarSection, nkLetSection: genVarStmt(p, n)
   of nkConstSection: discard
-  of nkForStmt, nkParForStmt: 
+  of nkForStmt, nkParForStmt:
     internalError(n.info, "for statement not eliminated")
-  of nkCaseStmt: 
+  of nkCaseStmt:
     if p.target == targetJS: genCaseJS(p, n, r)
     else: genCaseLua(p, n, r)
   of nkReturnStmt: genReturnStmt(p, n)
@@ -1663,8 +1665,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt: genTry(p, n, r)
   of nkRaiseStmt: genRaiseStmt(p, n)
-  of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, 
-     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, 
+  of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
+     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
      nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard
   of nkProcDef, nkMethodDef, nkConverterDef:
     var s = n.sons[namePos].sym
@@ -1675,33 +1677,33 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
     internalError(n.info, "first class iterators not implemented")
   of nkPragmaBlock: gen(p, n.lastSon, r)
   else: internalError(n.info, "gen: unknown node type: " & $n.kind)
-  
+
 var globals: PGlobals
 
-proc newModule(module: PSym): BModule = 
+proc newModule(module: PSym): BModule =
   new(result)
   result.module = module
   if globals == nil: globals = newGlobals()
-  
+
 proc genHeader(): PRope =
   result = ropef("/* Generated by the Nim Compiler v$1 */$n" &
                  "/*   (c) 2015 Andreas Rumpf */$n$n" &
-                 "var framePtr = null;$n" & 
+                 "var framePtr = null;$n" &
                  "var excHandler = null;$n" &
-                 "var lastJSError = null;$n", 
+                 "var lastJSError = null;$n",
                  [toRope(VersionAsString)])
 
-proc genModule(p: PProc, n: PNode) = 
+proc genModule(p: PProc, n: PNode) =
   if optStackTrace in p.options:
     appf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
                  "framePtr = F;$n", [
-        makeJSString("module " & p.module.module.name.s), 
+        makeJSString("module " & p.module.module.name.s),
         makeJSString(toFilename(p.module.module.info))])
   genStmt(p, n)
   if optStackTrace in p.options:
     appf(p.body, "framePtr = framePtr.prev;$n")
 
-proc myProcess(b: PPassContext, n: PNode): PNode = 
+proc myProcess(b: PPassContext, n: PNode): PNode =
   if passes.skipCodegen(n): return n
   result = n
   var m = BModule(b)
@@ -1716,17 +1718,17 @@ proc wholeCode*(m: BModule): PRope =
     if not globals.generatedSyms.containsOrIncl(prc.id):
       var p = newProc(globals, m, nil, m.module.options)
       app(p.g.code, genProc(p, prc))
-  
+
   var disp = generateMethodDispatchers()
-  for i in 0..sonsLen(disp)-1: 
+  for i in 0..sonsLen(disp)-1:
     let prc = disp.sons[i].sym
     if not globals.generatedSyms.containsOrIncl(prc.id):
       var p = newProc(globals, m, nil, m.module.options)
       app(p.g.code, genProc(p, prc))
 
   result = con(globals.typeInfo, globals.code)
-  
-proc myClose(b: PPassContext, n: PNode): PNode = 
+
+proc myClose(b: PPassContext, n: PNode): PNode =
   if passes.skipCodegen(n): return n
   result = myProcess(b, n)
   var m = BModule(b)
@@ -1740,11 +1742,11 @@ proc myClose(b: PPassContext, n: PNode): PNode =
        changeFileExt(completeCFilePath(m.module.filename), "js")
     discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
 
-proc myOpenCached(s: PSym, rd: PRodReader): PPassContext = 
+proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
   internalError("symbol files are not possible with the JS code generator")
   result = nil
 
-proc myOpen(s: PSym): PPassContext = 
+proc myOpen(s: PSym): PPassContext =
   result = newModule(s)
 
 const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index 8b032c3ce..1288c854d 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -123,7 +123,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
   case t.kind
   of tyDistinct: 
     result = genTypeInfo(p, typ.sons[0])
-  of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyFloat128: 
+  of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
     var s = ropef(
       "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", 
               [result, toRope(ord(t.kind))])
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 0f670ae7a..a51ca9ed6 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -23,7 +23,7 @@ proc newTupleAccess*(tup: PNode, i: int): PNode =
   lit.intVal = i
   addSon(result, lit)
 
-proc addVar*(father, v: PNode) = 
+proc addVar*(father, v: PNode) =
   var vpart = newNodeI(nkIdentDefs, v.info, 3)
   vpart.sons[0] = v
   vpart.sons[1] = ast.emptyNode
@@ -53,7 +53,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
   let tempAsNode = newSymNode(temp)
   v.addVar(tempAsNode)
   result.add(v)
-  
+
   result.add newAsgnStmt(tempAsNode, value)
   for i in 0 .. n.len-3:
     if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
@@ -70,7 +70,7 @@ proc rawAddField*(obj: PType; field: PSym) =
   field.position = sonsLen(obj.n)
   addSon(obj.n, newSymNode(field))
 
-proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode = 
+proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
   # returns a[].field as a node
   assert field.kind == skField
   var deref = newNodeI(nkHiddenDeref, info)
@@ -109,7 +109,7 @@ proc newDotExpr(obj, b: PSym): PNode =
   addSon(result, newSymNode(field))
   result.typ = field.typ
 
-proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = 
+proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
   # returns a[].b as a node
   var deref = newNodeI(nkHiddenDeref, info)
   deref.typ = a.typ.skipTypes(abstractInst).sons[0]
@@ -144,7 +144,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
     if t == nil: break
     t = t.skipTypes(abstractInst)
 
-proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = 
+proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
   # returns a[].b as a node
   result = indirectAccess(a, b.name.s & $b.id, info)
 
@@ -158,11 +158,11 @@ proc genAddrOf*(n: PNode): PNode =
   result.typ.rawAddSon(n.typ)
 
 proc genDeref*(n: PNode): PNode =
-  result = newNodeIT(nkHiddenDeref, n.info, 
+  result = newNodeIT(nkHiddenDeref, n.info,
                      n.typ.skipTypes(abstractInst).sons[0])
   result.add n
 
-proc callCodegenProc*(name: string, arg1: PNode; 
+proc callCodegenProc*(name: string, arg1: PNode;
                       arg2, arg3: PNode = nil): PNode =
   result = newNodeI(nkCall, arg1.info)
   let sym = magicsys.getCompilerProc(name)
@@ -203,6 +203,17 @@ proc flowVarKind(t: PType): TFlowVarKind =
   elif containsGarbageCollectedRef(t): fvInvalid
   else: fvBlob
 
+proc typeNeedsNoDeepCopy(t: PType): bool =
+  var t = t.skipTypes(abstractInst)
+  # for the tconvexhull example (and others) we're a bit lax here and pretend
+  # seqs and strings are *by value* only and 'shallow' doesn't exist!
+  if t.kind == tyString: return true
+  # note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var'
+  # for the stricter check and likewise we can skip 'seq' for a less
+  # strict check:
+  if t.kind in {tyVar, tySequence}: t = t.sons[0]
+  result = not containsGarbageCollectedRef(t)
+
 proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
                  v: PNode; useShallowCopy=false): PSym =
   result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
@@ -215,7 +226,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
   vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
   varSection.add vpart
   if varInit != nil:
-    if useShallowCopy:
+    if useShallowCopy and typeNeedsNoDeepCopy(typ):
       varInit.add newFastAsgnStmt(newSymNode(result), v)
     else:
       let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
@@ -236,10 +247,10 @@ proc f_wrapper(thread, args) =
 
   fv.owner = thread # optional
   nimArgsPassingDone() # signal parent that the work is done
-  # 
+  #
   args.fv.blob = f(a, b, ...)
   nimFlowVarSignal(args.fv)
-  
+
   # - or -
   f(a, b, ...)
   barrierLeave(args.barrier)  # for parallel statement
@@ -261,7 +272,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
   var threadLocalBarrier: PSym
   if barrier != nil:
     var varSection2 = newNodeI(nkVarSection, barrier.info)
-    threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, 
+    threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
                                      barrier.typ, barrier)
     body.add varSection2
     body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
@@ -285,7 +296,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
   elif fv != nil:
     let fk = fv.typ.sons[1].flowVarKind
     if fk == fvInvalid:
-      localError(f.info, "cannot create a flowVar of type: " & 
+      localError(f.info, "cannot create a flowVar of type: " &
         typeToString(fv.typ.sons[1]))
     body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
       if fk == fvGC: "data" else: "blob", fv.info), call)
@@ -330,8 +341,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
   result.typ = newType(tyPtr, objType.owner)
   result.typ.rawAddSon(objType)
 
-proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, 
-                             castExpr, call, 
+proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
+                             castExpr, call,
                              varSection, varInit, result: PNode) =
   let formals = n[0].typ.n
   let tmpName = getIdent(genPrefix)
@@ -385,7 +396,7 @@ proc genHigh(n: PNode): PNode =
     result.sons[1] = n
 
 proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
-                             castExpr, call, 
+                             castExpr, call,
                              varSection, varInit, result: PNode) =
   let formals = n[0].typ.n
   let tmpName = getIdent(genPrefix)
@@ -409,7 +420,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
       var fieldB = newSym(skField, tmpName, objType.owner, n.info)
       fieldB.typ = getSysType(tyInt)
       objType.addField(fieldB)
-      
+
       if getMagic(n) == mSlice:
         let a = genAddrOf(n[1])
         field.typ = a.typ
@@ -464,7 +475,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
                                     useShallowCopy=true)
       call.add(threadLocal.newSymNode)
 
-proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; 
+proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
                        barrier, dest: PNode = nil): PNode =
   # if 'barrier' != nil, then it is in a 'parallel' section and we
   # generate quite different code
@@ -530,10 +541,10 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
   var varSection = newNodeI(nkVarSection, n.info)
   var varInit = newNodeI(nkStmtList, n.info)
   if barrier.isNil:
-    setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, 
+    setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
                             varSection, varInit, result)
   else:
-    setupArgsForParallelism(n, objType, scratchObj, castExpr, call, 
+    setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
                             varSection, varInit, result)
 
   var barrierAsExpr: PNode = nil
@@ -566,7 +577,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
     fvAsExpr = indirectAccess(castExpr, field, n.info)
     result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
 
-  let wrapper = createWrapperProc(fn, threadParam, argsParam, 
+  let wrapper = createWrapperProc(fn, threadParam, argsParam,
                                   varSection, varInit, call,
                                   barrierAsExpr, fvAsExpr, spawnKind)
   result.add callCodegenProc("nimSpawn", wrapper.newSymNode,
diff --git a/compiler/main.nim b/compiler/main.nim
index f7592a891..363327e40 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -58,7 +58,7 @@ proc commandCompileToC =
   registerPass(cgenPass)
   rodPass()
   #registerPass(cleanupPass())
-  
+
   compileProject()
   cgenWriteModules()
   if gCmd != cmdRun:
@@ -363,7 +363,9 @@ proc mainCommand* =
       gVerbosity > 0):
     rawMessage(hintSuccessX, [$gLinesCompiled,
                formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
-               formatSize(getTotalMem())])
+               formatSize(getTotalMem()),
+               if condSyms.isDefined("release"): "Release Build"
+               else: "Debug Build"])
 
   when PrintRopeCacheStats:
     echo "rope cache stats: "
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index e15cdc86d..0f7921ddb 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -10,95 +10,95 @@
 import
   options, strutils, os, tables, ropes, platform
 
-type 
-  TMsgKind* = enum 
-    errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, 
-    errXCompilerDoesNotSupportCpp, errStringLiteralExpected, 
-    errIntLiteralExpected, errInvalidCharacterConstant, 
-    errClosingTripleQuoteExpected, errClosingQuoteExpected, 
-    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, 
-    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter, 
-    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected, 
+type
+  TMsgKind* = enum
+    errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
+    errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
+    errIntLiteralExpected, errInvalidCharacterConstant,
+    errClosingTripleQuoteExpected, errClosingQuoteExpected,
+    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
+    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
+    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
     errNewlineExpected,
     errInvalidModuleName,
-    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected, 
-    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, 
-    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, 
-    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, 
-    errExceptionExpected, errExceptionAlreadyHandled, 
-    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, 
-    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine, 
-    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel, 
-    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected, 
-    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, 
-    errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound, 
-    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound, 
-    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound, 
-    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected, 
-    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected, 
-    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable, 
-    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, 
-    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, 
-    errConstantDivisionByZero, errOrdinalTypeExpected, 
-    errOrdinalOrFloatTypeExpected, errOverOrUnderflow, 
-    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, 
-    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, 
-    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, 
-    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, 
-    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, 
-    errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected, 
-    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, 
-    errMagicOnlyInSystem, errPowerOfTwoExpected, 
-    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, 
-    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected, 
-    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes, 
-    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid, 
-    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop, 
-    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue, 
-    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, 
-    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, 
-    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, 
+    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
+    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
+    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
+    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
+    errExceptionExpected, errExceptionAlreadyHandled,
+    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
+    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
+    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
+    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
+    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
+    errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,
+    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
+    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
+    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
+    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
+    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
+    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
+    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
+    errConstantDivisionByZero, errOrdinalTypeExpected,
+    errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
+    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
+    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
+    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
+    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
+    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
+    errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,
+    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
+    errMagicOnlyInSystem, errPowerOfTwoExpected,
+    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
+    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
+    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
+    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
+    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
+    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
+    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
+    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
+    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
     errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
-    errVarForOutParamNeeded, 
-    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, 
-    errAmbiguousCallXYZ, errWrongNumberOfArguments, 
-    errXCannotBePassedToProcVar, 
-    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, 
-    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, 
-    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, 
+    errVarForOutParamNeeded,
+    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
+    errAmbiguousCallXYZ, errWrongNumberOfArguments,
+    errXCannotBePassedToProcVar,
+    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
+    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
+    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
     errInvalidOrderInArrayConstructor,
-    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, 
-    errOptionExpected, errXisNoLabel, errNotAllCasesCovered, 
-    errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, 
-    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, 
-    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, 
-    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, 
+    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
+    errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
+    errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
+    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
+    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
+    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
     errXNotAllowedHere, errInvalidControlFlowX,
-    errXisNoType, errCircumNeedsPointer, errInvalidExpression, 
-    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, 
-    errNamedExprNotAllowed, errXExpectsOneTypeParam, 
-    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, 
-    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, 
+    errXisNoType, errCircumNeedsPointer, errInvalidExpression,
+    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
+    errNamedExprNotAllowed, errXExpectsOneTypeParam,
+    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
+    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
     errNoReturnTypeDeclared,
-    errInvalidCommandX, errXOnlyAtModuleScope, 
+    errInvalidCommandX, errXOnlyAtModuleScope,
     errXNeedsParamObjectType,
-    errTemplateInstantiationTooNested, errInstantiationFrom, 
+    errTemplateInstantiationTooNested, errInstantiationFrom,
     errInvalidIndexValueForTuple, errCommandExpectsFilename,
     errMainModuleMustBeSpecified,
     errXExpected,
     errTIsNotAConcreteType,
-    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, 
-    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, 
+    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
+    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
     errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
     errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
     errMacroBodyDependsOnGenericTypes,
     errDestructorNotGenericEnough,
     errInlineIteratorsAsProcParams,
     errXExpectsTwoArguments,
-    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, 
-    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, 
-    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, 
-    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate, 
+    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
+    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
+    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
+    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
     errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
     errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
     errXCannotBeClosure, errXMustBeCompileTime,
@@ -107,17 +107,18 @@ type
     errGenericLambdaNotAllowed,
     errCompilerDoesntSupportTarget,
     errUser,
-    warnCannotOpenFile, 
-    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, 
+    warnCannotOpenFile,
+    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
     warnDeprecated, warnConfigDeprecated,
-    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, 
+    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
     warnUnknownSubstitutionX, warnLanguageXNotSupported,
-    warnFieldXNotSupported, warnCommentXIgnored, 
+    warnFieldXNotSupported, warnCommentXIgnored,
     warnNilStatement, warnTypelessParam,
     warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
-    warnEachIdentIsTuple, warnShadowIdent, 
+    warnEachIdentIsTuple, warnShadowIdent,
     warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
-    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnUser,
+    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
+    warnUser,
     hintSuccess, hintSuccessX,
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
@@ -125,205 +126,205 @@ type
     hintConditionAlwaysTrue, hintName, hintPattern,
     hintUser
 
-const 
+const
   MsgKindToStr*: array[TMsgKind, string] = [
-    errUnknown: "unknown error", 
+    errUnknown: "unknown error",
     errIllFormedAstX: "illformed AST: $1",
-    errInternal: "internal error: $1", 
-    errCannotOpenFile: "cannot open \'$1\'", 
-    errGenerated: "$1", 
-    errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++", 
-    errStringLiteralExpected: "string literal expected", 
-    errIntLiteralExpected: "integer literal expected", 
-    errInvalidCharacterConstant: "invalid character constant", 
-    errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached", 
-    errClosingQuoteExpected: "closing \" expected", 
-    errTabulatorsAreNotAllowed: "tabulators are not allowed", 
-    errInvalidToken: "invalid token: $1", 
-    errLineTooLong: "line too long", 
-    errInvalidNumber: "$1 is not a valid number", 
-    errNumberOutOfRange: "number $1 out of valid range", 
-    errNnotAllowedInCharacter: "\\n not allowed in character literal", 
-    errClosingBracketExpected: "closing ']' expected, but end of file reached", 
-    errMissingFinalQuote: "missing final \' for character literal", 
-    errIdentifierExpected: "identifier expected, but found \'$1\'", 
+    errInternal: "internal error: $1",
+    errCannotOpenFile: "cannot open \'$1\'",
+    errGenerated: "$1",
+    errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
+    errStringLiteralExpected: "string literal expected",
+    errIntLiteralExpected: "integer literal expected",
+    errInvalidCharacterConstant: "invalid character constant",
+    errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached",
+    errClosingQuoteExpected: "closing \" expected",
+    errTabulatorsAreNotAllowed: "tabulators are not allowed",
+    errInvalidToken: "invalid token: $1",
+    errLineTooLong: "line too long",
+    errInvalidNumber: "$1 is not a valid number",
+    errNumberOutOfRange: "number $1 out of valid range",
+    errNnotAllowedInCharacter: "\\n not allowed in character literal",
+    errClosingBracketExpected: "closing ']' expected, but end of file reached",
+    errMissingFinalQuote: "missing final \' for character literal",
+    errIdentifierExpected: "identifier expected, but found \'$1\'",
     errNewlineExpected: "newline expected, but found \'$1\'",
     errInvalidModuleName: "invalid module name: '$1'",
-    errOperatorExpected: "operator expected, but found \'$1\'", 
-    errTokenExpected: "\'$1\' expected", 
-    errStringAfterIncludeExpected: "string after \'include\' expected", 
-    errRecursiveDependencyX: "recursive dependency: \'$1\'", 
-    errOnOrOffExpected: "\'on\' or \'off\' expected", 
-    errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected", 
-    errInvalidPragma: "invalid pragma", 
-    errUnknownPragma: "unknown pragma: \'$1\'", 
-    errInvalidDirectiveX: "invalid directive: \'$1\'", 
-    errAtPopWithoutPush: "\'pop\' without a \'push\' pragma", 
-    errEmptyAsm: "empty asm statement", 
-    errInvalidIndentation: "invalid indentation", 
-    errExceptionExpected: "exception expected", 
-    errExceptionAlreadyHandled: "exception already handled", 
+    errOperatorExpected: "operator expected, but found \'$1\'",
+    errTokenExpected: "\'$1\' expected",
+    errStringAfterIncludeExpected: "string after \'include\' expected",
+    errRecursiveDependencyX: "recursive dependency: \'$1\'",
+    errOnOrOffExpected: "\'on\' or \'off\' expected",
+    errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
+    errInvalidPragma: "invalid pragma",
+    errUnknownPragma: "unknown pragma: \'$1\'",
+    errInvalidDirectiveX: "invalid directive: \'$1\'",
+    errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
+    errEmptyAsm: "empty asm statement",
+    errInvalidIndentation: "invalid indentation",
+    errExceptionExpected: "exception expected",
+    errExceptionAlreadyHandled: "exception already handled",
     errYieldNotAllowedHere: "'yield' only allowed in an iterator",
     errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
-    errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions", 
-    errCannotReturnExpr: "current routine cannot return an expression", 
-    errAttemptToRedefine: "redefinition of \'$1\'", 
-    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'", 
-    errStmtExpected: "statement expected", 
-    errInvalidLabel: "\'$1\' is no label", 
-    errInvalidCmdLineOption: "invalid command line option: \'$1\'", 
-    errCmdLineArgExpected: "argument for command line option expected: \'$1\'", 
-    errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'", 
-    errInvalidVarSubstitution: "invalid variable substitution in \'$1\'", 
-    errUnknownVar: "unknown variable: \'$1\'", 
-    errUnknownCcompiler: "unknown C compiler: \'$1\'", 
-    errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found", 
-    errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found", 
-    errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found", 
-    errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found", 
-    errUnknownOS: "unknown OS: '$1'", 
-    errUnknownCPU: "unknown CPU: '$1'", 
-    errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found", 
-    errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected", 
-    errInvalidMultipleAsgn: "multiple assignment is not allowed", 
-    errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'", 
-    errExprExpected: "expression expected, but found \'$1\'", 
-    errUndeclaredIdentifier: "undeclared identifier: \'$1\'", 
-    errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier", 
-    errTypeExpected: "type expected", 
-    errSystemNeeds: "system module needs \'$1\'", 
-    errExecutionOfProgramFailed: "execution of an external program failed", 
-    errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls", 
-    errInvalidArgForX: "invalid argument for \'$1\'", 
-    errStmtHasNoEffect: "statement has no effect", 
-    errXExpectsTypeOrValue: "\'$1\' expects a type or value", 
-    errXExpectsArrayType: "\'$1\' expects an array type", 
-    errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", 
-    errExprXAmbiguous: "expression '$1' ambiguous in this context", 
-    errConstantDivisionByZero: "division by zero", 
-    errOrdinalTypeExpected: "ordinal type expected", 
-    errOrdinalOrFloatTypeExpected: "ordinal or float type expected", 
-    errOverOrUnderflow: "over- or underflow", 
-    errCannotEvalXBecauseIncompletelyDefined: "cannot evalutate '$1' because type is not defined completely", 
-    errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255", 
-    errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'", 
-    errUndeclaredFieldX: "undeclared field: \'$1\'", 
+    errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
+    errCannotReturnExpr: "current routine cannot return an expression",
+    errAttemptToRedefine: "redefinition of \'$1\'",
+    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'",
+    errStmtExpected: "statement expected",
+    errInvalidLabel: "\'$1\' is no label",
+    errInvalidCmdLineOption: "invalid command line option: \'$1\'",
+    errCmdLineArgExpected: "argument for command line option expected: \'$1\'",
+    errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'",
+    errInvalidVarSubstitution: "invalid variable substitution in \'$1\'",
+    errUnknownVar: "unknown variable: \'$1\'",
+    errUnknownCcompiler: "unknown C compiler: \'$1\'",
+    errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found",
+    errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
+    errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
+    errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
+    errUnknownOS: "unknown OS: '$1'",
+    errUnknownCPU: "unknown CPU: '$1'",
+    errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
+    errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
+    errInvalidMultipleAsgn: "multiple assignment is not allowed",
+    errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'",
+    errExprExpected: "expression expected, but found \'$1\'",
+    errUndeclaredIdentifier: "undeclared identifier: \'$1\'",
+    errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier",
+    errTypeExpected: "type expected",
+    errSystemNeeds: "system module needs \'$1\'",
+    errExecutionOfProgramFailed: "execution of an external program failed",
+    errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls",
+    errInvalidArgForX: "invalid argument for \'$1\'",
+    errStmtHasNoEffect: "statement has no effect",
+    errXExpectsTypeOrValue: "\'$1\' expects a type or value",
+    errXExpectsArrayType: "\'$1\' expects an array type",
+    errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
+    errExprXAmbiguous: "expression '$1' ambiguous in this context",
+    errConstantDivisionByZero: "division by zero",
+    errOrdinalTypeExpected: "ordinal type expected",
+    errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
+    errOverOrUnderflow: "over- or underflow",
+    errCannotEvalXBecauseIncompletelyDefined: "cannot evalutate '$1' because type is not defined completely",
+    errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255",
+    errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'",
+    errUndeclaredFieldX: "undeclared field: \'$1\'",
     errNilAccess: "attempt to access a nil address",
-    errIndexOutOfBounds: "index out of bounds", 
-    errIndexTypesDoNotMatch: "index types do not match", 
-    errBracketsInvalidForType: "\'[]\' operator invalid for this type", 
-    errValueOutOfSetBounds: "value out of set bounds", 
-    errFieldInitTwice: "field initialized twice: \'$1\'", 
-    errFieldNotInit: "field \'$1\' not initialized", 
-    errExprXCannotBeCalled: "expression \'$1\' cannot be called", 
-    errExprHasNoType: "expression has no type", 
-    errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)", 
+    errIndexOutOfBounds: "index out of bounds",
+    errIndexTypesDoNotMatch: "index types do not match",
+    errBracketsInvalidForType: "\'[]\' operator invalid for this type",
+    errValueOutOfSetBounds: "value out of set bounds",
+    errFieldInitTwice: "field initialized twice: \'$1\'",
+    errFieldNotInit: "field \'$1\' not initialized",
+    errExprXCannotBeCalled: "expression \'$1\' cannot be called",
+    errExprHasNoType: "expression has no type",
+    errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)",
     errCastNotInSafeMode: "\'cast\' not allowed in safe mode",
-    errExprCannotBeCastedToX: "expression cannot be casted to $1", 
-    errCommaOrParRiExpected: "',' or ')' expected", 
-    errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected", 
-    errSectionExpected: "section (\'type\', \'proc\', etc.) expected", 
-    errRangeExpected: "range expected", 
-    errMagicOnlyInSystem: "\'magic\' only allowed in system module", 
+    errExprCannotBeCastedToX: "expression cannot be casted to $1",
+    errCommaOrParRiExpected: "',' or ')' expected",
+    errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected",
+    errSectionExpected: "section (\'type\', \'proc\', etc.) expected",
+    errRangeExpected: "range expected",
+    errMagicOnlyInSystem: "\'magic\' only allowed in system module",
     errPowerOfTwoExpected: "power of two expected",
-    errStringMayNotBeEmpty: "string literal may not be empty", 
-    errCallConvExpected: "calling convention expected", 
-    errProcOnlyOneCallConv: "a proc can only have one calling convention", 
-    errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used", 
-    errExprMustBeBool: "expression must be of type 'bool'", 
-    errConstExprExpected: "constant expression expected", 
-    errDuplicateCaseLabel: "duplicate case label", 
-    errRangeIsEmpty: "range is empty", 
-    errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string", 
-    errSelectorMustBeOrdinal: "selector must be of an ordinal type", 
-    errOrdXMustNotBeNegative: "ord($1) must not be negative", 
+    errStringMayNotBeEmpty: "string literal may not be empty",
+    errCallConvExpected: "calling convention expected",
+    errProcOnlyOneCallConv: "a proc can only have one calling convention",
+    errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
+    errExprMustBeBool: "expression must be of type 'bool'",
+    errConstExprExpected: "constant expression expected",
+    errDuplicateCaseLabel: "duplicate case label",
+    errRangeIsEmpty: "range is empty",
+    errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string",
+    errSelectorMustBeOrdinal: "selector must be of an ordinal type",
+    errOrdXMustNotBeNegative: "ord($1) must not be negative",
     errLenXinvalid: "len($1) must be less than 32768",
-    errWrongNumberOfVariables: "wrong number of variables", 
-    errExprCannotBeRaised: "only a 'ref object' can be raised", 
-    errBreakOnlyInLoop: "'break' only allowed in loop construct", 
-    errTypeXhasUnknownSize: "type \'$1\' has unknown size", 
-    errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", 
-    errConstNeedsValue: "a constant needs a value", 
-    errResultCannotBeOpenArray: "the result type cannot be on open array", 
-    errSizeTooBig: "computing the type\'s size produced an overflow", 
-    errSetTooBig: "set is too large", 
-    errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", 
-    errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", 
+    errWrongNumberOfVariables: "wrong number of variables",
+    errExprCannotBeRaised: "only a 'ref object' can be raised",
+    errBreakOnlyInLoop: "'break' only allowed in loop construct",
+    errTypeXhasUnknownSize: "type \'$1\' has unknown size",
+    errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
+    errConstNeedsValue: "a constant needs a value",
+    errResultCannotBeOpenArray: "the result type cannot be on open array",
+    errSizeTooBig: "computing the type\'s size produced an overflow",
+    errSetTooBig: "set is too large",
+    errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
+    errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
     errInheritanceOnlyWithEnums: "inheritance only works with an enum",
-    errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'", 
-    errCannotInstantiateX: "cannot instantiate: \'$1\'", 
-    errExprHasNoAddress: "expression has no address", 
+    errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'",
+    errCannotInstantiateX: "cannot instantiate: \'$1\'",
+    errExprHasNoAddress: "expression has no address",
     errXStackEscape: "address of '$1' may not escape its stack frame",
     errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed",
-    errPureTypeMismatch: "type mismatch", 
-    errTypeMismatch: "type mismatch: got (", 
+    errPureTypeMismatch: "type mismatch",
+    errTypeMismatch: "type mismatch: got (",
     errButExpected: "but expected one of: ",
-    errButExpectedX: "but expected \'$1\'", 
-    errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", 
-    errWrongNumberOfArguments: "wrong number of arguments", 
-    errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar", 
-    errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration", 
-    errPragmaOnlyInHeaderOfProc: "pragmas are only allowed in the header of a proc", 
-    errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", 
-    errImplOfXexpected: "implementation of \'$1\' expected", 
-    errNoSymbolToBorrowFromFound: "no symbol to borrow from found", 
-    errDiscardValueX: "value of type '$1' has to be discarded", 
-    errInvalidDiscard: "statement returns no value that can be discarded", 
+    errButExpectedX: "but expected \'$1\'",
+    errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
+    errWrongNumberOfArguments: "wrong number of arguments",
+    errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
+    errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
+    errPragmaOnlyInHeaderOfProc: "pragmas are only allowed in the header of a proc",
+    errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
+    errImplOfXexpected: "implementation of \'$1\' expected",
+    errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
+    errDiscardValueX: "value of type '$1' has to be discarded",
+    errInvalidDiscard: "statement returns no value that can be discarded",
     errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
-    errCannotBindXTwice: "cannot bind parameter \'$1\' twice", 
+    errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
     errInvalidOrderInArrayConstructor: "invalid order in array constructor",
-    errInvalidOrderInEnumX: "invalid order in enum \'$1\'", 
-    errEnumXHasHoles: "enum \'$1\' has holes", 
-    errExceptExpected: "\'except\' or \'finally\' expected", 
-    errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow", 
+    errInvalidOrderInEnumX: "invalid order in enum \'$1\'",
+    errEnumXHasHoles: "enum \'$1\' has holes",
+    errExceptExpected: "\'except\' or \'finally\' expected",
+    errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow",
     errOptionExpected: "option expected, but found \'$1\'",
-    errXisNoLabel: "\'$1\' is not a label", 
-    errNotAllCasesCovered: "not all cases are covered", 
-    errUnknownSubstitionVar: "unknown substitution variable: \'$1\'", 
+    errXisNoLabel: "\'$1\' is not a label",
+    errNotAllCasesCovered: "not all cases are covered",
+    errUnknownSubstitionVar: "unknown substitution variable: \'$1\'",
     errComplexStmtRequiresInd: "complex statement requires indentation",
-    errXisNotCallable: "\'$1\' is not callable", 
-    errNoPragmasAllowedForX: "no pragmas allowed for $1", 
-    errNoGenericParamsAllowedForX: "no generic parameters allowed for $1", 
-    errInvalidParamKindX: "invalid param kind: \'$1\'", 
-    errDefaultArgumentInvalid: "default argument invalid", 
-    errNamedParamHasToBeIdent: "named parameter has to be an identifier", 
-    errNoReturnTypeForX: "no return type allowed for $1", 
-    errConvNeedsOneArg: "a type conversion needs exactly one argument", 
-    errInvalidPragmaX: "invalid pragma: $1", 
+    errXisNotCallable: "\'$1\' is not callable",
+    errNoPragmasAllowedForX: "no pragmas allowed for $1",
+    errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
+    errInvalidParamKindX: "invalid param kind: \'$1\'",
+    errDefaultArgumentInvalid: "default argument invalid",
+    errNamedParamHasToBeIdent: "named parameter has to be an identifier",
+    errNoReturnTypeForX: "no return type allowed for $1",
+    errConvNeedsOneArg: "a type conversion needs exactly one argument",
+    errInvalidPragmaX: "invalid pragma: $1",
     errXNotAllowedHere: "$1 not allowed here",
     errInvalidControlFlowX: "invalid control flow: $1",
     errXisNoType: "invalid type: \'$1\'",
-    errCircumNeedsPointer: "'[]' needs a pointer or reference type", 
+    errCircumNeedsPointer: "'[]' needs a pointer or reference type",
     errInvalidExpression: "invalid expression",
-    errInvalidExpressionX: "invalid expression: \'$1\'", 
+    errInvalidExpressionX: "invalid expression: \'$1\'",
     errEnumHasNoValueX: "enum has no value \'$1\'",
-    errNamedExprExpected: "named expression expected", 
-    errNamedExprNotAllowed: "named expression not allowed here", 
-    errXExpectsOneTypeParam: "\'$1\' expects one type parameter", 
-    errArrayExpectsTwoTypeParams: "array expects two type parameters", 
-    errInvalidVisibilityX: "invalid visibility: \'$1\'", 
-    errInitHereNotAllowed: "initialization not allowed here", 
-    errXCannotBeAssignedTo: "\'$1\' cannot be assigned to", 
-    errIteratorNotAllowed: "iterators can only be defined at the module\'s top level", 
+    errNamedExprExpected: "named expression expected",
+    errNamedExprNotAllowed: "named expression not allowed here",
+    errXExpectsOneTypeParam: "\'$1\' expects one type parameter",
+    errArrayExpectsTwoTypeParams: "array expects two type parameters",
+    errInvalidVisibilityX: "invalid visibility: \'$1\'",
+    errInitHereNotAllowed: "initialization not allowed here",
+    errXCannotBeAssignedTo: "\'$1\' cannot be assigned to",
+    errIteratorNotAllowed: "iterators can only be defined at the module\'s top level",
     errXNeedsReturnType: "$1 needs a return type",
     errNoReturnTypeDeclared: "no return type declared",
-    errInvalidCommandX: "invalid command: \'$1\'", 
-    errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", 
+    errInvalidCommandX: "invalid command: \'$1\'",
+    errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
     errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
     errTemplateInstantiationTooNested: "template/macro instantiation too nested",
-    errInstantiationFrom: "template/generic instantiation from here", 
-    errInvalidIndexValueForTuple: "invalid index value for tuple subscript", 
+    errInstantiationFrom: "template/generic instantiation from here",
+    errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
     errCommandExpectsFilename: "command expects a filename argument",
     errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
-    errXExpected: "\'$1\' expected", 
+    errXExpected: "\'$1\' expected",
     errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
     errInvalidSectionStart: "invalid section start",
-    errGridTableNotImplemented: "grid table is not implemented", 
+    errGridTableNotImplemented: "grid table is not implemented",
     errGeneralParseError: "general parse error",
-    errNewSectionExpected: "new section expected", 
+    errNewSectionExpected: "new section expected",
     errWhitespaceExpected: "whitespace expected, got \'$1\'",
-    errXisNoValidIndexFile: "\'$1\' is no valid index file", 
-    errCannotRenderX: "cannot render reStructuredText element \'$1\'", 
+    errXisNoValidIndexFile: "\'$1\' is no valid index file",
+    errCannotRenderX: "cannot render reStructuredText element \'$1\'",
     errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
     errInstantiateXExplicitly: "instantiate '$1' explicitly",
     errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
@@ -334,24 +335,24 @@ const
                                    "A destructor must be associated will all instantiations of a generic type",
     errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
                                     "templates, macros and other inline iterators",
-    errXExpectsTwoArguments: "\'$1\' expects two arguments", 
+    errXExpectsTwoArguments: "\'$1\' expects two arguments",
     errXExpectsObjectTypes: "\'$1\' expects object types",
-    errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", 
-    errTooManyIterations: "interpretation requires too many iterations", 
-    errCannotInterpretNodeX: "cannot evaluate \'$1\'", 
-    errFieldXNotFound: "field \'$1\' cannot be found", 
+    errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
+    errTooManyIterations: "interpretation requires too many iterations",
+    errCannotInterpretNodeX: "cannot evaluate \'$1\'",
+    errFieldXNotFound: "field \'$1\' cannot be found",
     errInvalidConversionFromTypeX: "invalid conversion from type \'$1\'",
-    errAssertionFailed: "assertion failed", 
-    errCannotGenerateCodeForX: "cannot generate code for \'$1\'", 
-    errXRequiresOneArgument: "$1 requires one parameter", 
-    errUnhandledExceptionX: "unhandled exception: $1", 
-    errCyclicTree: "macro returned a cyclic abstract syntax tree", 
+    errAssertionFailed: "assertion failed",
+    errCannotGenerateCodeForX: "cannot generate code for \'$1\'",
+    errXRequiresOneArgument: "$1 requires one parameter",
+    errUnhandledExceptionX: "unhandled exception: $1",
+    errCyclicTree: "macro returned a cyclic abstract syntax tree",
     errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
-    errXhasSideEffects: "\'$1\' can have side effects", 
+    errXhasSideEffects: "\'$1\' can have side effects",
     errIteratorExpected: "iterator within for loop context expected",
     errLetNeedsInit: "'let' symbol requires an initialization",
     errThreadvarCannotInit: "a thread var cannot be initialized explicitly",
-    errWrongSymbolX: "usage of \'$1\' is a user-defined error", 
+    errWrongSymbolX: "usage of \'$1\' is a user-defined error",
     errIllegalCaptureX: "illegal capture '$1'",
     errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
     errXMustBeCompileTime: "'$1' can only be used in compile-time context",
@@ -361,21 +362,21 @@ const
                                 "it is used as an operand to another routine and the types " &
                                 "of the generic paramers can be inferred from the expected signature.",
     errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
-    errUser: "$1", 
+    errUser: "$1",
     warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
-    warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]", 
-    warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]", 
-    warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]", 
-    warnDeprecated: "$1 is deprecated [Deprecated]", 
+    warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
+    warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
+    warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
+    warnDeprecated: "$1 is deprecated [Deprecated]",
     warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
-    warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]", 
-    warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]", 
-    warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]", 
-    warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]", 
-    warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]", 
-    warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]", 
-    warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]", 
-    warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]", 
+    warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
+    warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
+    warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
+    warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
+    warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
+    warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
+    warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
+    warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
     warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]",
     warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
     warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
@@ -391,19 +392,20 @@ const
     warnGcMem: "'$1' uses GC'ed memory [GcMem]",
     warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
     warnLockLevel: "$1 [LockLevel]",
-    warnUser: "$1 [User]", 
-    hintSuccess: "operation successful [Success]", 
-    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", 
-    hintLineTooLong: "line too long [LineTooLong]", 
-    hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]", 
-    hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]", 
-    hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]", 
-    hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]", 
+    warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
+    warnUser: "$1 [User]",
+    hintSuccess: "operation successful [Success]",
+    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#) [SuccessX]",
+    hintLineTooLong: "line too long [LineTooLong]",
+    hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]",
+    hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]",
+    hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]",
+    hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]",
     hintQuitCalled: "quit() called [QuitCalled]",
-    hintProcessing: "$1 [Processing]", 
+    hintProcessing: "$1 [Processing]",
     hintCodeBegin: "generated code listing: [CodeBegin]",
-    hintCodeEnd: "end of listing [CodeEnd]", 
-    hintConf: "used config file \'$1\' [Conf]", 
+    hintCodeEnd: "end of listing [CodeEnd]",
+    hintConf: "used config file \'$1\' [Conf]",
     hintPath: "added path: '$1' [Path]",
     hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
     hintName: "name should be: '$1' [Name]",
@@ -411,25 +413,25 @@ const
     hintUser: "$1 [User]"]
 
 const
-  WarningsToStr*: array[0..29, string] = ["CannotOpenFile", "OctalEscape", 
+  WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
     "XIsNeverRead", "XmightNotBeenInit",
     "Deprecated", "ConfigDeprecated",
-    "SmallLshouldNotBeUsed", "UnknownMagic", 
+    "SmallLshouldNotBeUsed", "UnknownMagic",
     "RedefinitionOfLabel", "UnknownSubstitutionX",
     "LanguageXNotSupported", "FieldXNotSupported",
     "CommentXIgnored", "NilStmt",
     "TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
-    "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", 
+    "UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
     "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
-    "GcMem", "Destructor", "LockLevel", "User"]
+    "GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
 
-  HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong", 
-    "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", 
-    "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", 
+  HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
+    "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
+    "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
     "Path", "CondTrue", "Name", "Pattern",
     "User"]
 
-const 
+const
   fatalMin* = errUnknown
   fatalMax* = errInternal
   errMin* = errUnknown
@@ -438,18 +440,18 @@ const
   warnMax* = pred(hintSuccess)
   hintMin* = hintSuccess
   hintMax* = high(TMsgKind)
- 
-type 
+
+type
   TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
   TNoteKinds* = set[TNoteKind]
 
-  TFileInfo* = object 
+  TFileInfo* = object
     fullPath: string           # This is a canonical full filesystem path
     projPath*: string          # This is relative to the project's root
     shortName*: string         # short name of the module
     quotedName*: PRope         # cached quoted short name for codegen
                                # purposes
-    
+
     lines*: seq[PRope]         # the source code of the module
                                #   used for better error messages and
                                #   embedding the original source in the
@@ -460,13 +462,13 @@ type
 
   TLineInfo* = object          # This is designed to be as small as possible,
                                # because it is used
-                               # in syntax nodes. We save space here by using 
+                               # in syntax nodes. We save space here by using
                                # two int16 and an int32.
-                               # On 64 bit and on 32 bit systems this is 
+                               # On 64 bit and on 32 bit systems this is
                                # only 8 bytes.
     line*, col*: int16
     fileIndex*: int32
-  
+
   TErrorOutput* = enum
     eStdOut
     eStdErr
@@ -485,7 +487,7 @@ var
   fileInfos*: seq[TFileInfo] = @[]
   systemFileIdx*: int32
 
-proc toCChar*(c: char): string = 
+proc toCChar*(c: char): string =
   case c
   of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
   of '\'', '\"', '\\': result = '\\' & c
@@ -495,7 +497,7 @@ proc makeCString*(s: string): PRope =
   # BUGFIX: We have to split long strings into many ropes. Otherwise
   # this could trigger an internalError(). See the ropes module for
   # further information.
-  const 
+  const
     MaxLineLength = 64
   result = nil
   var res = "\""
@@ -569,7 +571,7 @@ proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
 proc sourceLine*(i: TLineInfo): PRope
 
 var
-  gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - 
+  gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
                         {warnShadowIdent, warnUninit,
                          warnProveField, warnProveIndex, warnGcUnsafe}
   gErrorCounter*: int = 0     # counts the number of errors
@@ -582,7 +584,7 @@ proc unknownLineInfo*(): TLineInfo =
   result.col = int16(-1)
   result.fileIndex = -1
 
-var 
+var
   msgContext: seq[TLineInfo] = @[]
   lastError = unknownLineInfo()
   bufferedMsgs*: seq[string]
@@ -597,7 +599,7 @@ proc suggestWriteln*(s: string) =
   if eStdOut in errorOutputs:
     if isNil(writelnHook): writeln(stdout, s)
     else: writelnHook(s)
-  
+
   if eInMemory in errorOutputs:
     bufferedMsgs.safeAdd(s)
 
@@ -621,10 +623,10 @@ const
 proc getInfoContextLen*(): int = return msgContext.len
 proc setInfoContextLen*(L: int) = setLen(msgContext, L)
 
-proc pushInfoContext*(info: TLineInfo) = 
+proc pushInfoContext*(info: TLineInfo) =
   msgContext.add(info)
-  
-proc popInfoContext*() = 
+
+proc popInfoContext*() =
   setLen(msgContext, len(msgContext) - 1)
 
 proc getInfoContext*(index: int): TLineInfo =
@@ -667,10 +669,10 @@ proc toMsgFilename*(info: TLineInfo): string =
   else:
     result = fileInfos[info.fileIndex].projPath
 
-proc toLinenumber*(info: TLineInfo): int {.inline.} = 
+proc toLinenumber*(info: TLineInfo): int {.inline.} =
   result = info.line
 
-proc toColumn*(info: TLineInfo): int {.inline.} = 
+proc toColumn*(info: TLineInfo): int {.inline.} =
   result = info.col
 
 proc toFileLine*(info: TLineInfo): string {.inline.} =
@@ -687,11 +689,11 @@ proc `??`* (info: TLineInfo, filename: string): bool =
 
 var gTrackPos*: TLineInfo
 
-proc outWriteln*(s: string) = 
+proc outWriteln*(s: string) =
   ## Writes to stdout. Always.
   if eStdOut in errorOutputs: writeln(stdout, s)
- 
-proc msgWriteln*(s: string) = 
+
+proc msgWriteln*(s: string) =
   ## Writes to stdout. If --stdout option is given, writes to stderr instead.
 
   #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
@@ -702,18 +704,18 @@ proc msgWriteln*(s: string) =
     if eStdErr in errorOutputs: writeln(stderr, s)
   else:
     if eStdOut in errorOutputs: writeln(stdout, s)
-  
+
   if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
 
-proc coordToStr(coord: int): string = 
+proc coordToStr(coord: int): string =
   if coord == -1: result = "???"
   else: result = $coord
-  
-proc msgKindToString*(kind: TMsgKind): string = 
+
+proc msgKindToString*(kind: TMsgKind): string =
   # later versions may provide translated error messages
   result = MsgKindToStr[kind]
 
-proc getMessageStr(msg: TMsgKind, arg: string): string = 
+proc getMessageStr(msg: TMsgKind, arg: string): string =
   result = msgKindToString(msg) % [arg]
 
 type
@@ -743,34 +745,34 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
 proc `==`*(a, b: TLineInfo): bool =
   result = a.line == b.line and a.fileIndex == b.fileIndex
 
-proc writeContext(lastinfo: TLineInfo) = 
+proc writeContext(lastinfo: TLineInfo) =
   var info = lastinfo
-  for i in countup(0, len(msgContext) - 1): 
-    if msgContext[i] != lastinfo and msgContext[i] != info: 
-      msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]), 
-                                     coordToStr(msgContext[i].line), 
-                                     coordToStr(msgContext[i].col), 
+  for i in countup(0, len(msgContext) - 1):
+    if msgContext[i] != lastinfo and msgContext[i] != info:
+      msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
+                                     coordToStr(msgContext[i].line),
+                                     coordToStr(msgContext[i].col),
                                      getMessageStr(errInstantiationFrom, "")])
     info = msgContext[i]
 
 proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
   msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
 
-proc rawMessage*(msg: TMsgKind, args: openArray[string]) = 
+proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
   var frmt: string
   case msg
-  of errMin..errMax: 
+  of errMin..errMax:
     writeContext(unknownLineInfo())
     frmt = RawErrorFormat
-  of warnMin..warnMax: 
-    if optWarns notin gOptions: return 
-    if msg notin gNotes: return 
+  of warnMin..warnMax:
+    if optWarns notin gOptions: return
+    if msg notin gNotes: return
     writeContext(unknownLineInfo())
     frmt = RawWarningFormat
     inc(gWarnCounter)
-  of hintMin..hintMax: 
-    if optHints notin gOptions: return 
-    if msg notin gNotes: return 
+  of hintMin..hintMax:
+    if optHints notin gOptions: return
+    if msg notin gNotes: return
     frmt = RawHintFormat
     inc(gHintCounter)
   let s = `%`(frmt, `%`(msgKindToString(msg), args))
@@ -778,7 +780,7 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
     msgWriteln(s)
   handleError(msg, doAbort, s)
 
-proc rawMessage*(msg: TMsgKind, arg: string) = 
+proc rawMessage*(msg: TMsgKind, arg: string) =
   rawMessage(msg, [arg])
 
 proc writeSurroundingSrc(info: TLineInfo) =
@@ -794,7 +796,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
   result = frmt % [toMsgFilename(info), coordToStr(info.line),
                    coordToStr(info.col), getMessageStr(msg, arg)]
 
-proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, 
+proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
                eh: TErrorHandling) =
   var frmt: string
   var ignoreMsg = false
@@ -811,7 +813,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     if not ignoreMsg: writeContext(info)
     frmt = PosWarningFormat
     inc(gWarnCounter)
-  of hintMin..hintMax: 
+  of hintMin..hintMax:
     ignoreMsg = optHints notin gOptions or msg notin gNotes
     frmt = PosHintFormat
     inc(gHintCounter)
@@ -822,11 +824,11 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     if optPrintSurroundingSrc and msg in errMin..errMax:
       info.writeSurroundingSrc
   handleError(msg, eh, s)
-  
-proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") = 
+
+proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doAbort)
 
-proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") = 
+proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doRaise)
 
 proc globalError*(info: TLineInfo, arg: string) =
@@ -841,12 +843,12 @@ proc localError*(info: TLineInfo, arg: string) =
 proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doNothing)
 
-proc internalError*(info: TLineInfo, errMsg: string) = 
+proc internalError*(info: TLineInfo, errMsg: string) =
   if gCmd == cmdIdeTools: return
   writeContext(info)
   liMessage(info, errInternal, errMsg, doAbort)
 
-proc internalError*(errMsg: string) = 
+proc internalError*(errMsg: string) =
   if gCmd == cmdIdeTools: return
   writeContext(unknownLineInfo())
   rawMessage(errInternal, errMsg)
@@ -863,7 +865,7 @@ proc addSourceLine*(fileIdx: int32, line: string) =
 
 proc sourceLine*(i: TLineInfo): PRope =
   if i.fileIndex < 0: return nil
-  
+
   if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
     try:
       for line in lines(i.toFullPath):
diff --git a/compiler/nim.nim.cfg b/compiler/nim.nim.cfg
index f4d8b9dcb..64631a437 100644
--- a/compiler/nim.nim.cfg
+++ b/compiler/nim.nim.cfg
@@ -18,3 +18,4 @@ define:useStdoutAsStdmsg
 cs:partial
 #define:useNodeIds
 symbol:nimfix
+#gc:markAndSweep
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 8fbf033d8..9e4d45cd2 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -865,6 +865,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
   #|     [' optInd  (identColonEquals (comma/semicolon)?)*  optPar ']'
   #| extTupleDecl = 'tuple'
   #|     COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
+  #| tupleClass = 'tuple'
   result = newNodeP(nkTupleTy, p)
   getTok(p)
   if p.tok.tokType == tkBracketLe:
@@ -894,6 +895,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
             parMessage(p, errIdentifierExpected, p.tok)
             break
           if not sameInd(p): break
+  else:
+    result = newNodeP(nkTupleClassTy, p)
 
 proc parseParamList(p: var TParser, retColon = true): PNode =
   #| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 96088bd88..129d8ad47 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -10,15 +10,15 @@
 # This module implements the passes functionality. A pass must implement the
 # `TPass` interface.
 
-import 
-  strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, 
-  condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, 
+import
+  strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
+  condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
   nimsets, syntaxes, times, rodread, idgen
 
-type  
+type
   TPassContext* = object of RootObj # the pass's context
     fromCache*: bool  # true if created by "openCached"
-   
+
   PPassContext* = ref TPassContext
 
   TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
@@ -33,8 +33,8 @@ type
   TPassData* = tuple[input: PNode, closeOutput: PNode]
   TPasses* = openArray[TPass]
 
-# a pass is a tuple of procedure vars ``TPass.close`` may produce additional 
-# nodes. These are passed to the other close procedures. 
+# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
+# nodes. These are passed to the other close procedures.
 # This mechanism used to be used for the instantiation of generics.
 
 proc makePass*(open: TPassOpen = nil,
@@ -53,46 +53,46 @@ proc makePass*(open: TPassOpen = nil,
 proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
 
 # the semantic checker needs these:
-var 
+var
   gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
   gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
 
 # implementation
 
-proc skipCodegen*(n: PNode): bool {.inline.} = 
-  # can be used by codegen passes to determine whether they should do 
+proc skipCodegen*(n: PNode): bool {.inline.} =
+  # can be used by codegen passes to determine whether they should do
   # something with `n`. Currently, this ignores `n` and uses the global
   # error count instead.
   result = msgs.gErrorCounter > 0
 
-proc astNeeded*(s: PSym): bool = 
+proc astNeeded*(s: PSym): bool =
   # The ``rodwrite`` module uses this to determine if the body of a proc
   # needs to be stored. The passes manager frees s.sons[codePos] when
   # appropriate to free the procedure body's memory. This is important
   # to keep memory usage down.
   if (s.kind in {skMethod, skProc}) and
       ({sfCompilerProc, sfCompileTime} * s.flags == {}) and
-      (s.typ.callConv != ccInline) and 
-      (s.ast.sons[genericParamsPos].kind == nkEmpty): 
+      (s.typ.callConv != ccInline) and
+      (s.ast.sons[genericParamsPos].kind == nkEmpty):
     result = false
     # XXX this doesn't really make sense with excessive CTFE
   else:
     result = true
-  
-const 
+
+const
   maxPasses = 10
 
-type 
+type
   TPassContextArray = array[0..maxPasses - 1, PPassContext]
 
-var 
+var
   gPasses: array[0..maxPasses - 1, TPass]
   gPassesLen*: int
 
 proc clearPasses* =
   gPassesLen = 0
 
-proc registerPass*(p: TPass) = 
+proc registerPass*(p: TPass) =
   gPasses[gPassesLen] = p
   inc(gPassesLen)
 
@@ -109,48 +109,48 @@ proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) =
     passdata = carryPass(pass, module, passdata)
 
 proc openPasses(a: var TPassContextArray, module: PSym) =
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].open): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].open):
       a[i] = gPasses[i].open(module)
     else: a[i] = nil
-  
+
 proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].openCached): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].openCached):
       a[i] = gPasses[i].openCached(module, rd)
-      if a[i] != nil: 
+      if a[i] != nil:
         a[i].fromCache = true
     else:
       a[i] = nil
-  
-proc closePasses(a: var TPassContextArray) = 
+
+proc closePasses(a: var TPassContextArray) =
   var m: PNode = nil
-  for i in countup(0, gPassesLen - 1): 
+  for i in countup(0, gPassesLen - 1):
     if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m)
     a[i] = nil                # free the memory here
-  
-proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool = 
+
+proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
   # this implements the code transformation pipeline
   var m = n
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].process): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].process):
       m = gPasses[i].process(a[i], m)
       if isNil(m): return false
   result = true
-  
-proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = 
+
+proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
   # this implements the code transformation pipeline
   var m = n
-  for i in countup(0, gPassesLen - 1): 
+  for i in countup(0, gPassesLen - 1):
     if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
-  
-proc closePassesCached(a: var TPassContextArray) = 
+
+proc closePassesCached(a: var TPassContextArray) =
   var m: PNode = nil
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
       m = gPasses[i].close(a[i], m)
     a[i] = nil                # free the memory here
-  
+
 proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
                       a: var TPassContextArray) =
   for module in items(implicits):
@@ -159,45 +159,45 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
     str.info = gCmdLineInfo
     importStmt.addSon str
     if not processTopLevelStmt(importStmt, a): break
-  
+
 proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
-  var 
+  var
     p: TParsers
     a: TPassContextArray
     s: PLLStream
     fileIdx = module.fileIdx
-  if rd == nil: 
+  if rd == nil:
     openPasses(a, module)
-    if stream == nil: 
+    if stream == nil:
       let filename = fileIdx.toFullPathConsiderDirty
       if module.name.s == "-":
         module.name.s = "stdinfile"
         s = llStreamOpen(stdin)
       else:
         s = llStreamOpen(filename, fmRead)
-      if s == nil: 
+      if s == nil:
         rawMessage(errCannotOpenFile, filename)
         return
     else:
       s = stream
-    while true: 
+    while true:
       openParsers(p, fileIdx, s)
 
       if sfSystemModule notin module.flags:
-        # XXX what about caching? no processing then? what if I change the 
+        # XXX what about caching? no processing then? what if I change the
         # modules to include between compilation runs? we'd need to track that
         # in ROD files. I think we should enable this feature only
         # for the interactive mode.
         processImplicits implicitImports, nkImportStmt, a
         processImplicits implicitIncludes, nkIncludeStmt, a
 
-      while true: 
+      while true:
         var n = parseTopLevelStmt(p)
-        if n.kind == nkEmpty: break 
+        if n.kind == nkEmpty: break
         if not processTopLevelStmt(n, a): break
 
       closeParsers(p)
-      if s.kind != llsStdIn: break 
+      if s.kind != llsStdIn: break
     closePasses(a)
     # id synchronization point for more consistent code generation:
     idSynchronizationPoint(1000)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index f5cabb4bc..689bf23c8 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -9,20 +9,20 @@
 
 # This module implements the renderer of the standard Nim representation.
 
-import 
+import
   lexer, options, idents, strutils, ast, msgs, lists
 
-type 
-  TRenderFlag* = enum 
-    renderNone, renderNoBody, renderNoComments, renderDocComments, 
+type
+  TRenderFlag* = enum
+    renderNone, renderNoBody, renderNoComments, renderDocComments,
     renderNoPragmas, renderIds, renderNoProcDefs
   TRenderFlags* = set[TRenderFlag]
-  TRenderTok*{.final.} = object 
+  TRenderTok*{.final.} = object
     kind*: TTokType
     length*: int16
 
   TRenderTokSeq* = seq[TRenderTok]
-  TSrcGen*{.final.} = object 
+  TSrcGen*{.final.} = object
     indent*: int
     lineLen*: int
     pos*: int              # current position for iteration over the buffer
@@ -41,6 +41,8 @@ proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
 proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string
 proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {})
 proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string)
+
+proc `$`*(n: PNode): string = n.renderTree
 # implementation
 # We render the source code in a two phases: The first
 # determines how long the subtree will likely be, the second
@@ -65,13 +67,13 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string =
   else:
     result = '`' & x & '`'
 
-const 
+const
   IndentWidth = 2
   longIndentWid = 4
   MaxLineLen = 80
   LineCommentColumn = 30
 
-proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = 
+proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
   g.comStack = @[]
   g.tokens = @[]
   g.indent = 0
@@ -83,67 +85,67 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
   g.pendingNL = -1
   g.checkAnon = false
 
-proc addTok(g: var TSrcGen, kind: TTokType, s: string) = 
+proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
   var length = len(g.tokens)
   setLen(g.tokens, length + 1)
   g.tokens[length].kind = kind
   g.tokens[length].length = int16(len(s))
   add(g.buf, s)
 
-proc addPendingNL(g: var TSrcGen) = 
-  if g.pendingNL >= 0: 
+proc addPendingNL(g: var TSrcGen) =
+  if g.pendingNL >= 0:
     addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
     g.lineLen = g.pendingNL
     g.pendingNL = - 1
 
-proc putNL(g: var TSrcGen, indent: int) = 
+proc putNL(g: var TSrcGen, indent: int) =
   if g.pendingNL >= 0: addPendingNL(g)
   else: addTok(g, tkSpaces, "\n")
   g.pendingNL = indent
   g.lineLen = indent
 
-proc putNL(g: var TSrcGen) = 
+proc putNL(g: var TSrcGen) =
   putNL(g, g.indent)
 
-proc optNL(g: var TSrcGen, indent: int) = 
+proc optNL(g: var TSrcGen, indent: int) =
   g.pendingNL = indent
   g.lineLen = indent          # BUGFIX
-  
-proc optNL(g: var TSrcGen) = 
+
+proc optNL(g: var TSrcGen) =
   optNL(g, g.indent)
 
-proc indentNL(g: var TSrcGen) = 
+proc indentNL(g: var TSrcGen) =
   inc(g.indent, IndentWidth)
   g.pendingNL = g.indent
   g.lineLen = g.indent
 
-proc dedent(g: var TSrcGen) = 
+proc dedent(g: var TSrcGen) =
   dec(g.indent, IndentWidth)
   assert(g.indent >= 0)
-  if g.pendingNL > IndentWidth: 
+  if g.pendingNL > IndentWidth:
     dec(g.pendingNL, IndentWidth)
     dec(g.lineLen, IndentWidth)
 
-proc put(g: var TSrcGen, kind: TTokType, s: string) = 
+proc put(g: var TSrcGen, kind: TTokType, s: string) =
   addPendingNL(g)
-  if len(s) > 0: 
+  if len(s) > 0:
     addTok(g, kind, s)
     inc(g.lineLen, len(s))
 
-proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = 
+proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
   # use this for tokens over multiple lines.
   addPendingNL(g)
   addTok(g, kind, s)
   g.lineLen = lineLen
 
-proc toNimChar(c: char): string = 
+proc toNimChar(c: char): string =
   case c
   of '\0': result = "\\0"
   of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2)
   of '\'', '\"', '\\': result = '\\' & c
   else: result = c & ""
-  
-proc makeNimString(s: string): string = 
+
+proc makeNimString(s: string): string =
   result = "\""
   for i in countup(0, len(s)-1): add(result, toNimChar(s[i]))
   add(result, '\"')
@@ -174,7 +176,7 @@ proc putComment(g: var TSrcGen, s: string) =
       add(com, s[i])
       inc(i)
       comIndent = 0
-      while s[i] == ' ': 
+      while s[i] == ' ':
         add(com, s[i])
         inc(i)
         inc(comIndent)
@@ -187,109 +189,109 @@ proc putComment(g: var TSrcGen, s: string) =
       # compute length of the following word:
       var j = i
       while s[j] > ' ': inc(j)
-      if not isCode and (g.lineLen + (j - i) > MaxLineLen): 
+      if not isCode and (g.lineLen + (j - i) > MaxLineLen):
         put(g, tkComment, com)
         optNL(g, ind)
         com = '#' & spaces(comIndent)
-      while s[i] > ' ': 
+      while s[i] > ' ':
         add(com, s[i])
         inc(i)
   put(g, tkComment, com)
   optNL(g)
 
-proc maxLineLength(s: string): int = 
+proc maxLineLength(s: string): int =
   if s.isNil: return 0
   var i = 0
   var lineLen = 0
   while true:
     case s[i]
-    of '\0': 
-      break 
-    of '\x0D': 
+    of '\0':
+      break
+    of '\x0D':
       inc(i)
       if s[i] == '\x0A': inc(i)
       result = max(result, lineLen)
       lineLen = 0
-    of '\x0A': 
+    of '\x0A':
       inc(i)
       result = max(result, lineLen)
       lineLen = 0
-    else: 
+    else:
       inc(lineLen)
       inc(i)
 
-proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = 
+proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
   var i = 0
   var hi = len(s) - 1
   var str = ""
-  while i <= hi: 
+  while i <= hi:
     case s[i]
-    of '\x0D': 
+    of '\x0D':
       put(g, kind, str)
       str = ""
       inc(i)
       if (i <= hi) and (s[i] == '\x0A'): inc(i)
       optNL(g, 0)
-    of '\x0A': 
+    of '\x0A':
       put(g, kind, str)
       str = ""
       inc(i)
       optNL(g, 0)
-    else: 
+    else:
       add(str, s[i])
       inc(i)
   put(g, kind, str)
 
-proc containsNL(s: string): bool = 
-  for i in countup(0, len(s) - 1): 
+proc containsNL(s: string): bool =
+  for i in countup(0, len(s) - 1):
     case s[i]
-    of '\x0D', '\x0A': 
+    of '\x0D', '\x0A':
       return true
-    else: 
+    else:
       discard
   result = false
 
-proc pushCom(g: var TSrcGen, n: PNode) = 
+proc pushCom(g: var TSrcGen, n: PNode) =
   var length = len(g.comStack)
   setLen(g.comStack, length + 1)
   g.comStack[length] = n
 
-proc popAllComs(g: var TSrcGen) = 
+proc popAllComs(g: var TSrcGen) =
   setLen(g.comStack, 0)
 
-proc popCom(g: var TSrcGen) = 
+proc popCom(g: var TSrcGen) =
   setLen(g.comStack, len(g.comStack) - 1)
 
-const 
+const
   Space = " "
 
-proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = 
+proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
   result = false
-  if n.comment != nil: 
+  if n.comment != nil:
     result = (renderNoComments notin g.flags) or
         (renderDocComments in g.flags) and startsWith(n.comment, "##")
-  
-proc gcom(g: var TSrcGen, n: PNode) = 
+
+proc gcom(g: var TSrcGen, n: PNode) =
   assert(n != nil)
-  if shouldRenderComment(g, n): 
+  if shouldRenderComment(g, n):
     if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)-1] != ' '):
-      put(g, tkSpaces, Space) 
+      put(g, tkSpaces, Space)
       # Before long comments we cannot make sure that a newline is generated,
       # because this might be wrong. But it is no problem in practice.
     if (g.pendingNL < 0) and (len(g.buf) > 0) and
-        (g.lineLen < LineCommentColumn): 
+        (g.lineLen < LineCommentColumn):
       var ml = maxLineLength(n.comment)
-      if ml + LineCommentColumn <= MaxLineLen: 
+      if ml + LineCommentColumn <= MaxLineLen:
         put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
     putComment(g, n.comment)  #assert(g.comStack[high(g.comStack)] = n);
-  
-proc gcoms(g: var TSrcGen) = 
+
+proc gcoms(g: var TSrcGen) =
   for i in countup(0, high(g.comStack)): gcom(g, g.comStack[i])
   popAllComs(g)
 
 proc lsub(n: PNode): int
 proc litAux(n: PNode, x: BiggestInt, size: int): string =
-  proc skip(t: PType): PType = 
+  proc skip(t: PType): PType =
     result = t
     while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
                           tyConst, tyMutable}:
@@ -299,20 +301,20 @@ proc litAux(n: PNode, x: BiggestInt, size: int): string =
     # we need a slow linear search because of enums with holes:
     for e in items(enumfields):
       if e.sym.position == x: return e.sym.name.s
-    
+
   if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
   elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
   elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
   else: result = $x
 
-proc ulitAux(n: PNode, x: BiggestInt, size: int): string = 
+proc ulitAux(n: PNode, x: BiggestInt, size: int): string =
   if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
   elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
   elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
   else: result = $x
   # XXX proper unsigned output!
-  
-proc atom(n: PNode): string = 
+
+proc atom(n: PNode): string =
   var f: float32
   case n.kind
   of nkEmpty: result = ""
@@ -335,49 +337,49 @@ proc atom(n: PNode): string =
   of nkFloatLit:
     if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal)
     else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))[] , 8)
-  of nkFloat32Lit: 
-    if n.flags * {nfBase2, nfBase8, nfBase16} == {}: 
+  of nkFloat32Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
       result = $n.floatVal & "\'f32"
-    else: 
+    else:
       f = n.floatVal.float32
       result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
-  of nkFloat64Lit: 
-    if n.flags * {nfBase2, nfBase8, nfBase16} == {}: 
+  of nkFloat64Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
       result = $n.floatVal & "\'f64"
-    else: 
+    else:
       result = litAux(n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64"
   of nkNilLit: result = "nil"
-  of nkType: 
+  of nkType:
     if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
     else: result = "[type node]"
-  else: 
+  else:
     internalError("rnimsyn.atom " & $n.kind)
     result = ""
-  
-proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int = 
+
+proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
   assert(theEnd < 0)
   result = 0
-  for i in countup(start, sonsLen(n) + theEnd): 
+  for i in countup(start, sonsLen(n) + theEnd):
     inc(result, lsub(n.sons[i]))
     inc(result, 2)            # for ``, ``
-  if result > 0: 
+  if result > 0:
     dec(result, 2)            # last does not get a comma!
-  
-proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int = 
+
+proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
   assert(theEnd < 0)
   result = 0
   for i in countup(start, sonsLen(n) + theEnd): inc(result, lsub(n.sons[i]))
-  
-proc lsub(n: PNode): int = 
+
+proc lsub(n: PNode): int =
   # computes the length of a tree
   if isNil(n): return 0
   if n.comment != nil: return MaxLineLen + 1
   case n.kind
   of nkEmpty: result = 0
-  of nkTripleStrLit: 
+  of nkTripleStrLit:
     if containsNL(n.strVal): result = MaxLineLen + 1
     else: result = len(atom(n))
-  of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: 
+  of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
     result = len(atom(n))
   of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
     result = lsub(n.sons[0]) + lcomma(n, 1) + 2
@@ -392,9 +394,10 @@ proc lsub(n: PNode): int =
   of nkArgList: result = lcomma(n)
   of nkTableConstr:
     result = if n.len > 0: lcomma(n) + 2 else: len("{:}")
-  of nkClosedSymChoice, nkOpenSymChoice: 
+  of nkClosedSymChoice, nkOpenSymChoice:
     result = lsons(n) + len("()") + sonsLen(n) - 1
   of nkTupleTy: result = lcomma(n) + len("tuple[]")
+  of nkTupleClassTy: result = len("tuple")
   of nkDotExpr: result = lsons(n) + 1
   of nkBind: result = lsons(n) + len("bind_")
   of nkBindStmt: result = lcomma(n) + len("bind_")
@@ -402,7 +405,7 @@ proc lsub(n: PNode): int =
   of nkCheckedFieldExpr: result = lsub(n.sons[0])
   of nkLambda: result = lsons(n) + len("proc__=_")
   of nkDo: result = lsons(n) + len("do__:_")
-  of nkConstDef, nkIdentDefs: 
+  of nkConstDef, nkIdentDefs:
     result = lcomma(n, 0, - 3)
     var L = sonsLen(n)
     if n.sons[L - 2].kind != nkEmpty: result = result + lsub(n.sons[L - 2]) + 2
@@ -411,7 +414,7 @@ proc lsub(n: PNode): int =
   of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(n)
   of nkChckRange64: result = len("chckRange64") + 2 + lcomma(n)
   of nkChckRange: result = len("chckRange") + 2 + lcomma(n)
-  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: 
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
     result = 2
     if sonsLen(n) >= 1: result = result + lsub(n.sons[0])
     result = result + lcomma(n, 1)
@@ -425,7 +428,7 @@ proc lsub(n: PNode): int =
   of nkRange: result = lsons(n) + 2
   of nkDerefExpr: result = lsub(n.sons[0]) + 2
   of nkAccQuoted: result = lsons(n) + 2
-  of nkIfExpr: 
+  of nkIfExpr:
     result = lsub(n.sons[0].sons[0]) + lsub(n.sons[0].sons[1]) + lsons(n, 1) +
         len("if_:_")
   of nkElifExpr: result = lsons(n) + len("_elif_:_")
@@ -446,13 +449,13 @@ proc lsub(n: PNode): int =
   of nkProcTy: result = lsons(n) + len("proc_")
   of nkIteratorTy: result = lsons(n) + len("iterator_")
   of nkSharedTy: result = lsons(n) + len("shared_")
-  of nkEnumTy: 
+  of nkEnumTy:
     if sonsLen(n) > 0:
       result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
     else:
       result = len("enum")
   of nkEnumFieldDef: result = lsons(n) + 3
-  of nkVarSection, nkLetSection: 
+  of nkVarSection, nkLetSection:
     if sonsLen(n) > 1: result = MaxLineLen + 1
     else: result = lsons(n) + len("var_")
   of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
@@ -469,50 +472,50 @@ proc lsub(n: PNode): int =
   of nkElse: result = lsub(n.sons[0]) + len("else:_")
   of nkFinally: result = lsub(n.sons[0]) + len("finally:_")
   of nkGenericParams: result = lcomma(n) + 2
-  of nkFormalParams: 
+  of nkFormalParams:
     result = lcomma(n, 1) + 2
     if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
-  of nkExceptBranch: 
+  of nkExceptBranch:
     result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
   else: result = MaxLineLen + 1
-  
-proc fits(g: TSrcGen, x: int): bool = 
+
+proc fits(g: TSrcGen, x: int): bool =
   result = x + g.lineLen <= MaxLineLen
 
-type 
-  TSubFlag = enum 
+type
+  TSubFlag = enum
     rfLongMode, rfNoIndent, rfInConstExpr
   TSubFlags = set[TSubFlag]
   TContext = tuple[spacing: int, flags: TSubFlags]
 
-const 
+const
   emptyContext: TContext = (spacing: 0, flags: {})
 
-proc initContext(c: var TContext) = 
+proc initContext(c: var TContext) =
   c.spacing = 0
   c.flags = {}
 
 proc gsub(g: var TSrcGen, n: PNode, c: TContext)
-proc gsub(g: var TSrcGen, n: PNode) = 
+proc gsub(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   gsub(g, n, c)
 
-proc hasCom(n: PNode): bool = 
+proc hasCom(n: PNode): bool =
   result = false
   if n.comment != nil: return true
   case n.kind
   of nkEmpty..nkNilLit: discard
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
+  else:
+    for i in countup(0, sonsLen(n) - 1):
       if hasCom(n.sons[i]): return true
-  
-proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) = 
+
+proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
   put(g, kind, s)
   put(g, tkSpaces, Space)
 
-proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, 
-               theEnd: int = - 1, separator = tkComma) = 
+proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
+               theEnd: int = - 1, separator = tkComma) =
   for i in countup(start, sonsLen(n) + theEnd):
     var c = i < sonsLen(n) + theEnd
     var sublen = lsub(n.sons[i]) + ord(c)
@@ -522,54 +525,54 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
     if c:
       if g.tokens.len > oldLen:
         putWithSpace(g, separator, TokTypeToStr[separator])
-      if hasCom(n.sons[i]): 
+      if hasCom(n.sons[i]):
         gcoms(g)
         optNL(g, ind)
 
-proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, 
-            theEnd: int = - 1) = 
+proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
+            theEnd: int = - 1) =
   var ind: int
-  if rfInConstExpr in c.flags: 
+  if rfInConstExpr in c.flags:
     ind = g.indent + IndentWidth
-  else: 
+  else:
     ind = g.lineLen
     if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
   gcommaAux(g, n, ind, start, theEnd)
 
-proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = 
+proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
   var ind = g.lineLen
   if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
   gcommaAux(g, n, ind, start, theEnd)
 
-proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = 
+proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
   var ind = g.lineLen
   if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
   gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
 
-proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, 
-           theEnd: int = - 1) = 
+proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
+           theEnd: int = - 1) =
   for i in countup(start, sonsLen(n) + theEnd): gsub(g, n.sons[i], c)
 
-proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType, 
-              k: string) = 
+proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
+              k: string) =
   if sonsLen(n) == 0: return # empty var sections are possible
   putWithSpace(g, kind, k)
   gcoms(g)
   indentNL(g)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     optNL(g)
     gsub(g, n.sons[i], c)
     gcoms(g)
   dedent(g)
 
-proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool = 
+proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
   result = n.comment != nil
-  if not result: 
+  if not result:
     # check further
-    for i in countup(start, sonsLen(n) + theEnd): 
-      if (lsub(n.sons[i]) > MaxLineLen): 
+    for i in countup(start, sonsLen(n) + theEnd):
+      if (lsub(n.sons[i]) > MaxLineLen):
         result = true
-        break 
+        break
 
 proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
   if n.kind == nkEmpty: return
@@ -589,33 +592,33 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
     gcoms(g)
     optNL(g)
     if rfLongMode in c.flags: dedent(g)
-  
-proc gif(g: var TSrcGen, n: PNode) = 
+
+proc gif(g: var TSrcGen, n: PNode) =
   var c: TContext
   gsub(g, n.sons[0].sons[0])
   initContext(c)
   putWithSpace(g, tkColon, ":")
-  if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[0].sons[1], c)
   var length = sonsLen(n)
-  for i in countup(1, length - 1): 
+  for i in countup(1, length - 1):
     optNL(g)
     gsub(g, n.sons[i], c)
 
-proc gwhile(g: var TSrcGen, n: PNode) = 
+proc gwhile(g: var TSrcGen, n: PNode) =
   var c: TContext
   putWithSpace(g, tkWhile, "while")
   gsub(g, n.sons[0])
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[1], c)
 
-proc gpattern(g: var TSrcGen, n: PNode) = 
+proc gpattern(g: var TSrcGen, n: PNode) =
   var c: TContext
   put(g, tkCurlyLe, "{")
   initContext(c)
@@ -625,7 +628,7 @@ proc gpattern(g: var TSrcGen, n: PNode) =
   gstmts(g, n, c)
   put(g, tkCurlyRi, "}")
 
-proc gpragmaBlock(g: var TSrcGen, n: PNode) = 
+proc gpragmaBlock(g: var TSrcGen, n: PNode) =
   var c: TContext
   gsub(g, n.sons[0])
   putWithSpace(g, tkColon, ":")
@@ -635,25 +638,25 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) =
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[1], c)
 
-proc gtry(g: var TSrcGen, n: PNode) = 
+proc gtry(g: var TSrcGen, n: PNode) =
   var c: TContext
   put(g, tkTry, "try")
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[0], c)
   gsons(g, n, c, 1)
 
-proc gfor(g: var TSrcGen, n: PNode) = 
+proc gfor(g: var TSrcGen, n: PNode) =
   var c: TContext
   var length = sonsLen(n)
   putWithSpace(g, tkFor, "for")
   initContext(c)
   if longMode(n) or
       (lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen >
-      MaxLineLen): 
+      MaxLineLen):
     incl(c.flags, rfLongMode)
   gcomma(g, n, c, 0, - 3)
   put(g, tkSpaces, Space)
@@ -663,17 +666,17 @@ proc gfor(g: var TSrcGen, n: PNode) =
   gcoms(g)
   gstmts(g, n.sons[length - 1], c)
 
-proc gmacro(g: var TSrcGen, n: PNode) = 
+proc gmacro(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   gsub(g, n.sons[0])
   putWithSpace(g, tkColon, ":")
-  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)
   gsons(g, n, c, 1)
 
-proc gcase(g: var TSrcGen, n: PNode) = 
+proc gcase(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   var length = sonsLen(n)
@@ -684,18 +687,18 @@ proc gcase(g: var TSrcGen, n: PNode) =
   gcoms(g)
   optNL(g)
   gsons(g, n, c, 1, last)
-  if last == - 2: 
+  if last == - 2:
     initContext(c)
     if longMode(n.sons[length - 1]): incl(c.flags, rfLongMode)
     gsub(g, n.sons[length - 1], c)
 
-proc gproc(g: var TSrcGen, n: PNode) = 
+proc gproc(g: var TSrcGen, n: PNode) =
   var c: TContext
   if n.sons[namePos].kind == nkSym:
     put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
   else:
     gsub(g, n.sons[namePos])
-  
+
   if n.sons[patternPos].kind != nkEmpty:
     gpattern(g, n.sons[patternPos])
   let oldCheckAnon = g.checkAnon
@@ -732,7 +735,7 @@ proc gTypeClassTy(g: var TSrcGen, n: PNode) =
   gstmts(g, n[3], c)
   dedent(g)
 
-proc gblock(g: var TSrcGen, n: PNode) = 
+proc gblock(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   if n.sons[0].kind != nkEmpty:
@@ -741,7 +744,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
   else:
     put(g, tkBlock, "block")
   putWithSpace(g, tkColon, ":")
-  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)
   # XXX I don't get why this is needed here! gstmts should already handle this!
@@ -749,17 +752,17 @@ proc gblock(g: var TSrcGen, n: PNode) =
   gstmts(g, n.sons[1], c)
   dedent(g)
 
-proc gstaticStmt(g: var TSrcGen, n: PNode) = 
+proc gstaticStmt(g: var TSrcGen, n: PNode) =
   var c: TContext
   putWithSpace(g, tkStatic, "static")
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[0], c)
 
-proc gasm(g: var TSrcGen, n: PNode) = 
+proc gasm(g: var TSrcGen, n: PNode) =
   putWithSpace(g, tkAsm, "asm")
   gsub(g, n.sons[0])
   gcoms(g)
@@ -769,16 +772,16 @@ proc gident(g: var TSrcGen, n: PNode) =
   if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
   var t: TTokType
   var s = atom(n)
-  if (s[0] in lexer.SymChars): 
-    if (n.kind == nkIdent): 
+  if (s[0] in lexer.SymChars):
+    if (n.kind == nkIdent):
       if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
-          (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): 
+          (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
         t = tkSymbol
-      else: 
+      else:
         t = TTokType(n.ident.id + ord(tkSymbol))
-    else: 
+    else:
       t = tkSymbol
-  else: 
+  else:
     t = tkOpr
   put(g, t, s)
   if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
@@ -788,12 +791,12 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
     put(g, tkParLe, "(")
     gsemicolon(g, params, 1)
     put(g, tkParRi, ")")
-  
-  if params.sons[0].kind != nkEmpty: 
+
+  if params.sons[0].kind != nkEmpty:
     putWithSpace(g, tkOpr, "->")
     gsub(g, params.sons[0])
 
-proc gsub(g: var TSrcGen, n: PNode, c: TContext) = 
+proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   if isNil(n): return
   var
     a: TContext
@@ -826,14 +829,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
-  of nkCallStrLit: 
+  of nkCallStrLit:
     gsub(g, n.sons[0])
-    if n.sons[1].kind == nkRStrLit: 
+    if n.sons[1].kind == nkRStrLit:
       put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
-    else: 
+    else:
       gsub(g, n.sons[1])
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1])
-  of nkCast: 
+  of nkCast:
     put(g, tkCast, "cast")
     put(g, tkBracketLe, "[")
     gsub(g, n.sons[0])
@@ -841,7 +844,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gsub(g, n.sons[1])
     put(g, tkParRi, ")")
-  of nkAddr: 
+  of nkAddr:
     put(g, tkAddr, "addr")
     put(g, tkParLe, "(")
     gsub(g, n.sons[0])
@@ -850,7 +853,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkStatic, "static")
     put(g, tkSpaces, Space)
     gsub(g, n.sons[0])
-  of nkBracketExpr: 
+  of nkBracketExpr:
     gsub(g, n.sons[0])
     put(g, tkBracketLe, "[")
     gcomma(g, n, 1)
@@ -860,41 +863,41 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkCurlyLe, "{")
     gcomma(g, n, 1)
     put(g, tkCurlyRi, "}")
-  of nkPragmaExpr: 
+  of nkPragmaExpr:
     gsub(g, n.sons[0])
     gcomma(g, n, 1)
-  of nkCommand: 
+  of nkCommand:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     gcomma(g, n, 1)
-  of nkExprEqExpr, nkAsgn, nkFastAsgn: 
+  of nkExprEqExpr, nkAsgn, nkFastAsgn:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, n.sons[1])
-  of nkChckRangeF: 
+  of nkChckRangeF:
     put(g, tkSymbol, "chckRangeF")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkChckRange64: 
+  of nkChckRange64:
     put(g, tkSymbol, "chckRange64")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkChckRange: 
+  of nkChckRange:
     put(g, tkSymbol, "chckRange")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: 
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
     if sonsLen(n) >= 1: gsub(g, n.sons[0])
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
   of nkClosedSymChoice, nkOpenSymChoice:
     put(g, tkParLe, "(")
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       if i > 0: put(g, tkOpr, "|")
       if n.sons[i].kind == nkSym:
         let s = n[i].sym
@@ -905,11 +908,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       else:
         gsub(g, n.sons[i], c)
     put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
-  of nkPar, nkClosure: 
+  of nkPar, nkClosure:
     put(g, tkParLe, "(")
     gcomma(g, n, c)
     put(g, tkParRi, ")")
-  of nkCurly: 
+  of nkCurly:
     put(g, tkCurlyLe, "{")
     gcomma(g, n, c)
     put(g, tkCurlyRi, "}")
@@ -924,14 +927,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkBracketLe, "[")
     gcomma(g, n, c)
     put(g, tkBracketRi, "]")
-  of nkDotExpr: 
+  of nkDotExpr:
     gsub(g, n.sons[0])
     put(g, tkDot, ".")
     gsub(g, n.sons[1])
-  of nkBind: 
+  of nkBind:
     putWithSpace(g, tkBind, "bind")
     gsub(g, n.sons[0])
-  of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: 
+  of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
     gsub(g, n.sons[0])
   of nkLambda:
     putWithSpace(g, tkProc, "proc")
@@ -949,34 +952,34 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkConstDef, nkIdentDefs:
     gcomma(g, n, 0, -3)
     var L = sonsLen(n)
-    if L >= 2 and n.sons[L - 2].kind != nkEmpty: 
+    if L >= 2 and n.sons[L - 2].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
       gsub(g, n.sons[L - 2])
-    if L >= 1 and n.sons[L - 1].kind != nkEmpty: 
+    if L >= 1 and n.sons[L - 1].kind != nkEmpty:
       put(g, tkSpaces, Space)
       putWithSpace(g, tkEquals, "=")
       gsub(g, n.sons[L - 1], c)
-  of nkVarTuple: 
+  of nkVarTuple:
     put(g, tkParLe, "(")
     gcomma(g, n, 0, -3)
     put(g, tkParRi, ")")
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, lastSon(n), c)
-  of nkExprColonExpr: 
+  of nkExprColonExpr:
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[1])
-  of nkInfix: 
+  of nkInfix:
     gsub(g, n.sons[1])
     put(g, tkSpaces, Space)
     gsub(g, n.sons[0])        # binary operator
-    if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1): 
+    if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1):
       optNL(g, g.indent + longIndentWid)
-    else: 
+    else:
       put(g, tkSpaces, Space)
     gsub(g, n.sons[2])
-  of nkPrefix: 
+  of nkPrefix:
     gsub(g, n.sons[0])
     if n.len > 1:
       put(g, tkSpaces, Space)
@@ -986,10 +989,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         put(g, tkParRi, ")")
       else:
         gsub(g, n.sons[1])
-  of nkPostfix: 
+  of nkPostfix:
     gsub(g, n.sons[1])
     gsub(g, n.sons[0])
-  of nkRange: 
+  of nkRange:
     gsub(g, n.sons[0])
     put(g, tkDotDot, "..")
     gsub(g, n.sons[1])
@@ -1003,43 +1006,43 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       put(g, tkSpaces, Space)
       gsub(g, n.sons[i])
     put(g, tkAccent, "`")
-  of nkIfExpr: 
+  of nkIfExpr:
     putWithSpace(g, tkIf, "if")
     gsub(g, n.sons[0].sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[0].sons[1])
     gsons(g, n, emptyContext, 1)
-  of nkElifExpr: 
+  of nkElifExpr:
     putWithSpace(g, tkElif, " elif")
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[1])
-  of nkElseExpr: 
+  of nkElseExpr:
     put(g, tkElse, " else")
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[0])
   of nkTypeOfExpr:
     putWithSpace(g, tkType, "type")
     if n.len > 0: gsub(g, n.sons[0])
-  of nkRefTy: 
+  of nkRefTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkRef, "ref")
       gsub(g, n.sons[0])
     else:
       put(g, tkRef, "ref")
-  of nkPtrTy: 
+  of nkPtrTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkPtr, "ptr")
       gsub(g, n.sons[0])
     else:
       put(g, tkPtr, "ptr")
-  of nkVarTy: 
+  of nkVarTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkVar, "var")
       gsub(g, n.sons[0])
     else:
       put(g, tkVar, "var")
-  of nkDistinctTy: 
+  of nkDistinctTy:
     if n.len > 0:
       putWithSpace(g, tkDistinct, "distinct")
       gsub(g, n.sons[0])
@@ -1051,14 +1054,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         gcomma(g, n[1])
     else:
       put(g, tkDistinct, "distinct")
-  of nkTypeDef: 
+  of nkTypeDef:
     gsub(g, n.sons[0])
     gsub(g, n.sons[1])
     put(g, tkSpaces, Space)
-    if n.sons[2].kind != nkEmpty: 
+    if n.sons[2].kind != nkEmpty:
       putWithSpace(g, tkEquals, "=")
       gsub(g, n.sons[2])
-  of nkObjectTy: 
+  of nkObjectTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkObject, "object")
       gsub(g, n.sons[0])
@@ -1067,18 +1070,18 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       gsub(g, n.sons[2])
     else:
       put(g, tkObject, "object")
-  of nkRecList: 
+  of nkRecList:
     indentNL(g)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       optNL(g)
       gsub(g, n.sons[i], c)
       gcoms(g)
     dedent(g)
     putNL(g)
-  of nkOfInherit: 
+  of nkOfInherit:
     putWithSpace(g, tkOf, "of")
     gsub(g, n.sons[0])
-  of nkProcTy: 
+  of nkProcTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkProc, "proc")
       gsub(g, n.sons[0])
@@ -1097,7 +1100,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkBracketLe, "[")
     if n.len > 0:
       gsub(g, n.sons[0])
-    put(g, tkBracketRi, "]")    
+    put(g, tkBracketRi, "]")
   of nkEnumTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkEnum, "enum")
@@ -1109,16 +1112,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       dedent(g)
     else:
       put(g, tkEnum, "enum")
-  of nkEnumFieldDef: 
+  of nkEnumFieldDef:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, n.sons[1])
   of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
-  of nkIfStmt: 
+  of nkIfStmt:
     putWithSpace(g, tkIf, "if")
     gif(g, n)
-  of nkWhen, nkRecWhen: 
+  of nkWhen, nkRecWhen:
     putWithSpace(g, tkWhen, "when")
     gif(g, n)
   of nkWhileStmt: gwhile(g, n)
@@ -1129,27 +1132,27 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkBlockStmt, nkBlockExpr: gblock(g, n)
   of nkStaticStmt: gstaticStmt(g, n)
   of nkAsmStmt: gasm(g, n)
-  of nkProcDef: 
+  of nkProcDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
     gproc(g, n)
   of nkConverterDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
     gproc(g, n)
-  of nkMethodDef: 
+  of nkMethodDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
     gproc(g, n)
-  of nkIteratorDef: 
+  of nkIteratorDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
     gproc(g, n)
-  of nkMacroDef: 
+  of nkMacroDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
     gproc(g, n)
-  of nkTemplateDef: 
+  of nkTemplateDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
     gproc(g, n)
-  of nkTypeSection: 
+  of nkTypeSection:
     gsection(g, n, emptyContext, tkType, "type")
-  of nkConstSection: 
+  of nkConstSection:
     initContext(a)
     incl(a.flags, rfInConstExpr)
     gsection(g, n, a, tkConst, "const")
@@ -1158,32 +1161,32 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     if L == 0: return
     if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
     else: putWithSpace(g, tkLet, "let")
-    if L > 1: 
+    if L > 1:
       gcoms(g)
       indentNL(g)
-      for i in countup(0, L - 1): 
+      for i in countup(0, L - 1):
         optNL(g)
         gsub(g, n.sons[i])
         gcoms(g)
       dedent(g)
-    else: 
+    else:
       gsub(g, n.sons[0])
-  of nkReturnStmt: 
+  of nkReturnStmt:
     putWithSpace(g, tkReturn, "return")
     gsub(g, n.sons[0])
-  of nkRaiseStmt: 
+  of nkRaiseStmt:
     putWithSpace(g, tkRaise, "raise")
     gsub(g, n.sons[0])
-  of nkYieldStmt: 
+  of nkYieldStmt:
     putWithSpace(g, tkYield, "yield")
     gsub(g, n.sons[0])
-  of nkDiscardStmt: 
+  of nkDiscardStmt:
     putWithSpace(g, tkDiscard, "discard")
     gsub(g, n.sons[0])
-  of nkBreakStmt: 
+  of nkBreakStmt:
     putWithSpace(g, tkBreak, "break")
     gsub(g, n.sons[0])
-  of nkContinueStmt: 
+  of nkContinueStmt:
     putWithSpace(g, tkContinue, "continue")
     gsub(g, n.sons[0])
   of nkPragma:
@@ -1218,24 +1221,24 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gcommaAux(g, n, g.indent, 1)
     gcoms(g)
     putNL(g)
-  of nkFromStmt: 
+  of nkFromStmt:
     putWithSpace(g, tkFrom, "from")
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkImport, "import")
     gcomma(g, n, emptyContext, 1)
     putNL(g)
-  of nkIncludeStmt: 
+  of nkIncludeStmt:
     putWithSpace(g, tkInclude, "include")
     gcoms(g)
     indentNL(g)
     gcommaAux(g, n, g.indent)
     dedent(g)
     putNL(g)
-  of nkCommentStmt: 
+  of nkCommentStmt:
     gcoms(g)
     optNL(g)
-  of nkOfBranch: 
+  of nkOfBranch:
     optNL(g)
     putWithSpace(g, tkOf, "of")
     gcomma(g, n, c, 0, - 2)
@@ -1247,55 +1250,56 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkSpaces, Space)
     putWithSpace(g, tkAs, "as")
     gsub(g, n.sons[1])
-  of nkBindStmt: 
+  of nkBindStmt:
     putWithSpace(g, tkBind, "bind")
     gcomma(g, n, c)
   of nkMixinStmt:
     putWithSpace(g, tkMixin, "mixin")
     gcomma(g, n, c)
-  of nkElifBranch: 
+  of nkElifBranch:
     optNL(g)
     putWithSpace(g, tkElif, "elif")
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[1], c)
-  of nkElse: 
+  of nkElse:
     optNL(g)
     put(g, tkElse, "else")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[0], c)
-  of nkFinally: 
+  of nkFinally:
     optNL(g)
     put(g, tkFinally, "finally")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[0], c)
-  of nkExceptBranch: 
+  of nkExceptBranch:
     optNL(g)
     putWithSpace(g, tkExcept, "except")
     gcomma(g, n, 0, - 2)
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, lastSon(n), c)
-  of nkGenericParams: 
+  of nkGenericParams:
     put(g, tkBracketLe, "[")
     gcomma(g, n)
     put(g, tkBracketRi, "]")
-  of nkFormalParams: 
+  of nkFormalParams:
     put(g, tkParLe, "(")
     gsemicolon(g, n, 1)
     put(g, tkParRi, ")")
-    if n.sons[0].kind != nkEmpty: 
+    if n.sons[0].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
       gsub(g, n.sons[0])
-  of nkTupleTy: 
+  of nkTupleTy:
+    put(g, tkTuple, "tuple")
+    put(g, tkBracketLe, "[")
+    gcomma(g, n)
+    put(g, tkBracketRi, "]")
+  of nkTupleClassTy:
     put(g, tkTuple, "tuple")
-    if sonsLen(n) > 0:
-      put(g, tkBracketLe, "[")
-      gcomma(g, n)
-      put(g, tkBracketRi, "]")
   of nkMetaNode_Obsolete:
     put(g, tkParLe, "(META|")
     gsub(g, n.sons[0])
@@ -1307,17 +1311,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsons(g, n, c)
   of nkTypeClassTy:
     gTypeClassTy(g, n)
-  else: 
-    #nkNone, nkExplicitTypeListCall: 
+  else:
+    #nkNone, nkExplicitTypeListCall:
     internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
 
-proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = 
+proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
   var g: TSrcGen
   initSrcGen(g, renderFlags)
   gsub(g, n)
   result = g.buf
 
-proc renderModule(n: PNode, filename: string, 
+proc renderModule(n: PNode, filename: string,
                   renderFlags: TRenderFlags = {}) =
   var
     f: File
@@ -1337,18 +1341,18 @@ proc renderModule(n: PNode, filename: string,
     write(f, g.buf)
     close(f)
   else:
-    rawMessage(errCannotOpenFile, filename)    
+    rawMessage(errCannotOpenFile, filename)
 
-proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = 
+proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
   initSrcGen(r, renderFlags)
   gsub(r, n)
 
-proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) = 
-  if r.idx < len(r.tokens): 
+proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
+  if r.idx < len(r.tokens):
     kind = r.tokens[r.idx].kind
     var length = r.tokens[r.idx].length.int
     literal = substr(r.buf, r.pos, r.pos + length - 1)
     inc(r.pos, length)
     inc(r.idx)
-  else: 
+  else:
     kind = tkEof
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 718a87232..4309661f3 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -41,48 +41,55 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
                        best, alt: var TCandidate,
                        errors: var CandidateErrors) =
   var o: TOverloadIter
-  var sym = initOverloadIter(o, c, headSymbol)
+  # thanks to the lazy semchecking for operands, we need to iterate over the
+  # symbol table *before* any call to 'initCandidate' which might invoke
+  # semExpr which might modify the symbol table in cases like
+  # 'init(a, 1, (var b = new(Type2); b))'.
+  var symx = initOverloadIter(o, c, headSymbol)
   let symScope = o.lastOverloadScope
 
-  var z: TCandidate
+  var syms: seq[tuple[a: PSym, b: int]] = @[]
+  while symx != nil:
+    if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
+    symx = nextOverloadIter(o, c, headSymbol)
+  if syms.len == 0: return
 
-  if sym == nil: return
-  initCandidate(c, best, sym, initialBinding, symScope)
-  initCandidate(c, alt, sym, initialBinding, symScope)
+  var z: TCandidate
+  initCandidate(c, best, syms[0][0], initialBinding, symScope)
+  initCandidate(c, alt, syms[0][0], initialBinding, symScope)
   best.state = csNoMatch
 
-  while sym != nil:
-    if sym.kind in filter:
-      determineType(c, sym)
-      initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
-      z.calleeSym = sym
-
-      #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
-      #  gDebug = true
-      matches(c, n, orig, z)
-      if errors != nil:
-        errors.safeAdd(sym)
-        if z.errors != nil:
-          for err in z.errors:
-            errors.add(err)
-      if z.state == csMatch:
-        # little hack so that iterators are preferred over everything else:
-        if sym.kind in skIterators: inc(z.exactMatches, 200)
-        case best.state
-        of csEmpty, csNoMatch: best = z
-        of csMatch:
-          var cmp = cmpCandidates(best, z)
-          if cmp < 0: best = z   # x is better than the best so far
-          elif cmp == 0: alt = z # x is as good as the best so far
-          else: discard
-        #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
-        #  echo "Matches ", n.info, " ", typeToString(sym.typ)
-        #  debug sym
-        #  writeMatches(z)
-        #  for i in 1 .. <len(z.call):
-        #    z.call[i].typ.debug
-        #  quit 1
-    sym = nextOverloadIter(o, c, headSymbol)
+  for i in 0 .. <syms.len:
+    let sym = syms[i][0]
+    determineType(c, sym)
+    initCandidate(c, z, sym, initialBinding, syms[i][1])
+    z.calleeSym = sym
+
+    #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
+    #  gDebug = true
+    matches(c, n, orig, z)
+    if errors != nil:
+      errors.safeAdd(sym)
+      if z.errors != nil:
+        for err in z.errors:
+          errors.add(err)
+    if z.state == csMatch:
+      # little hack so that iterators are preferred over everything else:
+      if sym.kind in skIterators: inc(z.exactMatches, 200)
+      case best.state
+      of csEmpty, csNoMatch: best = z
+      of csMatch:
+        var cmp = cmpCandidates(best, z)
+        if cmp < 0: best = z   # x is better than the best so far
+        elif cmp == 0: alt = z # x is as good as the best so far
+        else: discard
+      #if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
+      #  echo "Matches ", n.info, " ", typeToString(sym.typ)
+      #  debug sym
+      #  writeMatches(z)
+      #  for i in 1 .. <len(z.call):
+      #    z.call[i].typ.debug
+      #  quit 1
 
 proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   # Gives a detailed error message; this is separated from semOverloadedCall,
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 89469ae50..d236687c3 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -24,7 +24,7 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   # same as 'semExprWithType' but doesn't check for proc vars
   result = semExpr(c, n, flags + {efOperand})
-  if result.kind == nkEmpty: 
+  if result.kind == nkEmpty:
     # do not produce another redundant error message:
     #raiseRecoverableError("")
     result = errorNode(c, n)
@@ -34,19 +34,19 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   elif efWantStmt in flags:
     result.typ = newTypeS(tyEmpty, c)
   else:
-    localError(n.info, errExprXHasNoType, 
+    localError(n.info, errExprXHasNoType,
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
 
 proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   result = semExpr(c, n, flags+{efWantValue})
-  if result.isNil or result.kind == nkEmpty: 
+  if result.isNil or result.kind == nkEmpty:
     # do not produce another redundant error message:
     #raiseRecoverableError("")
     result = errorNode(c, n)
   if result.typ == nil or result.typ == enforceVoidContext:
     # we cannot check for 'void' in macros ...
-    localError(n.info, errExprXHasNoType, 
+    localError(n.info, errExprXHasNoType,
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
   else:
@@ -61,7 +61,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     # do not produce another redundant error message:
     result = errorNode(c, n)
   if result.typ == nil:
-    localError(n.info, errExprXHasNoType, 
+    localError(n.info, errExprXHasNoType,
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
   else:
@@ -70,19 +70,19 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
 
 proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   result = symChoice(c, n, s, scClosed)
-  
+
 proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
   result = copyTree(s.ast)
   result.typ = s.typ
   result.info = n.info
-  
-proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
+
+proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   case s.kind
   of skConst:
     markUsed(n.info, s)
     styleCheckUse(n.info, s)
     case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
-    of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, 
+    of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
         tyTuple, tySet, tyUInt..tyUInt64:
       if s.magic == mNone: result = inlineConst(n, s)
       else: result = newSymNode(s, n.info)
@@ -167,7 +167,7 @@ proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
     else:
       convOK
 
-const 
+const
   IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
 
 proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
@@ -201,10 +201,10 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
 
 proc isCastable(dst, src: PType): bool =
   ## Checks whether the source type can be casted to the destination type.
-  ## Casting is very unrestrictive; casts are allowed as long as 
+  ## Casting is very unrestrictive; casts are allowed as long as
   ## castDest.size >= src.size, and typeAllowed(dst, skParam)
   #const
-  #  castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString, 
+  #  castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
   #                       tySequence, tyPointer, tyNil, tyOpenArray,
   #                       tyProc, tySet, tyEnum, tyBool, tyChar}
   if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
@@ -213,7 +213,7 @@ proc isCastable(dst, src: PType): bool =
 
   dstSize = computeSize(dst)
   srcSize = computeSize(src)
-  if dstSize < 0: 
+  if dstSize < 0:
     result = false
   elif srcSize < 0:
     result = false
@@ -225,7 +225,7 @@ proc isCastable(dst, src: PType): bool =
         (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
   if result and src.kind == tyNil:
     result = dst.size <= platform.ptrSize
-  
+
 proc isSymChoice(n: PNode): bool {.inline.} =
   result = n.kind in nkSymChoices
 
@@ -249,7 +249,7 @@ proc semConv(c: PContext, n: PNode): PNode =
   maybeLiftType(targetType, c, n[0].info)
   result.addSon copyTree(n.sons[0])
   var op = semExprWithType(c, n.sons[1])
-  
+
   if targetType.isMetaType:
     let final = inferWithMetatype(c, targetType, op, true)
     result.addSon final
@@ -258,7 +258,7 @@ proc semConv(c: PContext, n: PNode): PNode =
 
   result.typ = targetType
   addSon(result, op)
-  
+
   if not isSymChoice(op):
     let status = checkConvertible(c, result.typ, op.typ)
     case status
@@ -286,7 +286,7 @@ proc semConv(c: PContext, n: PNode): PNode =
         return it
     localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
 
-proc semCast(c: PContext, n: PNode): PNode = 
+proc semCast(c: PContext, n: PNode): PNode =
   ## Semantically analyze a casting ("cast[type](param)")
   if optSafeCode in gGlobalOptions: localError(n.info, errCastNotInSafeMode)
   #incl(c.p.owner.flags, sfSideEffect)
@@ -295,25 +295,25 @@ proc semCast(c: PContext, n: PNode): PNode =
   result.typ = semTypeNode(c, n.sons[0], nil)
   addSon(result, copyTree(n.sons[0]))
   addSon(result, semExprWithType(c, n.sons[1]))
-  if not isCastable(result.typ, result.sons[1].typ): 
-    localError(result.info, errExprCannotBeCastedToX, 
+  if not isCastable(result.typ, result.sons[1].typ):
+    localError(result.info, errExprCannotBeCastedToX,
                typeToString(result.typ))
 
-proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = 
-  const 
+proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
+  const
     opToStr: array[mLow..mHigh, string] = ["low", "high"]
-  if sonsLen(n) != 2: 
+  if sonsLen(n) != 2:
     localError(n.info, errXExpectsTypeOrValue, opToStr[m])
-  else: 
+  else:
     n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
     var typ = skipTypes(n.sons[1].typ, abstractVarRange +
                                        {tyTypeDesc, tyFieldAccessor})
     case typ.kind
-    of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: 
+    of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
       n.typ = getSysType(tyInt)
-    of tyArrayConstr, tyArray: 
+    of tyArrayConstr, tyArray:
       n.typ = typ.sons[0] # indextype
-    of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: 
+    of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
       # do not skip the range!
       n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor})
     of tyGenericParam:
@@ -334,8 +334,8 @@ proc semSizeof(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyInt)
   result = n
 
-proc semOf(c: PContext, n: PNode): PNode = 
-  if sonsLen(n) == 3: 
+proc semOf(c: PContext, n: PNode): PNode =
+  if sonsLen(n) == 3:
     n.sons[1] = semExprWithType(c, n.sons[1])
     n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType})
     #restoreOldStyleType(n.sons[1])
@@ -373,7 +373,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
   internalAssert n.sonsLen == 3 and
     n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
-  
+
   let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor})
 
   if n[2].kind in {nkStrLit..nkTripleStrLit}:
@@ -381,7 +381,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
     of "closure":
       let t = skipTypes(t1, abstractRange)
       result = newIntNode(nkIntLit, ord(t.kind == tyProc and
-                                        t.callConv == ccClosure and 
+                                        t.callConv == ccClosure and
                                         tfIterator notin t.flags))
     else: discard
   else:
@@ -400,7 +400,7 @@ proc semIs(c: PContext, n: PNode): PNode =
 
   result = n
   n.typ = getSysType(tyBool)
- 
+
   n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
   if n[2].kind notin {nkStrLit..nkTripleStrLit}:
     let t2 = semTypeNode(c, n[2], nil)
@@ -420,7 +420,7 @@ proc semOpAux(c: PContext, n: PNode) =
   const flags = {efDetermineType}
   for i in countup(1, n.sonsLen-1):
     var a = n.sons[i]
-    if a.kind == nkExprEqExpr and sonsLen(a) == 2: 
+    if a.kind == nkExprEqExpr and sonsLen(a) == 2:
       var info = a.sons[0].info
       a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
       a.sons[1] = semExprWithType(c, a.sons[1], flags)
@@ -428,7 +428,7 @@ proc semOpAux(c: PContext, n: PNode) =
     else:
       n.sons[i] = semExprWithType(c, a, flags)
 
-proc overloadedCallOpr(c: PContext, n: PNode): PNode = 
+proc overloadedCallOpr(c: PContext, n: PNode): PNode =
   # quick check if there is *any* () operator overloaded:
   var par = getIdent("()")
   if searchInScopes(c, par) == nil:
@@ -457,7 +457,7 @@ proc changeType(n: PNode, newType: PType, check: bool) =
           return
         if tup.n != nil:
           var f = getSymFromList(newType.n, m.sym.name)
-          if f == nil: 
+          if f == nil:
             internalError(m.info, "changeType(): invalid identifier")
             return
           changeType(n.sons[i].sons[1], f.typ, check)
@@ -481,10 +481,10 @@ proc changeType(n: PNode, newType: PType, check: bool) =
   else: discard
   n.typ = newType
 
-proc arrayConstrType(c: PContext, n: PNode): PType = 
+proc arrayConstrType(c: PContext, n: PNode): PType =
   var typ = newTypeS(tyArrayConstr, c)
   rawAddSon(typ, nil)     # index type
-  if sonsLen(n) == 0: 
+  if sonsLen(n) == 0:
     rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
   else:
     var x = n.sons[0]
@@ -494,35 +494,35 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
   typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
   result = typ
 
-proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = newNodeI(nkBracket, n.info)
   result.typ = newTypeS(tyArrayConstr, c)
   rawAddSon(result.typ, nil)     # index type
-  if sonsLen(n) == 0: 
+  if sonsLen(n) == 0:
     rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
   else:
     var x = n.sons[0]
     var lastIndex: BiggestInt = 0
     var indexType = getSysType(tyInt)
-    if x.kind == nkExprColonExpr and sonsLen(x) == 2: 
+    if x.kind == nkExprColonExpr and sonsLen(x) == 2:
       var idx = semConstExpr(c, x.sons[0])
       lastIndex = getOrdValue(idx)
       indexType = idx.typ
       x = x.sons[1]
-    
+
     let yy = semExprWithType(c, x)
     var typ = yy.typ
     addSon(result, yy)
     #var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       x = n.sons[i]
-      if x.kind == nkExprColonExpr and sonsLen(x) == 2: 
+      if x.kind == nkExprColonExpr and sonsLen(x) == 2:
         var idx = semConstExpr(c, x.sons[0])
         idx = fitNode(c, indexType, idx)
         if lastIndex+1 != getOrdValue(idx):
           localError(x.info, errInvalidOrderInArrayConstructor)
         x = x.sons[1]
-      
+
       let xx = semExprWithType(c, x, flags*{efAllowDestructor})
       result.add xx
       typ = commonType(typ, xx.typ)
@@ -534,21 +534,21 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result.sons[i] = fitNode(c, typ, result.sons[i])
   result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
 
-proc fixAbstractType(c: PContext, n: PNode) = 
+proc fixAbstractType(c: PContext, n: PNode) =
   # XXX finally rewrite that crap!
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var it = n.sons[i]
     case it.kind
     of nkHiddenStdConv, nkHiddenSubConv:
       if it.sons[1].kind == nkBracket:
         it.sons[1].typ = arrayConstrType(c, it.sons[1])
         #it.sons[1] = semArrayConstr(c, it.sons[1])
-      if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: 
+      if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
         #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
         #  debug(n)
-        
+
         var s = skipTypes(it.sons[1].typ, abstractVar)
-        if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty: 
+        if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
           s = copyType(s, getCurrOwner(), false)
           skipTypes(s, abstractVar).sons[1] = elemType(
               skipTypes(it.typ, abstractVar))
@@ -558,32 +558,32 @@ proc fixAbstractType(c: PContext, n: PNode) =
           skipTypes(s, abstractVar).sons[0] = elemType(
               skipTypes(it.typ, abstractVar))
           it.sons[1].typ = s
-          
+
       elif skipTypes(it.sons[1].typ, abstractVar).kind in
-          {tyNil, tyArrayConstr, tyTuple, tySet}: 
+          {tyNil, tyArrayConstr, tyTuple, tySet}:
         var s = skipTypes(it.typ, abstractVar)
         if s.kind != tyExpr:
           changeType(it.sons[1], s, check=true)
         n.sons[i] = it.sons[1]
-    of nkBracket: 
+    of nkBracket:
       # an implicitly constructed array (passed to an open array):
       n.sons[i] = semArrayConstr(c, it, {})
-    else: 
+    else:
       discard
-      #if (it.typ == nil): 
-      #  InternalError(it.info, "fixAbstractType: " & renderTree(it))  
-  
-proc skipObjConv(n: PNode): PNode = 
+      #if (it.typ == nil):
+      #  InternalError(it.info, "fixAbstractType: " & renderTree(it))
+
+proc skipObjConv(n: PNode): PNode =
   case n.kind
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
-    if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}:
       result = n.sons[1]
-    else: 
+    else:
       result = n
   of nkObjUpConv, nkObjDownConv: result = n.sons[0]
   else: result = n
 
-proc isAssignable(c: PContext, n: PNode): TAssignableResult = 
+proc isAssignable(c: PContext, n: PNode): TAssignableResult =
   result = parampatterns.isAssignable(c.p.owner, n)
 
 proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
@@ -597,49 +597,49 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
     if isAssignable(c, n) notin {arLValue, arLocalLValue}:
       localError(n.info, errVarForOutParamNeeded)
 
-proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = 
+proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
   result = n
   case n.kind
   of nkSym:
     # n.sym.typ can be nil in 'check' mode ...
     if n.sym.typ != nil and
-        skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: 
+        skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
       incl(n.sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
-  of nkDotExpr: 
+  of nkDotExpr:
     checkSonsLen(n, 2)
-    if n.sons[1].kind != nkSym: 
+    if n.sons[1].kind != nkSym:
       internalError(n.info, "analyseIfAddressTaken")
       return
-    if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: 
+    if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
       incl(n.sons[1].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
-  of nkBracketExpr: 
+  of nkBracketExpr:
     checkMinSonsLen(n, 1)
-    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar: 
+    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar:
       if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
-  else: 
+  else:
     result = newHiddenAddrTaken(c, n)
-  
-proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = 
+
+proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
   checkMinSonsLen(n, 1)
-  const 
-    FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, 
-      mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, 
+  const
+    FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
+      mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
       mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
-  
+
   # get the real type of the callee
   # it may be a proc var with a generic alias type, so we skip over them
   var t = n.sons[0].typ.skipTypes({tyGenericInst})
 
-  if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams: 
+  if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams:
     # BUGFIX: check for L-Value still needs to be done for the arguments!
     # note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       if i < sonsLen(t) and t.sons[i] != nil and
-          skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: 
-        if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}: 
+          skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
+        if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}:
           if n.sons[i].kind != nkHiddenAddr:
             localError(n.sons[i].info, errVarForOutParamNeeded)
     return
@@ -653,14 +653,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
         skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
       if n.sons[i].kind != nkHiddenAddr:
         n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
-  
+
 include semmagic
 
 proc evalAtCompileTime(c: PContext, n: PNode): PNode =
   result = n
   if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
   var callee = n.sons[0].sym
-  
+
   # constant folding that is necessary for correctness of semantic pass:
   if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil:
     var call = newNodeIT(nkCall, n.info, n.typ)
@@ -678,7 +678,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
       if result.isNil: result = n
       else: return result
     result.typ = semfold.getIntervalType(callee.magic, call)
-  
+
   block maybeLabelAsStatic:
     # XXX: temporary work-around needed for tlateboundstatic.
     # This is certainly not correct, but it will get the job
@@ -696,15 +696,15 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
   # optimization pass: not necessary for correctness of the semantic pass
   if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
      {sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
-    if sfCompileTime notin callee.flags and 
+    if sfCompileTime notin callee.flags and
         optImplicitStatic notin gOptions: return
 
     if callee.magic notin ctfeWhitelist: return
     if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
       return
-    
+
     if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
-    
+
     var call = newNodeIT(nkCall, n.info, n.typ)
     call.add(n.sons[0])
     for i in 1 .. < n.len:
@@ -714,7 +714,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     #echo "NOW evaluating at compile time: ", call.renderTree
     if sfCompileTime in callee.flags:
       result = evalStaticExpr(c.module, call, c.p.owner)
-      if result.isNil: 
+      if result.isNil:
         localError(n.info, errCannotInterpretNodeX, renderTree(call))
       else: result = fixupTypeAfterEval(c, result, n)
     else:
@@ -737,17 +737,17 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
                                      flags: TExprFlags): PNode =
   if flags*{efInTypeof, efWantIterator} != {}:
     # consider: 'for x in pReturningArray()' --> we don't want the restriction
-    # to 'skIterators' anymore; skIterators are preferred in sigmatch already 
+    # to 'skIterators' anymore; skIterators are preferred in sigmatch already
     # for typeof support.
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
     result = semOverloadedCall(c, n, nOrig,
       {skProc, skMethod, skConverter, skMacro, skTemplate}+skIterators)
   else:
-    result = semOverloadedCall(c, n, nOrig, 
+    result = semOverloadedCall(c, n, nOrig,
       {skProc, skMethod, skConverter, skMacro, skTemplate})
- 
+
   if result != nil:
-    if result.sons[0].kind != nkSym: 
+    if result.sons[0].kind != nkSym:
       internalError("semOverloadedCallAnalyseEffects")
       return
     let callee = result.sons[0].sym
@@ -759,7 +759,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
         # error correction, prevents endless for loop elimination in transf.
         # See bug #2051:
         result.sons[0] = newSymNode(errorSym(c, n))
-      if sfNoSideEffect notin callee.flags: 
+      if sfNoSideEffect notin callee.flags:
         if {sfImportc, sfSideEffect} * callee.flags != {}:
           incl(c.p.owner.flags, sfSideEffect)
 
@@ -808,11 +808,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       else:
         var hasErrorType = false
         var msg = msgKindToString(errTypeMismatch)
-        for i in countup(1, sonsLen(n) - 1): 
+        for i in countup(1, sonsLen(n) - 1):
           if i > 1: add(msg, ", ")
           let nt = n.sons[i].typ
           add(msg, typeToString(nt))
-          if nt.kind == tyError: 
+          if nt.kind == tyError:
             hasErrorType = true
             break
         if not hasErrorType:
@@ -824,7 +824,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       result = m.call
       instGenericConvertersSons(c, result, m)
-    # we assume that a procedure that calls something indirectly 
+    # we assume that a procedure that calls something indirectly
     # has side-effects:
     if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
   elif t != nil and t.kind == tyTypeDesc:
@@ -834,7 +834,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result = overloadedCallOpr(c, n)
     # Now that nkSym does not imply an iteration over the proc/iterator space,
     # the old ``prc`` (which is likely an nkIdent) has to be restored:
-    if result == nil: 
+    if result == nil:
       # XXX: hmm, what kind of symbols will end up here?
       # do we really need to try the overload resolution?
       n.sons[0] = prc
@@ -869,7 +869,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
   if c.inTypeClass == 0:
     result = evalAtCompileTime(c, result)
 
-proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # this seems to be a hotspot in the compiler!
   let nOrig = n.copyTree
   #semLazyOpAux(c, n)
@@ -877,7 +877,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if result != nil: result = afterCallActions(c, result, nOrig, flags)
   else: result = errorNode(c, n)
 
-proc buildEchoStmt(c: PContext, n: PNode): PNode = 
+proc buildEchoStmt(c: PContext, n: PNode): PNode =
   # we MUST not check 'n' for semantics again here! But for now we give up:
   result = newNodeI(nkCall, n.info)
   var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
@@ -892,8 +892,8 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
 proc semExprNoType(c: PContext, n: PNode): PNode =
   result = semExpr(c, n, {efWantStmt})
   discardCheck(c, result)
-  
-proc isTypeExpr(n: PNode): bool = 
+
+proc isTypeExpr(n: PNode): bool =
   case n.kind
   of nkType, nkTypeOfExpr: result = true
   of nkSym: result = n.sym.kind == skType
@@ -904,24 +904,24 @@ proc createSetType(c: PContext; baseType: PType): PType =
   result = newTypeS(tySet, c)
   rawAddSon(result, baseType)
 
-proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, 
-                                 check: var PNode): PSym = 
+proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
+                                 check: var PNode): PSym =
   # transform in a node that contains the runtime check for the
   # field, if it is in a case-part...
   result = nil
   case r.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(r) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(r) - 1):
       result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check)
-      if result != nil: return 
-  of nkRecCase: 
+      if result != nil: return
+  of nkRecCase:
     checkMinSonsLen(r, 2)
     if (r.sons[0].kind != nkSym): illFormedAst(r)
     result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check)
-    if result != nil: return 
+    if result != nil: return
     let setType = createSetType(c, r.sons[0].typ)
     var s = newNodeIT(nkCurly, r.info, setType)
-    for i in countup(1, sonsLen(r) - 1): 
+    for i in countup(1, sonsLen(r) - 1):
       var it = r.sons[i]
       case it.kind
       of nkOfBranch:
@@ -957,14 +957,14 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
           addSon(check, notExpr)
           return
       else: illFormedAst(it)
-  of nkSym: 
+  of nkSym:
     if r.sym.name.id == field.id: result = r.sym
   else: illFormedAst(n)
 
-proc makeDeref(n: PNode): PNode = 
+proc makeDeref(n: PNode): PNode =
   var t = skipTypes(n.typ, {tyGenericInst})
   result = n
-  if t.kind == tyVar: 
+  if t.kind == tyVar:
     result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
     addSon(result, n)
     t = skipTypes(t.sons[0], {tyGenericInst})
@@ -1079,7 +1079,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
           check.sons[0] = n
           check.typ = n.typ
           result = check
-  elif ty.kind == tyTuple and ty.n != nil: 
+  elif ty.kind == tyTuple and ty.n != nil:
     f = getSymFromList(ty.n, i)
     if f != nil:
       markUsed(n.sons[1].info, f)
@@ -1106,8 +1106,8 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
     result.flags.incl nfDotField
     addSon(result, newIdentNode(i, n[1].info))
     addSon(result, copyTree(n[0]))
-  
-proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+
+proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # this is difficult, because the '.' is used in many different contexts
   # in Nim. We first allow types in the semantic checking.
   result = builtinFieldAccess(c, n, flags)
@@ -1118,7 +1118,7 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
   result = newNodeI(nkCall, n.info)
   result.add(newIdentNode(ident, n.info))
   for i in 0 .. n.len-1: result.add(n[i])
-  
+
 proc semDeref(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1)
   n.sons[0] = semExprWithType(c, n.sons[0])
@@ -1127,12 +1127,12 @@ proc semDeref(c: PContext, n: PNode): PNode =
   case t.kind
   of tyRef, tyPtr: n.typ = t.lastSon
   else: result = nil
-  #GlobalError(n.sons[0].info, errCircumNeedsPointer) 
+  #GlobalError(n.sons[0].info, errCircumNeedsPointer)
 
 proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if not a built-in subscript operator; also called for the
   ## checking of assignments
-  if sonsLen(n) == 1: 
+  if sonsLen(n) == 1:
     var x = semDeref(c, n)
     if x == nil: return nil
     result = newNodeIT(nkDerefExpr, x.info, x.typ)
@@ -1142,12 +1142,12 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   n.sons[0] = semExprWithType(c, n.sons[0])
   var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
   case arr.kind
-  of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, 
+  of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
      tyCString:
     if n.len != 2: return nil
     n.sons[0] = makeDeref(n.sons[0])
-    for i in countup(1, sonsLen(n) - 1): 
-      n.sons[i] = semExprWithType(c, n.sons[i], 
+    for i in countup(1, sonsLen(n) - 1):
+      n.sons[i] = semExprWithType(c, n.sons[i],
                                   flags*{efInTypeof, efDetermineType})
     var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt)
     var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
@@ -1157,28 +1157,28 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result.typ = elemType(arr)
     #GlobalError(n.info, errIndexTypesDoNotMatch)
   of tyTypeDesc:
-    # The result so far is a tyTypeDesc bound 
+    # The result so far is a tyTypeDesc bound
     # a tyGenericBody. The line below will substitute
     # it with the instantiated type.
     result = n
     result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
     #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
-  of tyTuple: 
+  of tyTuple:
     checkSonsLen(n, 2)
     n.sons[0] = makeDeref(n.sons[0])
     # [] operator for tuples requires constant expression:
     n.sons[1] = semConstExpr(c, n.sons[1])
     if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
-        {tyInt..tyInt64}: 
+        {tyInt..tyInt64}:
       var idx = getOrdValue(n.sons[1])
       if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)]
       else: localError(n.info, errInvalidIndexValueForTuple)
-    else: 
+    else:
       localError(n.info, errIndexTypesDoNotMatch)
     result = n
   else: discard
-  
-proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+
+proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = semSubscript(c, n, flags)
   if result == nil:
     # overloaded [] operator:
@@ -1195,7 +1195,7 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
   result.flags.incl nfDotSetter
   let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
   result = semOverloadedCallAnalyseEffects(c, result, orig, {})
-  
+
   if result != nil:
     result = afterCallActions(c, result, nOrig, {})
     #fixAbstractType(c, result)
@@ -1216,7 +1216,7 @@ proc takeImplicitAddr(c: PContext, n: PNode): PNode =
       localError(n.info, errExprHasNoAddress)
   result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ))
   result.add(n)
-  
+
 proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
   if le.kind == nkHiddenDeref:
     var x = le.sons[0]
@@ -1265,7 +1265,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
   # a = b # both are vars, means: a[] = b[]
   # a = b # b no 'var T' means: a = addr(b)
   var le = a.typ
-  if skipTypes(le, {tyGenericInst}).kind != tyVar and 
+  if skipTypes(le, {tyGenericInst}).kind != tyVar and
       isAssignable(c, a) == arNone:
     # Direct assignment to a discriminant is allowed!
     localError(a.info, errXCannotBeAssignedTo,
@@ -1275,7 +1275,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
       lhs = n.sons[0]
       lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
     var
-      rhs = semExprWithType(c, n.sons[1], 
+      rhs = semExprWithType(c, n.sons[1],
         if lhsIsResult: {efAllowDestructor} else: {})
     if lhsIsResult:
       n.typ = enforceVoidContext
@@ -1300,13 +1300,13 @@ proc semReturn(c: PContext, n: PNode): PNode =
                         skClosureIterator}:
     if n.sons[0].kind != nkEmpty:
       # transform ``return expr`` to ``result = expr; return``
-      if c.p.resultSym != nil: 
+      if c.p.resultSym != nil:
         var a = newNodeI(nkAsgn, n.sons[0].info)
         addSon(a, newSymNode(c.p.resultSym))
         addSon(a, n.sons[0])
         n.sons[0] = semAsgn(c, a)
         # optimize away ``result = result``:
-        if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: 
+        if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
           n.sons[0] = ast.emptyNode
       else:
         localError(n.info, errNoReturnTypeDeclared)
@@ -1315,7 +1315,7 @@ proc semReturn(c: PContext, n: PNode): PNode =
 
 proc semProcBody(c: PContext, n: PNode): PNode =
   openScope(c)
-  
+
   result = semExpr(c, n)
   if c.p.resultSym != nil and not isEmptyType(result.typ):
     # transform ``expr`` to ``result = expr``, but not if the expr is already
@@ -1339,7 +1339,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
       result = semAsgn(c, a)
   else:
     discardCheck(c, result)
-  
+
   if c.p.owner.kind notin {skMacro, skTemplate} and
      c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
     if isEmptyType(result.typ):
@@ -1362,14 +1362,14 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
       if e.kind == tyVar:
         if n.sons[0].kind == nkPar:
           n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i])
-        elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and 
+        elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
              n.sons[0].sons[1].kind == nkPar:
           var a = n.sons[0].sons[1]
           a.sons[i] = takeImplicitAddr(c, a.sons[i])
         else:
           localError(n.sons[0].info, errXExpected, "tuple constructor")
   else: discard
-  
+
 proc semYield(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
@@ -1387,14 +1387,14 @@ proc semYield(c: PContext, n: PNode): PNode =
       if adjustedRes.kind != tyExpr:
         n.sons[0] = fitNode(c, adjustedRes, n.sons[0])
       if n.sons[0].typ == nil: internalError(n.info, "semYield")
-      
+
       if resultTypeIsInferrable(adjustedRes):
         let inferred = n.sons[0].typ
         if restype.kind == tyIter:
           restype.sons[0] = inferred
         else:
           iterType.sons[0] = inferred
-      
+
       semYieldVarResult(c, n, adjustedRes)
     else:
       localError(n.info, errCannotReturnExpr)
@@ -1402,25 +1402,25 @@ proc semYield(c: PContext, n: PNode): PNode =
     localError(n.info, errGenerated, "yield statement must yield a value")
 
 proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
-  if onlyCurrentScope: 
+  if onlyCurrentScope:
     result = localSearchInScope(c, i)
-  else: 
+  else:
     result = searchInScopes(c, i) # no need for stub loading
 
-proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = 
+proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
   case n.kind
-  of nkIdent: 
+  of nkIdent:
     result = lookUpForDefined(c, n.ident, onlyCurrentScope)
   of nkDotExpr:
     result = nil
-    if onlyCurrentScope: return 
+    if onlyCurrentScope: return
     checkSonsLen(n, 2)
     var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
     if m != nil and m.kind == skModule:
       let ident = considerQuotedIdent(n[1])
       if m == c.module:
         result = strTableGet(c.topLevelScope.symbols, ident)
-      else: 
+      else:
         result = strTableGet(m.tab, ident)
   of nkAccQuoted:
     result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope)
@@ -1432,7 +1432,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
     localError(n.info, errIdentifierExpected, renderTree(n))
     result = nil
 
-proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = 
+proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
   checkSonsLen(n, 2)
   # we replace this node by a 'true' or 'false' node:
   result = newIntNode(nkIntLit, 0)
@@ -1441,7 +1441,7 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
       localError(n.info, "obsolete usage of 'defined', use 'declared' instead")
     elif condsyms.isDefined(n.sons[1].ident):
       result.intVal = 1
-  elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: 
+  elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
     result.intVal = 1
   result.info = n.info
   result.typ = getSysType(tyBool)
@@ -1544,7 +1544,7 @@ proc processQuotations(n: var PNode, op: string,
         n.sons[0] = newIdentNode(getIdent(examinedOp.substr(op.len)), n.info)
   elif n.kind == nkAccQuoted and op == "``":
     returnQuote n[0]
- 
+
   for i in 0 .. <n.safeLen:
     processQuotations(n.sons[i], op, quotes, ids)
 
@@ -1556,7 +1556,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
     doBlk = n{-1}
     op = if n.len == 3: expectString(c, n[1]) else: "``"
     quotes = newSeq[PNode](1)
-      # the quotes will be added to a nkCall statement 
+      # the quotes will be added to a nkCall statement
       # leave some room for the callee symbol
     ids = newSeq[PNode]()
       # this will store the generated param names
@@ -1565,7 +1565,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
     localError(n.info, errXExpected, "block")
 
   processQuotations(doBlk.sons[bodyPos], op, quotes, ids)
-  
+
   doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
   if ids.len > 0:
     doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
@@ -1573,7 +1573,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
     ids.add getSysSym("expr").newSymNode # params type
     ids.add emptyNode # no default value
     doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
-  
+
   var tmpl = semTemplateDef(c, doBlk)
   quotes[0] = tmpl[namePos]
   result = newNode(nkCall, n.info, @[
@@ -1588,7 +1588,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   inc c.inCompilesContext
   # do not halt after first error:
   msgs.gErrorMax = high(int)
-  
+
   # open a scope for temporary symbol inclusions:
   let oldScope = c.currentScope
   openScope(c)
@@ -1597,7 +1597,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   let oldErrorOutputs = errorOutputs
   errorOutputs = {}
   let oldContextLen = msgs.getInfoContextLen()
-  
+
   let oldInGenericContext = c.inGenericContext
   let oldInUnrolledContext = c.inUnrolledContext
   let oldInGenericInst = c.inGenericInst
@@ -1625,7 +1625,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
 proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # we replace this node by a 'true' or 'false' node:
   if sonsLen(n) != 2: return semDirectOp(c, n, flags)
-  
+
   result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
   result.info = n.info
   result.typ = getSysType(tyBool)
@@ -1652,7 +1652,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
   let sym = magicsys.getCompilerProc("nimCreateFlowVar")
   if sym == nil:
     localError(info, errSystemNeeds, "nimCreateFlowVar")
-  var bindings: TIdTable 
+  var bindings: TIdTable
   initIdTable(bindings)
   bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
   result = c.semGenerateInstance(c, sym, bindings, info)
@@ -1662,12 +1662,12 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
     result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC}
     result.loc.r = nil
 
-proc setMs(n: PNode, s: PSym): PNode = 
+proc setMs(n: PNode, s: PSym): PNode =
   result = n
   n.sons[0] = newSymNode(s)
   n.sons[0].info = n.info
 
-proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
+proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   # this is a hotspot in the compiler!
   # DON'T forget to update ast.SpecialSemMagics if you add a magic here!
   result = n
@@ -1713,36 +1713,36 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   # If semCheck is set to false, ``when`` will return the verbatim AST of
   # the correct branch. Otherwise the AST will be passed through semStmt.
   result = nil
-  
+
   template setResult(e: expr) =
     if semCheck: result = semStmt(c, e) # do not open a new scope!
     else: result = e
 
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     case it.kind
-    of nkElifBranch, nkElifExpr: 
+    of nkElifBranch, nkElifExpr:
       checkSonsLen(it, 2)
       var e = semConstExpr(c, it.sons[0])
-      if e.kind != nkIntLit: 
+      if e.kind != nkIntLit:
         # can happen for cascading errors, assume false
         # InternalError(n.info, "semWhen")
         discard
       elif e.intVal != 0 and result == nil:
-        setResult(it.sons[1]) 
+        setResult(it.sons[1])
     of nkElse, nkElseExpr:
       checkSonsLen(it, 1)
-      if result == nil: 
+      if result == nil:
         setResult(it.sons[0])
     else: illFormedAst(n)
   if result == nil:
-    result = newNodeI(nkEmpty, n.info) 
+    result = newNodeI(nkEmpty, n.info)
   # The ``when`` statement implements the mechanism for platform dependent
   # code. Thus we try to ensure here consistent ID allocation after the
   # ``when`` statement.
   idSynchronizationPoint(200)
 
-proc semSetConstr(c: PContext, n: PNode): PNode = 
+proc semSetConstr(c: PContext, n: PNode): PNode =
   result = newNodeI(nkCurly, n.info)
   result.typ = newTypeS(tySet, c)
   if sonsLen(n) == 0:
@@ -1750,31 +1750,31 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
   else:
     # only semantic checking for all elements, later type checking:
     var typ: PType = nil
-    for i in countup(0, sonsLen(n) - 1): 
-      if isRange(n.sons[i]): 
+    for i in countup(0, sonsLen(n) - 1):
+      if isRange(n.sons[i]):
         checkSonsLen(n.sons[i], 3)
         n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
         n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2])
-        if typ == nil: 
-          typ = skipTypes(n.sons[i].sons[1].typ, 
+        if typ == nil:
+          typ = skipTypes(n.sons[i].sons[1].typ,
                           {tyGenericInst, tyVar, tyOrdinal})
         n.sons[i].typ = n.sons[i].sons[2].typ # range node needs type too
       elif n.sons[i].kind == nkRange:
         # already semchecked
         if typ == nil:
-          typ = skipTypes(n.sons[i].sons[0].typ, 
+          typ = skipTypes(n.sons[i].sons[0].typ,
                           {tyGenericInst, tyVar, tyOrdinal})
       else:
         n.sons[i] = semExprWithType(c, n.sons[i])
-        if typ == nil: 
+        if typ == nil:
           typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyOrdinal})
     if not isOrdinalType(typ):
       localError(n.info, errOrdinalTypeExpected)
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
-    elif lengthOrd(typ) > MaxSetElements: 
+    elif lengthOrd(typ) > MaxSetElements:
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
     addSonSkipIntLit(result.typ, typ)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       var m: PNode
       if isRange(n.sons[i]):
         m = newNodeI(nkRange, n.sons[i].info)
@@ -1786,7 +1786,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
       addSon(result, m)
 
 proc semTableConstr(c: PContext, n: PNode): PNode =
-  # we simply transform ``{key: value, key2, key3: value}`` to 
+  # we simply transform ``{key: value, key2, key3: value}`` to
   # ``[(key, value), (key2, value2), (key3, value2)]``
   result = newNodeI(nkBracket, n.info)
   var lastKey = 0
@@ -1815,7 +1815,7 @@ type
 
 proc checkPar(n: PNode): TParKind =
   var length = sonsLen(n)
-  if length == 0: 
+  if length == 0:
     result = paTuplePositions # ()
   elif length == 1:
     if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
@@ -1845,7 +1845,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     var id: PIdent
     if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
     else: id = n.sons[i].sons[0].sym.name
-    if containsOrIncl(ids, id.id): 
+    if containsOrIncl(ids, id.id):
       localError(n.sons[i].info, errFieldInitTwice, id.s)
     n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
                                         flags*{efAllowDestructor})
@@ -1858,14 +1858,22 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     addSon(result, n.sons[i])
   result.typ = typ
 
-proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = n                  # we don't modify n, but compute the type:
   var typ = newTypeS(tyTuple, c)  # leave typ.n nil!
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor})
     addSonSkipIntLit(typ, n.sons[i].typ)
   result.typ = typ
 
+proc isTupleType(n: PNode): bool =
+  if n.len == 0:
+    return false # don't interpret () as type
+  for i in countup(0, n.len - 1):
+    if n[i].typ == nil or n[i].typ.kind != tyTypeDesc:
+      return false
+  return true
+
 proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
   case n.kind
   of nkRecList:
@@ -1899,12 +1907,11 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var ids = initIntSet()
   for i in 1.. <n.len:
     let it = n.sons[i]
-    if it.kind != nkExprColonExpr or it.sons[0].kind notin {nkSym, nkIdent}:
+    if it.kind != nkExprColonExpr:
       localError(n.info, errNamedExprExpected)
       break
-    var id: PIdent
-    if it.sons[0].kind == nkIdent: id = it.sons[0].ident
-    else: id = it.sons[0].sym.name
+    let id = considerQuotedIdent(it.sons[0])
+
     if containsOrIncl(ids, id.id):
       localError(it.info, errFieldInitTwice, id.s)
     var e = semExprWithType(c, it.sons[1], flags*{efAllowDestructor})
@@ -1991,10 +1998,10 @@ proc setGenericParams(c: PContext, n: PNode) =
   for i in 1 .. <n.len:
     n[i].typ = semTypeNode(c, n[i], nil)
 
-proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
+proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   result = n
   if gCmd == cmdIdeTools: suggestExpr(c, n)
-  if nfSem in n.flags: return 
+  if nfSem in n.flags: return
   case n.kind
   of nkIdent, nkAccQuoted:
     var s = lookUp(c, n)
@@ -2011,43 +2018,43 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
     result = semSym(c, n, n.sym, flags)
-  of nkEmpty, nkNone, nkCommentStmt: 
+  of nkEmpty, nkNone, nkCommentStmt:
     discard
-  of nkNilLit: 
+  of nkNilLit:
     result.typ = getSysType(tyNil)
   of nkIntLit:
     if result.typ == nil: setIntLitType(result)
   of nkInt8Lit:
     if result.typ == nil: result.typ = getSysType(tyInt8)
-  of nkInt16Lit: 
+  of nkInt16Lit:
     if result.typ == nil: result.typ = getSysType(tyInt16)
-  of nkInt32Lit: 
+  of nkInt32Lit:
     if result.typ == nil: result.typ = getSysType(tyInt32)
-  of nkInt64Lit: 
+  of nkInt64Lit:
     if result.typ == nil: result.typ = getSysType(tyInt64)
   of nkUIntLit:
     if result.typ == nil: result.typ = getSysType(tyUInt)
-  of nkUInt8Lit: 
+  of nkUInt8Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt8)
-  of nkUInt16Lit: 
+  of nkUInt16Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt16)
-  of nkUInt32Lit: 
+  of nkUInt32Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt32)
-  of nkUInt64Lit: 
+  of nkUInt64Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt64)
-  of nkFloatLit: 
+  of nkFloatLit:
     if result.typ == nil: result.typ = getFloatLitType(result)
-  of nkFloat32Lit: 
+  of nkFloat32Lit:
     if result.typ == nil: result.typ = getSysType(tyFloat32)
-  of nkFloat64Lit: 
+  of nkFloat64Lit:
     if result.typ == nil: result.typ = getSysType(tyFloat64)
-  of nkFloat128Lit: 
+  of nkFloat128Lit:
     if result.typ == nil: result.typ = getSysType(tyFloat128)
-  of nkStrLit..nkTripleStrLit: 
+  of nkStrLit..nkTripleStrLit:
     if result.typ == nil: result.typ = getSysType(tyString)
-  of nkCharLit: 
+  of nkCharLit:
     if result.typ == nil: result.typ = getSysType(tyChar)
-  of nkDotExpr: 
+  of nkDotExpr:
     result = semFieldAccess(c, n, flags)
     if result.kind == nkDotCall:
       result.kind = nkCall
@@ -2055,11 +2062,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkBind:
     message(n.info, warnDeprecated, "bind")
     result = semExpr(c, n.sons[0], flags)
-  of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy:
+  of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
     var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
     result.typ = makeTypeDesc(c, typ)
     #result = symNodeFromType(c, typ, n.info)
-  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
+  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
     let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
@@ -2084,7 +2091,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
           result = semConv(c, n)
         elif n.len == 1:
           result = semObjConstr(c, n, flags)
-        elif contains(c.ambiguousSymbols, s.id): 
+        elif contains(c.ambiguousSymbols, s.id):
           localError(n.info, errUseQualifier, s.name.s)
         elif s.magic == mNone: result = semDirectOp(c, n, flags)
         else: result = semMagic(c, n, s, flags)
@@ -2123,13 +2130,20 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       result = semArrayAccess(c, n, flags)
   of nkCurlyExpr:
     result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
-  of nkPragmaExpr: 
+  of nkPragmaExpr:
     # which pragmas are allowed for expressions? `likely`, `unlikely`
     internalError(n.info, "semExpr() to implement") # XXX: to implement
-  of nkPar: 
+  of nkPar:
     case checkPar(n)
     of paNone: result = errorNode(c, n)
-    of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
+    of paTuplePositions:
+      var tupexp = semTuplePositionsConstr(c, n, flags)
+      if isTupleType(tupexp):
+        # reinterpret as type
+        var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
+        result.typ = makeTypeDesc(c, typ)
+      else:
+        result = tupexp
     of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
     of paSingle: result = semExpr(c, n.sons[0], flags)
   of nkCurly: result = semSetConstr(c, n)
@@ -2142,7 +2156,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result = n
     checkSonsLen(n, 1)
     n.sons[0] = semExprWithType(c, n.sons[0])
-    if isAssignable(c, n.sons[0]) notin {arLValue, arLocalLValue}: 
+    if isAssignable(c, n.sons[0]) notin {arLValue, arLocalLValue}:
       localError(n.info, errExprHasNoAddress)
     n.typ = makePtrType(c, n.sons[0].typ)
   of nkHiddenAddr, nkHiddenDeref:
@@ -2150,13 +2164,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     n.sons[0] = semExpr(c, n.sons[0], flags)
   of nkCast: result = semCast(c, n)
   of nkIfExpr, nkIfStmt: result = semIf(c, n)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
     checkSonsLen(n, 2)
-  of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv: 
+  of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv:
     checkSonsLen(n, 1)
-  of nkChckRangeF, nkChckRange64, nkChckRange: 
+  of nkChckRangeF, nkChckRange64, nkChckRange:
     checkSonsLen(n, 3)
-  of nkCheckedFieldExpr: 
+  of nkCheckedFieldExpr:
     checkMinSonsLen(n, 2)
   of nkTableConstr:
     result = semTableConstr(c, n)
@@ -2191,16 +2205,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkConverterDef: result = semConverterDef(c, n)
   of nkMacroDef: result = semMacroDef(c, n)
   of nkTemplateDef: result = semTemplateDef(c, n)
-  of nkImportStmt: 
+  of nkImportStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import")
     result = evalImport(c, n)
   of nkImportExceptStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import")
     result = evalImportExcept(c, n)
-  of nkFromStmt: 
+  of nkFromStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from")
     result = evalFrom(c, n)
-  of nkIncludeStmt: 
+  of nkIncludeStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
     result = evalInclude(c, n)
   of nkExportStmt, nkExportExceptStmt:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 2601f05ac..db910600b 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -356,7 +356,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         of nkIdent: a = n.sons[i]
         else: illFormedAst(n)
         addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
-  of nkObjectTy, nkTupleTy:
+  of nkObjectTy, nkTupleTy, nkTupleClassTy:
     discard
   of nkFormalParams:
     checkMinSonsLen(n, 1)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index a10f27519..dc36ecf34 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -11,12 +11,12 @@
 # included from sem.nim
 
 proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
-                                 entry: var TInstantiation) = 
-  if n.kind != nkGenericParams: 
+                                 entry: var TInstantiation) =
+  if n.kind != nkGenericParams:
     internalError(n.info, "instantiateGenericParamList; no generic params")
   newSeq(entry.concreteTypes, n.len)
   for i, a in n.pairs:
-    if a.kind != nkSym: 
+    if a.kind != nkSym:
       internalError(a.info, "instantiateGenericParamList; no symbol")
     var q = a.sym
     if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
@@ -27,13 +27,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
     var t = PType(idTableGet(pt, q.typ))
     if t == nil:
       if tfRetType in q.typ.flags:
-        # keep the generic type and allow the return type to be bound 
+        # keep the generic type and allow the return type to be bound
         # later by semAsgn in return type inference scenario
         t = q.typ
       else:
         localError(a.info, errCannotInstantiateX, s.name.s)
         t = errorType(c)
-    elif t.kind == tyGenericParam: 
+    elif t.kind == tyGenericParam:
       localError(a.info, errCannotInstantiateX, q.name.s)
       t = errorType(c)
     elif t.kind == tyGenericInvocation:
@@ -58,17 +58,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
       if sameInstantiation(entry, inst[]):
         return inst.sym
 
-proc removeDefaultParamValues(n: PNode) = 
+proc removeDefaultParamValues(n: PNode) =
   # we remove default params, because they cannot be instantiated properly
   # and they are not needed anyway for instantiation (each param is already
   # provided).
   when false:
-    for i in countup(1, sonsLen(n)-1): 
+    for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
       if a.kind != nkIdentDefs: IllFormedAst(a)
       var L = a.len
       if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
-        # ``param: typ = defaultVal``. 
+        # ``param: typ = defaultVal``.
         # We don't need defaultVal for semantic checking and it's wrong for
         # ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
         # not possible... XXX We don't solve this issue here.
@@ -97,7 +97,7 @@ proc addProcDecls(c: PContext, fn: PSym) =
     var param = fn.typ.n.sons[i].sym
     param.owner = fn
     addParamOrResult(c, param, fn.kind)
-  
+
   maybeAddResult(c, fn, fn.ast)
 
 proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
@@ -132,9 +132,9 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       closeScope(c)
       popInfoContext()
 
-proc sideEffectsCheck(c: PContext, s: PSym) = 
+proc sideEffectsCheck(c: PContext, s: PSym) =
   if {sfNoSideEffect, sfSideEffect} * s.flags ==
-      {sfNoSideEffect, sfSideEffect}: 
+      {sfNoSideEffect, sfSideEffect}:
     localError(s.info, errXhasSideEffects, s.name.s)
 
 proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
@@ -162,18 +162,18 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   # Alas, doing this here is probably not enough, because another
   # proc signature could appear in the params:
   # proc foo[T](a: proc (x: T, b: type(x.y))
-  #   
+  #
   # The solution would be to move this logic into semtypinst, but
   # at this point semtypinst have to become part of sem, because it
   # will need to use openScope, addDecl, etc.
   addDecl(c, prc)
-  
+
   pushInfoContext(info)
   var cl = initTypeVars(c, pt, info)
   var result = instCopyType(cl, prc.typ)
   let originalParams = result.n
   result.n = originalParams.shallowCopy
-  
+
   for i in 1 .. <result.len:
     # twrong_field_caching requires these 'resetIdTable' calls:
     if i > 1: resetIdTable(cl.symMap)
@@ -198,10 +198,10 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   resetIdTable(cl.symMap)
   result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
   result.n.sons[0] = originalParams[0].copyTree
-  
+
   eraseVoidParams(result)
   skipIntLiteralParams(result)
- 
+
   prc.typ = result
   maybeAddResult(c, prc, prc.ast)
   popInfoContext()
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
index a914832de..6572a7f49 100644
--- a/compiler/semparallel.nim
+++ b/compiler/semparallel.nim
@@ -37,7 +37,7 @@ is valid, but
   spawn f(a[i])
   spawn f(a[i])
   inc i
-is not! However, 
+is not! However,
   spawn f(a[i])
   if guard: inc i
   spawn f(a[i])
@@ -460,7 +460,7 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
   # - detect used slices
   # - detect used arguments
   #echo "PAR ", renderTree(n)
-  
+
   var a = initAnalysisCtx()
   let body = n.lastSon
   analyse(a, body)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 60153e052..14644a8d6 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
   if g.kind == skUnknown:
     var field: PSym = nil
     var ty = n.sons[0].typ.skipTypes(abstractPtrs)
-    if ty.kind == tyTuple:
+    if ty.kind == tyTuple and not ty.n.isNil:
       field = lookupInRecord(ty.n, g.name)
     else:
       while ty != nil and ty.kind == tyObject:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 3fbb6f8f3..19514263f 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -12,13 +12,13 @@
 
 var enforceVoidContext = PType(kind: tyStmt)
 
-proc semDiscard(c: PContext, n: PNode): PNode = 
+proc semDiscard(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
     if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
-  
+
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
@@ -29,7 +29,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
       of nkIdent: s = lookUp(c, n.sons[0])
       of nkSym: s = n.sons[0].sym
       else: illFormedAst(n)
-      if s.kind == skLabel and s.owner.id == c.p.owner.id: 
+      if s.kind == skLabel and s.owner.id == c.p.owner.id:
         var x = newSymNode(s)
         x.info = n.info
         incl(s.flags, sfUsed)
@@ -41,16 +41,16 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
     else:
       localError(n.info, errGenerated, "'continue' cannot have a label")
   elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
-    localError(n.info, errInvalidControlFlowX, 
+    localError(n.info, errInvalidControlFlowX,
                renderTree(n, {renderNoComments}))
 
-proc semAsm(con: PContext, n: PNode): PNode = 
+proc semAsm(con: PContext, n: PNode): PNode =
   checkSonsLen(n, 2)
   var marker = pragmaAsm(con, n.sons[0])
   if marker == '\0': marker = '`' # default marker
   result = semAsmOrEmit(con, n, marker)
-  
-proc semWhile(c: PContext, n: PNode): PNode = 
+
+proc semWhile(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 2)
   openScope(c)
@@ -62,16 +62,16 @@ proc semWhile(c: PContext, n: PNode): PNode =
   if n.sons[1].typ == enforceVoidContext:
     result.typ = enforceVoidContext
 
-proc toCover(t: PType): BiggestInt = 
+proc toCover(t: PType): BiggestInt =
   var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
-  if t2.kind == tyEnum and enumHasHoles(t2): 
+  if t2.kind == tyEnum and enumHasHoles(t2):
     result = sonsLen(t2.n)
   else:
     result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
 
 proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
   ## Checks that the given symbol is a proper procedure variable, meaning
-  ## that it 
+  ## that it
   var smoduleId = getModule(s).id
   if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
       smoduleId != c.module.id:
@@ -98,11 +98,11 @@ proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
       localError(n.info, warnDestructor)
   # This still breaks too many things:
   when false:
-    if efDetermineType notin flags and n.typ.kind == tyTypeDesc and 
+    if efDetermineType notin flags and n.typ.kind == tyTypeDesc and
         c.p.owner.kind notin {skTemplate, skMacro}:
       localError(n.info, errGenerated, "value expected, but got a type")
 
-proc newDeref(n: PNode): PNode {.inline.} =  
+proc newDeref(n: PNode): PNode {.inline.} =
   result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
   addSon(result, n)
 
@@ -127,7 +127,7 @@ const
 proc implicitlyDiscardable(n: PNode): bool =
   var n = n
   while n.kind in skipForDiscardable: n = n.lastSon
-  result = isCallExpr(n) and n.sons[0].kind == nkSym and 
+  result = isCallExpr(n) and n.sons[0].kind == nkSym and
            sfDiscardable in n.sons[0].sym.flags
 
 proc fixNilType(n: PNode) =
@@ -160,11 +160,11 @@ proc discardCheck(c: PContext, result: PNode) =
         while n.kind in skipForDiscardable: n = n.lastSon
         localError(n.info, errDiscardValueX, result.typ.typeToString)
 
-proc semIf(c: PContext, n: PNode): PNode = 
+proc semIf(c: PContext, n: PNode): PNode =
   result = n
   var typ = commonTypeBegin
   var hasElse = false
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if it.len == 2:
       when newScopeForIf: openScope(c)
@@ -208,10 +208,10 @@ proc semCase(c: PContext, n: PNode): PNode =
   else:
     localError(n.info, errSelectorMustBeOfCertainTypes)
     return
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var x = n.sons[i]
     case x.kind
-    of nkOfBranch: 
+    of nkOfBranch:
       checkMinSonsLen(x, 2)
       semCaseBranch(c, n, x, i, covered)
       var last = sonsLen(x)-1
@@ -304,9 +304,9 @@ proc semTry(c: PContext, n: PNode): PNode =
       it.sons[j] = fitNode(c, typ, it.sons[j])
     result.typ = typ
 
-proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = 
+proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
   result = fitNode(c, typ, n)
-  if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: 
+  if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
     changeType(result.sons[1], typ, check=true)
     result = result.sons[1]
   elif not sameType(result.typ, typ):
@@ -325,7 +325,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
   result = n.kind == nkSym and n.sym.name.id == s.id
 
 proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
-  if isTopLevel(c): 
+  if isTopLevel(c):
     result = semIdentWithPragma(c, kind, n, {sfExported})
     incl(result.flags, sfGlobal)
   else:
@@ -340,14 +340,14 @@ proc checkNilable(v: PSym) =
     elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
       message(v.info, warnProveInit, v.name.s)
 
-proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = 
+proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var b: PNode
   result = copyNode(n)
   var hasCompileTime = false
-  for i in countup(0, sonsLen(n)-1): 
+  for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
     checkMinSonsLen(a, 3)
     var length = sonsLen(a)
@@ -369,7 +369,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
           typ = def.typ
         else:
           # BUGFIX: ``fitNode`` is needed here!
-          # check type compatibility between def.typ and typ        
+          # check type compatibility between def.typ and typ
           def = fitNode(c, typ, def)
           #changeType(def.skipConv, typ, check=true)
       else:
@@ -381,15 +381,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
     else:
       def = ast.emptyNode
       if symkind == skLet: localError(a.info, errLetNeedsInit)
-      
+
     # this can only happen for errornous var statements:
     if typ == nil: continue
     typeAllowedCheck(a.info, typ, symkind)
     var tup = skipTypes(typ, {tyGenericInst})
-    if a.kind == nkVarTuple: 
-      if tup.kind != tyTuple: 
+    if a.kind == nkVarTuple:
+      if tup.kind != tyTuple:
         localError(a.info, errXExpected, "tuple")
-      elif length-2 != sonsLen(tup): 
+      elif length-2 != sonsLen(tup):
         localError(a.info, errWrongNumberOfVariables)
       else:
         b = newNodeI(nkVarTuple, a.info)
@@ -397,9 +397,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
         b.sons[length-1] = def
         addSon(result, b)
-    elif tup.kind == tyTuple and def.kind == nkPar and 
+    elif tup.kind == tyTuple and def.kind == nkPar and
         a.kind == nkIdentDefs and a.len > 3:
       message(a.info, warnEachIdentIsTuple)
+
     for j in countup(0, length-3):
       var v = semIdentDef(c, a.sons[j], symkind)
       if sfGenSym notin v.flags: addInterfaceDecl(c, v)
@@ -409,6 +410,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
           let shadowed = findShadowedVar(c, v)
           if shadowed != nil:
             shadowed.flags.incl(sfShadowed)
+            if shadowed.kind == skResult and sfGenSym notin v.flags:
+              message(a.info, warnResultShadowed)
             # a shadowed variable is an error unless it appears on the right
             # side of the '=':
             if warnShadowIdent in gNotes and not identWithin(def, v.name):
@@ -435,12 +438,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       if sfCompileTime in v.flags: hasCompileTime = true
   if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
 
-proc semConst(c: PContext, n: PNode): PNode = 
+proc semConst(c: PContext, n: PNode): PNode =
   result = copyNode(n)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if (a.kind != nkConstDef): illFormedAst(a)
     checkSonsLen(a, 3)
     var v = semIdentDef(c, a.sons[0], skConst)
@@ -495,7 +498,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
   var iter = skipTypes(iterBase, {tyGenericInst})
   # length == 3 means that there is one for loop variable
   # and thus no tuple unpacking:
-  if iter.kind != tyTuple or length == 3: 
+  if iter.kind != tyTuple or length == 3:
     if length == 3:
       var v = symForVar(c, n.sons[0])
       if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
@@ -523,13 +526,13 @@ proc semForVars(c: PContext, n: PNode): PNode =
 proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
   result = newNodeI(nkCall, arg.info)
   result.add(newIdentNode(it.getIdent, arg.info))
-  if arg.typ != nil and arg.typ.kind == tyVar: 
+  if arg.typ != nil and arg.typ.kind == tyVar:
     result.add newDeref(arg)
   else:
     result.add arg
   result = semExprNoDeref(c, result, {efWantIterator})
 
-proc semFor(c: PContext, n: PNode): PNode = 
+proc semFor(c: PContext, n: PNode): PNode =
   result = n
   checkMinSonsLen(n, 3)
   var length = sonsLen(n)
@@ -564,13 +567,13 @@ proc semFor(c: PContext, n: PNode): PNode =
     result.typ = enforceVoidContext
   closeScope(c)
 
-proc semRaise(c: PContext, n: PNode): PNode = 
+proc semRaise(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
-  if n.sons[0].kind != nkEmpty: 
+  if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
     var typ = n.sons[0].typ
-    if typ.kind != tyRef or typ.sons[0].kind != tyObject: 
+    if typ.kind != tyRef or typ.sons[0].kind != tyObject:
       localError(n.info, errExprCannotBeRaised)
 
 proc addGenericParamListToScope(c: PContext, n: PNode) =
@@ -580,13 +583,13 @@ proc addGenericParamListToScope(c: PContext, n: PNode) =
     if a.kind == nkSym: addDecl(c, a.sym)
     else: illFormedAst(a)
 
-proc typeSectionLeftSidePass(c: PContext, n: PNode) = 
+proc typeSectionLeftSidePass(c: PContext, n: PNode) =
   # process the symbols on the left side for the whole type section, before
   # we even look at the type definitions on the right
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if a.kind != nkTypeDef: illFormedAst(a)
     checkSonsLen(a, 3)
     var s = semIdentDef(c, a.sons[0], skType)
@@ -599,29 +602,29 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     a.sons[0] = newSymNode(s)
 
 proc typeSectionRightSidePass(c: PContext, n: PNode) =
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if (a.kind != nkTypeDef): illFormedAst(a)
     checkSonsLen(a, 3)
     if (a.sons[0].kind != nkSym): illFormedAst(a)
     var s = a.sons[0].sym
-    if s.magic == mNone and a.sons[2].kind == nkEmpty: 
+    if s.magic == mNone and a.sons[2].kind == nkEmpty:
       localError(a.info, errImplOfXexpected, s.name.s)
     if s.magic != mNone: processMagicType(c, s)
-    if a.sons[1].kind != nkEmpty: 
+    if a.sons[1].kind != nkEmpty:
       # We have a generic type declaration here. In generic types,
       # symbol lookup needs to be done here.
       openScope(c)
       pushOwner(s)
       if s.magic == mNone: s.typ.kind = tyGenericBody
       # XXX for generic type aliases this is not correct! We need the
-      # underlying Id really: 
+      # underlying Id really:
       #
       # type
       #   TGObj[T] = object
       #   TAlias[T] = TGObj[T]
-      # 
+      #
       s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
       a.sons[1] = s.typ.n
       s.typ.size = -1 # could not be computed properly
@@ -639,13 +642,13 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
         s.typ.sons[sonsLen(s.typ) - 1] = body
       popOwner()
       closeScope(c)
-    elif a.sons[2].kind != nkEmpty: 
+    elif a.sons[2].kind != nkEmpty:
       # process the type's body:
       pushOwner(s)
       var t = semTypeNode(c, a.sons[2], s.typ)
-      if s.typ == nil: 
+      if s.typ == nil:
         s.typ = t
-      elif t != s.typ: 
+      elif t != s.typ:
         # this can happen for e.g. tcan_alias_specialised_generic:
         assignType(s.typ, t)
         #debug s.typ
@@ -676,23 +679,23 @@ proc checkForMetaFields(n: PNode) =
   else:
     internalAssert false
 
-proc typeSectionFinalPass(c: PContext, n: PNode) = 
-  for i in countup(0, sonsLen(n) - 1): 
+proc typeSectionFinalPass(c: PContext, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if a.sons[0].kind != nkSym: illFormedAst(a)
     var s = a.sons[0].sym
     # compute the type's size and check for illegal recursions:
-    if a.sons[1].kind == nkEmpty: 
+    if a.sons[1].kind == nkEmpty:
       if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
         # type aliases are hard:
         #MessageOut('for type ' + typeToString(s.typ));
         var t = semTypeNode(c, a.sons[2], nil)
-        if t.kind in {tyObject, tyEnum}: 
+        if t.kind in {tyObject, tyEnum}:
           assignType(s.typ, t)
           s.typ.id = t.id     # same id
       checkConstructedType(s.info, s.typ)
-      if s.typ.kind in {tyObject, tyTuple}:
+      if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
         checkForMetaFields(s.typ.n)
     let aa = a.sons[2]
     if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
@@ -720,21 +723,21 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
     if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
       localError(n.info, errGenerated, "invalid return type: 'stmt'")
 
-proc addParams(c: PContext, n: PNode, kind: TSymKind) = 
-  for i in countup(1, sonsLen(n)-1): 
+proc addParams(c: PContext, n: PNode, kind: TSymKind) =
+  for i in countup(1, sonsLen(n)-1):
     if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
     else: illFormedAst(n)
 
-proc semBorrow(c: PContext, n: PNode, s: PSym) = 
+proc semBorrow(c: PContext, n: PNode, s: PSym) =
   # search for the correct alias:
   var b = searchForBorrowProc(c, c.currentScope.parent, s)
-  if b != nil: 
+  if b != nil:
     # store the alias:
     n.sons[bodyPos] = newSymNode(b)
   else:
-    localError(n.info, errNoSymbolToBorrowFromFound) 
-  
-proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = 
+    localError(n.info, errNoSymbolToBorrowFromFound)
+
+proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
   if t != nil:
     var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
     s.typ = t
@@ -742,7 +745,7 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
     addParamOrResult(c, s, owner)
     c.p.resultSym = s
 
-proc addResultNode(c: PContext, n: PNode) = 
+proc addResultNode(c: PContext, n: PNode) =
   if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
 
 proc copyExcept(n: PNode, i: int): PNode =
@@ -786,7 +789,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
     result = semStmt(c, x)
     # since a proc annotation can set pragmas, we process these here again.
     # This is required for SqueakNim-like export pragmas.
-    if result.kind in procDefs and result[namePos].kind == nkSym and 
+    if result.kind in procDefs and result[namePos].kind == nkSym and
         result[pragmasPos].kind != nkEmpty:
       pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
     return
@@ -808,7 +811,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   pushOwner(s)
   openScope(c)
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty: 
+  if n.sons[genericParamsPos].kind != nkEmpty:
     n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
     gp = n.sons[genericParamsPos]
   else:
@@ -858,13 +861,13 @@ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
 proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   var n = n
-  
+
   n = replaceTypesInBody(c, pt, n)
   result = n
-  
+
   n.sons[genericParamsPos] = emptyNode
   n.sons[paramsPos] = n.typ.n
-  
+
   openScope(c)
   var s = n.sons[namePos].sym
   pushOwner(s)
@@ -877,7 +880,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   popProcCon(c)
   popOwner()
   closeScope(c)
-  
+
   s.ast = result
 
   # alternative variant (not quite working):
@@ -923,7 +926,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         else: break
       if t.kind in {tyObject, tyDistinct, tyEnum}:
         if t.deepCopy.isNil: t.deepCopy = s
-        else: 
+        else:
           localError(n.info, errGenerated,
                      "cannot bind another 'deepCopy' to: " & typeToString(t))
       else:
@@ -990,10 +993,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   pushOwner(s)
   openScope(c)
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty: 
+  if n.sons[genericParamsPos].kind != nkEmpty:
     n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
     gp = n.sons[genericParamsPos]
-  else: 
+  else:
     gp = newNodeI(nkGenericParams, n.info)
   # process parameters:
   if n.sons[paramsPos].kind != nkEmpty:
@@ -1010,7 +1013,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     n.sons[patternPos] = semPattern(c, n.sons[patternPos])
   if s.kind in skIterators:
     s.typ.flags.incl(tfIterator)
-  
+
   var proto = searchForProc(c, s.scope, s)
   if proto == nil:
     if s.kind == skClosureIterator: s.typ.callConv = ccClosure
@@ -1028,14 +1031,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       implicitPragmas(c, s, n, validPragmas)
   else:
-    if n.sons[pragmasPos].kind != nkEmpty: 
+    if n.sons[pragmasPos].kind != nkEmpty:
       localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
-    if sfForward notin proto.flags: 
+    if sfForward notin proto.flags:
       wrongRedefinition(n.info, proto.name.s)
     excl(proto.flags, sfForward)
     closeScope(c)         # close scope with wrong parameter symbols
     openScope(c)          # open scope for old (correct) parameter symbols
-    if proto.ast.sons[genericParamsPos].kind != nkEmpty: 
+    if proto.ast.sons[genericParamsPos].kind != nkEmpty:
       addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
     addParams(c, proto.typ.n, proto.kind)
     proto.info = s.info       # more accurate line information
@@ -1085,7 +1088,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       n.sons[bodyPos] = ast.emptyNode
   else:
     if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
-    if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: 
+    if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
       incl(s.flags, sfForward)
     elif sfBorrow in s.flags: semBorrow(c, n, s)
   sideEffectsCheck(c, s)
@@ -1123,14 +1126,14 @@ proc semIterator(c: PContext, n: PNode): PNode =
   else:
     s.typ.callConv = ccInline
   when false:
-    if s.typ.callConv != ccInline: 
+    if s.typ.callConv != ccInline:
       s.typ.callConv = ccClosure
       # and they always at least use the 'env' for the state field:
       incl(s.typ.flags, tfCapturesEnv)
   if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
     localError(n.info, errImplOfXexpected, s.name.s)
-  
-proc semProc(c: PContext, n: PNode): PNode = 
+
+proc semProc(c: PContext, n: PNode): PNode =
   result = semProcAux(c, n, skProc, procPragmas)
 
 proc hasObjParam(s: PSym): bool =
@@ -1143,10 +1146,10 @@ proc finishMethod(c: PContext, s: PSym) =
   if hasObjParam(s):
     methodDef(s, false)
 
-proc semMethod(c: PContext, n: PNode): PNode = 
+proc semMethod(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
   result = semProcAux(c, n, skMethod, methodPragmas)
-  
+
   var s = result.sons[namePos].sym
   if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
     if hasObjParam(s):
@@ -1154,7 +1157,7 @@ proc semMethod(c: PContext, n: PNode): PNode =
     else:
       localError(n.info, errXNeedsParamObjectType, "method")
 
-proc semConverterDef(c: PContext, n: PNode): PNode = 
+proc semConverterDef(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
   checkSonsLen(n, bodyPos + 1)
   result = semProcAux(c, n, skConverter, converterPragmas)
@@ -1164,7 +1167,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
   if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
   addConverter(c, s)
 
-proc semMacroDef(c: PContext, n: PNode): PNode = 
+proc semMacroDef(c: PContext, n: PNode): PNode =
   checkSonsLen(n, bodyPos + 1)
   result = semProcAux(c, n, skMacro, macroPragmas)
   var s = result.sons[namePos].sym
@@ -1172,23 +1175,23 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
   if n.sons[bodyPos].kind == nkEmpty:
     localError(n.info, errImplOfXexpected, s.name.s)
-  
+
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   addSon(result, n)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var f = checkModuleName(n.sons[i])
     if f != InvalidFileIDX:
-      if containsOrIncl(c.includedFiles, f): 
+      if containsOrIncl(c.includedFiles, f):
         localError(n.info, errRecursiveDependencyX, f.toFilename)
       else:
         addSon(result, semStmt(c, gIncludeFile(c.module, f)))
         excl(c.includedFiles, f)
-  
+
 proc setLine(n: PNode, info: TLineInfo) =
   for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
   n.info = info
-  
+
 proc semPragmaBlock(c: PContext, n: PNode): PNode =
   let pragmaList = n.sons[0]
   pragma(c, nil, pragmaList, exprPragmas)
@@ -1197,7 +1200,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
   for i in 0 .. <pragmaList.len:
     case whichPragma(pragmaList.sons[i])
     of wLine: setLine(result, pragmaList.sons[i].info)
-    of wLocks: 
+    of wLocks:
       result = n
       result.typ = n.sons[1].typ
     else: discard
@@ -1312,8 +1315,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
           inner.addSon(semStmtList(c, rest, flags))
           n.sons.setLen(i+1)
           return
-      of LastBlockStmts: 
-        for j in countup(i + 1, length - 1): 
+      of LastBlockStmts:
+        for j in countup(i + 1, length - 1):
           case n.sons[j].kind
           of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
           else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
@@ -1335,7 +1338,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
         #  "Last expression must be explicitly returned if it " &
         #  "is discardable or discarded")
 
-proc semStmt(c: PContext, n: PNode): PNode = 
+proc semStmt(c: PContext, n: PNode): PNode =
   # now: simply an alias:
   result = semExprNoType(c, n)
 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 0735b76ce..ac0636211 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -345,8 +345,14 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
       localError(n.info, errIdentifierExpected)
       result = errorSym(c, n)
 
-proc semTuple(c: PContext, n: PNode, prev: PType): PType =
-  if n.sonsLen == 0: return newConstraint(c, tyTuple)
+proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
+  if sonsLen(n) == 0:
+    localError(n.info, errTypeExpected)
+  result = newOrPrevType(tyTuple, prev, c)
+  for i in countup(0, sonsLen(n) - 1):
+    addSonSkipIntLit(result, semTypeNode(c, n.sons[i], nil))
+
+proc semTuple(c: PContext, n: PNode, prev: PType): PType = 
   var typ: PType
   result = newOrPrevType(tyTuple, prev, c)
   result.n = newNodeI(nkRecList, n.info)
@@ -1117,9 +1123,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkPar:
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else:
-      # XXX support anon tuple here
-      localError(n.info, errTypeExpected)
-      result = newOrPrevType(tyError, prev, c)
+      result = semAnonTuple(c, n, prev)
   of nkCallKinds:
     if isRange(n):
       result = semRangeAux(c, n, prev)
@@ -1227,6 +1231,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = newOrPrevType(tyError, prev, c)
   of nkObjectTy: result = semObjectNode(c, n, prev)
   of nkTupleTy: result = semTuple(c, n, prev)
+  of nkTupleClassTy: result = newConstraint(c, tyTuple)
   of nkTypeClassTy: result = semTypeClass(c, n, prev)
   of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
   of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 57aa6305e..012782730 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -341,6 +341,8 @@ proc skipIntLiteralParams*(t: PType) =
 proc propagateFieldFlags(t: PType, n: PNode) =
   # This is meant for objects and tuples
   # The type must be fully instantiated!
+  if n.isNil:
+    return
   internalAssert n.kind != nkRecWhen
   case n.kind
   of nkSym:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index a1b5c8dc9..f1fd84326 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -10,7 +10,7 @@
 ## This module implements the signature matching for resolving
 ## the call to overloaded procs, generic procs and operators.
 
-import 
+import
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
   nimfix.pretty
@@ -19,7 +19,7 @@ when not defined(noDocgen):
   import docgen
 
 type
-  TCandidateState* = enum 
+  TCandidateState* = enum
     csEmpty, csMatch, csNoMatch
 
   CandidateErrors* = seq[PSym]
@@ -62,10 +62,10 @@ type
     isGeneric,
     isFromIntLit,            # conversion *from* int literal; proven safe
     isEqual
-  
+
 const
   isNilConversion = isConvertible # maybe 'isIntConv' fits better?
-    
+
 proc markUsed*(info: TLineInfo, s: PSym)
 
 template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
@@ -128,7 +128,7 @@ proc newCandidate*(ctx: PContext, callee: PSym,
 proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
   initCandidate(ctx, result, callee)
 
-proc copyCandidate(a: var TCandidate, b: TCandidate) = 
+proc copyCandidate(a: var TCandidate, b: TCandidate) =
   a.c = b.c
   a.exactMatches = b.exactMatches
   a.subtypeMatches = b.subtypeMatches
@@ -157,17 +157,40 @@ proc sumGeneric(t: PType): int =
       result = ord(t.kind == tyGenericInvocation)
       for i in 0 .. <t.len: result += t.sons[i].sumGeneric
       break
-    of tyProc:
-      # proc matches proc better than 'stmt' to disambiguate 'spawn'
-      return 1
     of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
+    of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
+        tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
+        tyUInt..tyUInt64:
+      return 1
     else: return 0
 
+#var ggDebug: bool
+
 proc complexDisambiguation(a, b: PType): int =
-  var x, y: int
-  for i in 1 .. <a.len: x += a.sons[i].sumGeneric
-  for i in 1 .. <b.len: y += b.sons[i].sumGeneric
-  result = x - y
+  # 'a' matches better if *every* argument matches better or equal than 'b'.
+  var winner = 0
+  for i in 1 .. <min(a.len, b.len):
+    let x = a.sons[i].sumGeneric
+    let y = b.sons[i].sumGeneric
+    #if ggDebug:
+    #  echo "came her ", typeToString(a.sons[i]), " ", typeToString(b.sons[i])
+    if x != y:
+      if winner == 0:
+        if x > y: winner = 1
+        else: winner = -1
+      elif x > y:
+        if winner != 1:
+          # contradiction
+          return 0
+      else:
+        if winner != -1:
+          return 0
+  result = winner
+  when false:
+    var x, y: int
+    for i in 1 .. <a.len: x += a.sons[i].sumGeneric
+    for i in 1 .. <b.len: y += b.sons[i].sumGeneric
+    result = x - y
   when false:
     proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
 
@@ -176,7 +199,7 @@ proc complexDisambiguation(a, b: PType): int =
       let bb = b.sons[1].sumGeneric
       var a = a
       var b = b
-      
+
       if aa < bb: swap(a, b)
       # all must be better
       for i in 2 .. <min(a.len, b.len):
@@ -203,7 +226,7 @@ proc cmpCandidates*(a, b: TCandidate): int =
   # prefer more specialized generic over more general generic:
   result = complexDisambiguation(a.callee, b.callee)
 
-proc writeMatches*(c: TCandidate) = 
+proc writeMatches*(c: TCandidate) =
   writeln(stdout, "exact matches: " & $c.exactMatches)
   writeln(stdout, "generic matches: " & $c.genericMatches)
   writeln(stdout, "subtype matches: " & $c.subtypeMatches)
@@ -225,7 +248,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
   result = ""
   for i in countup(startIdx, n.len - 1):
     var arg = n.sons[i]
-    if n.sons[i].kind == nkExprEqExpr: 
+    if n.sons[i].kind == nkExprEqExpr:
       add(result, renderTree(n.sons[i].sons[0]))
       add(result, ": ")
       if arg.typ.isNil:
@@ -241,9 +264,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
     if i != sonsLen(n) - 1: add(result, ", ")
 
 proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
-proc concreteType(c: TCandidate, t: PType): PType = 
+proc concreteType(c: TCandidate, t: PType): PType =
   case t.kind
-  of tyArrayConstr: 
+  of tyArrayConstr:
     # make it an array
     result = newType(tyArray, t.owner)
     addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID!
@@ -255,7 +278,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
     else: result = t
   of tyGenericParam, tyAnything:
     result = t
-    while true: 
+    while true:
       result = PType(idTableGet(c.bindings, t))
       if result == nil:
         break # it's ok, no match
@@ -267,15 +290,15 @@ proc concreteType(c: TCandidate, t: PType): PType =
     result = t
   else:
     result = t                # Note: empty is valid here
-  
-proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = 
-  if a.kind == f.kind: 
+
+proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
+  if a.kind == f.kind:
     result = isEqual
   else:
     let ab = skipTypes(a, {tyRange})
     let k = ab.kind
     if k == f.kind: result = isSubrange
-    elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, 
+    elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
                                    tyUInt..tyUInt64} and
         isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
                          ab.n.intVal <= lastOrd(f):
@@ -286,7 +309,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
       result = isIntConv
     elif k >= min and k <= max:
       result = isConvertible
-    elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64, 
+    elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
                                                   tyUInt8..tyUInt32} and
                          a.n[0].intVal >= firstOrd(f) and
                          a.n[1].intVal <= lastOrd(f):
@@ -318,12 +341,12 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
       if f.kind == tyFloat32: result = isConvertible
       else: result = isIntConv
     else: result = isNone
-  
+
 proc isObjectSubtype(a, f: PType): int =
   var t = a
   assert t.kind == tyObject
   var depth = 0
-  while t != nil and not sameObjectTypes(f, t): 
+  while t != nil and not sameObjectTypes(f, t):
     assert t.kind == tyObject
     t = t.sons[0]
     if t == nil: break
@@ -332,17 +355,18 @@ proc isObjectSubtype(a, f: PType): int =
   if t != nil:
     result = depth
 
-proc minRel(a, b: TTypeRelation): TTypeRelation = 
+proc minRel(a, b: TTypeRelation): TTypeRelation =
   if a <= b: result = a
   else: result = b
-  
+
 proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
   result = isNone
-  if sameType(f, a): result = isEqual
+  if sameType(f, a):
+    result = isEqual
   elif sonsLen(a) == sonsLen(f):
     result = isEqual
     let firstField = if f.kind == tyTuple: 0
-                     else: 1 
+                     else: 1
     for i in countup(firstField, sonsLen(f) - 1):
       var m = typeRel(c, f.sons[i], a.sons[i])
       if m < isSubtype: return isNone
@@ -373,32 +397,32 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
       # We are matching a generic proc (as proc param)
       # to another generic type appearing in the proc
       # signature. There is a change that the target
-      # type is already fully-determined, so we are 
+      # type is already fully-determined, so we are
       # going to try resolve it
       f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
       if f == nil or f.isMetaType:
         # no luck resolving the type, so the inference fails
         return isNone
     let reverseRel = typeRel(c, a, f)
-    if reverseRel == isGeneric:
+    if reverseRel >= isGeneric:
       result = isInferred
-      inc c.genericMatches
+      #inc c.genericMatches
   else:
     result = typeRel(c, f, a)
 
   if result <= isSubtype or inconsistentVarTypes(f, a):
     result = isNone
- 
-  if result == isEqual:
-    inc c.exactMatches
-    
+
+  #if result == isEqual:
+  #  inc c.exactMatches
+
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   case a.kind
   of tyProc:
     if sonsLen(f) != sonsLen(a): return
     result = isEqual      # start with maximum; also correct for no
                           # params at all
-    
+
     template checkParam(f, a) =
       result = minRel(result, procParamTypeRel(c, f, a))
       if result == isNone: return
@@ -407,7 +431,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     # return type!
     for i in 1 .. <f.sonsLen:
       checkParam(f.sons[i], a.sons[i])
-    
+
     if f.sons[0] != nil:
       if a.sons[0] != nil:
         checkParam(f.sons[0], a.sons[0])
@@ -433,6 +457,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         return isNone
     when useEffectSystem:
       if not compatibleEffects(f, a): return isNone
+
   of tyNil:
     result = f.allowsNil
   of tyIter:
@@ -487,14 +512,14 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
       else:
         param = paramSym skType
         param.typ = makeTypeDesc(c, typ)
-      
+
       addDecl(c, param)
 
   for param in body.n[0]:
     var
       dummyName: PNode
       dummyType: PType
-    
+
     if param.kind == nkVarTy:
       dummyName = param[0]
       dummyType = if a.kind != tyVar: makeVarType(c, a)
@@ -520,7 +545,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
       of nkTypeSection: discard
       of nkConstDef: discard
       else: discard
-    
+
   return isGeneric
 
 proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
@@ -554,7 +579,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # typeRel can be used to establish various relationships between types:
   #
   # 1) When used with concrete types, it will check for type equivalence
-  # or a subtype relationship. 
+  # or a subtype relationship.
   #
   # 2) When used with a concrete type against a type class (such as generic
   # signature of a proc), it will check whether the concrete type is a member
@@ -569,7 +594,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   result = isNone
   assert(f != nil)
-  
+
   if f.kind == tyExpr:
     if aOrig != nil: put(c.bindings, f, aOrig)
     return isGeneric
@@ -582,7 +607,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # start the param matching process. This could be done in `prepareOperand`
   # for example, but unfortunately `prepareOperand` is not called in certain
   # situation when nkDotExpr are rotated to nkDotCalls
-  
+
   if a.kind == tyGenericInst and
       skipTypes(f, {tyVar}).kind notin {
         tyGenericBody, tyGenericInvocation,
@@ -590,10 +615,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     return typeRel(c, f, lastSon(a))
 
   template bindingRet(res) =
-    when res == isGeneric:
-      if doBind:
-        let bound = aOrig.skipTypes({tyRange}).skipIntLit
-        if doBind: put(c.bindings, f, bound)
+    if doBind:
+      let bound = aOrig.skipTypes({tyRange}).skipIntLit
+      if doBind: put(c.bindings, f, bound)
     return res
 
   template considerPreviousT(body: stmt) {.immediate.} =
@@ -605,20 +629,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyOr:
     # seq[int|string] vs seq[number]
     # both int and string must match against number
+    # but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
+    result = isGeneric
     for branch in a.sons:
-      if typeRel(c, f, branch, false) == isNone:
-        return isNone
-
-    return isGeneric
+      let x = typeRel(c, f, branch, false)
+      if x == isNone: return isNone
+      if x < result: result = x
 
   of tyAnd:
     # seq[Sortable and Iterable] vs seq[Sortable]
     # only one match is enough
     for branch in a.sons:
-      if typeRel(c, f, branch, false) != isNone:
-        return isGeneric
-
-    return isNone
+      let x = typeRel(c, f, branch, false)
+      if x != isNone:
+        return if x >= isGeneric: isGeneric else: x
+    result = isNone
 
   of tyNot:
     case f.kind
@@ -626,9 +651,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       # seq[!int] vs seq[!number]
       # seq[float] matches the first, but not the second
       # we must turn the problem around:
-      # is number a subset of int? 
+      # is number a subset of int?
       return typeRel(c, a.lastSon, f.lastSon)
- 
+
     else:
       # negative type classes are essentially infinite,
       # so only the `any` type class is their superset
@@ -727,20 +752,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     of tyOpenArray, tyVarargs:
       result = typeRel(c, base(f), base(a))
       if result < isGeneric: result = isNone
-    of tyArrayConstr: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
+    of tyArrayConstr:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
         result = isSubtype    # [] is allowed here
-      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
         result = isSubtype
-    of tyArray: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
+    of tyArray:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
         result = isSubtype
-      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
         result = isConvertible
-    of tySequence: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
+    of tySequence:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
         result = isConvertible
-      elif typeRel(c, base(f), a.sons[0]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
         result = isConvertible
     else: discard
   of tySequence:
@@ -768,7 +793,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyForward: internalError("forward type in typeRel()")
   of tyNil:
     if a.kind == f.kind: result = isEqual
-  of tyTuple: 
+  of tyTuple:
     if a.kind == tyTuple: result = recordRel(c, f, a)
   of tyObject:
     if a.kind == tyObject:
@@ -781,15 +806,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
           inc(c.inheritancePenalty, depth)
           result = isSubtype
   of tyDistinct:
-    if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
+    if a.kind == tyDistinct and sameDistinctTypes(f, a): result = isEqual
     elif c.coerceDistincts: result = typeRel(c, f.base, a)
-  of tySet: 
-    if a.kind == tySet: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
+  of tySet:
+    if a.kind == tySet:
+      if f.sons[0].kind != tyGenericParam and a.sons[0].kind == tyEmpty:
         result = isSubtype
-      else: 
+      else:
         result = typeRel(c, f.sons[0], a.sons[0])
-        if result <= isConvertible: 
+        if result <= isConvertible:
           result = isNone     # BUGFIX!
   of tyPtr, tyRef:
     if a.kind == f.kind:
@@ -823,9 +848,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       if a.len == 1: result = isConvertible
     of tyCString: result = isConvertible
     else: discard
-  of tyString: 
+  of tyString:
     case a.kind
-    of tyString: 
+    of tyString:
       if tfNotNil in f.flags and tfNotNil notin a.flags:
         result = isNilConversion
       else:
@@ -848,7 +873,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     of tyArray:
       if (firstOrd(a.sons[0]) == 0) and
           (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
-          (a.sons[1].kind == tyChar): 
+          (a.sons[1].kind == tyChar):
         result = isConvertible
     else: discard
 
@@ -863,9 +888,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         let ff = rootf.sons[i]
         let aa = roota.sons[i]
         result = typeRel(c, ff, aa)
-        if result == isNone: return        
+        if result == isNone: return
         if ff.kind == tyRange and result != isEqual: return isNone
-      result = isGeneric
+      #result = isGeneric
       # XXX See bug #2220. A[int] should match A[int] better than some generic X
     else:
       result = typeRel(c, lastSon(f), a)
@@ -883,13 +908,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
       # simply no match for now:
       discard
-    elif x.kind == tyGenericInst and 
+    elif x.kind == tyGenericInst and
           (f.sons[0] == x.sons[0]) and
           (sonsLen(x) - 1 == sonsLen(f)):
       for i in countup(1, sonsLen(f) - 1):
         if x.sons[i].kind == tyGenericParam:
           internalError("wrong instantiated type!")
-        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return 
+        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
       result = isGeneric
     else:
       result = typeRel(c, f.sons[0], x)
@@ -900,29 +925,34 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
           if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}:
             internalError("wrong instantiated type!")
           put(c.bindings, f.sons[i], x)
-  
+
   of tyAnd:
     considerPreviousT:
       for branch in f.sons:
-        if typeRel(c, branch, aOrig) < isSubtype:
-          return isNone
-
-      bindingRet isGeneric
+        let x = typeRel(c, branch, aOrig)
+        if x < isSubtype: return isNone
+        # 'and' implies minimum matching result:
+        if x < result: result = x
+      bindingRet result
 
   of tyOr:
     considerPreviousT:
+      result = isNone
       for branch in f.sons:
-        if typeRel(c, branch, aOrig) >= isSubtype:
-          bindingRet isGeneric
-       
-      return isNone
+        let x = typeRel(c, branch, aOrig)
+        # 'or' implies maximum matching result:
+        if x > result: result = x
+      if result >= isSubtype:
+        bindingRet result
+      else:
+        result = isNone
 
   of tyNot:
     considerPreviousT:
       for branch in f.sons:
         if typeRel(c, branch, aOrig) != isNone:
           return isNone
-      
+
       bindingRet isGeneric
 
   of tyAnything:
@@ -961,7 +991,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     if x == nil:
       if c.callee.kind == tyGenericBody and
          f.kind == tyGenericParam and not c.typedescMatched:
-        # XXX: The fact that generic types currently use tyGenericParam for 
+        # XXX: The fact that generic types currently use tyGenericParam for
         # their parameters is really a misnomer. tyGenericParam means "match
         # any value" and what we need is "match any type", which can be encoded
         # by a tyTypeDesc params. Unfortunately, this requires more substantial
@@ -975,6 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
             internalAssert a.sons != nil and a.sons.len > 0
             c.typedescMatched = true
             result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
+            if result > isGeneric: result = isGeneric
         else:
           result = isNone
       else:
@@ -998,13 +1029,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
             return isNone
         if doBind:
           put(c.bindings, f, concrete)
+      elif result > isGeneric:
+        result = isGeneric
     elif a.kind == tyEmpty:
       result = isGeneric
     elif x.kind == tyGenericParam:
       result = isGeneric
     else:
       result = typeRel(c, x, a) # check if it fits
-  
+      if result > isGeneric: result = isGeneric
+
   of tyStatic:
     let prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
@@ -1034,12 +1068,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       # when `f` is an unresolved typedesc, `a` could be any
       # type, so we should not perform this check earlier
       if a.kind != tyTypeDesc: return isNone
-    
+
       if f.base.kind == tyNone:
         result = isGeneric
       else:
         result = typeRel(c, f.base, a.base)
-      
+
       if result != isNone:
         put(c.bindings, f, a)
     else:
@@ -1049,9 +1083,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         result = typeRel(c, prev.base, a.base)
       else:
         result = isNone
- 
+
   of tyIter:
-    if a.kind == tyIter or 
+    if a.kind == tyIter or
       (a.kind == tyProc and tfIterator in a.flags):
       result = typeRel(c, f.base, a.base)
     else:
@@ -1059,7 +1093,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   of tyStmt:
     result = isGeneric
-  
+
   of tyProxy:
     result = isEqual
 
@@ -1078,11 +1112,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     else:
       localError(f.n.info, errTypeExpected)
       result = isNone
-  
+
   else:
     internalAssert false
-  
-proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = 
+
+proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
   var m: TCandidate
   initCandidate(c, m, f)
   result = typeRel(m, f, a)
@@ -1095,9 +1129,9 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
   if result == nil:
     internalError(arg.info, "getInstantiatedType")
     result = errorType(c)
-  
-proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, 
-                  c: PContext): PNode = 
+
+proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
+                  c: PContext): PNode =
   result = newNodeI(kind, arg.info)
   if containsGenericType(f):
     if not m.hasFauxMatch:
@@ -1110,10 +1144,10 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
   addSon(result, ast.emptyNode)
   addSon(result, arg)
 
-proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, 
-                   arg: PNode): PNode = 
+proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                   arg: PNode): PNode =
   result = nil
-  for i in countup(0, len(c.converters) - 1): 
+  for i in countup(0, len(c.converters) - 1):
     var src = c.converters[i].typ.sons[1]
     var dest = c.converters[i].typ.sons[0]
     # for generic type converters we need to check 'src <- a' before
@@ -1121,12 +1155,12 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
     # see tests/tgenericconverter:
     let srca = typeRel(m, src, a)
     if srca notin {isEqual, isGeneric}: continue
-    
+
     let destIsGeneric = containsGenericType(dest)
     if destIsGeneric:
       dest = generateTypeInstance(c, m.bindings, arg, dest)
     let fdest = typeRel(m, f, dest)
-    if fdest in {isEqual, isGeneric}: 
+    if fdest in {isEqual, isGeneric}:
       markUsed(arg.info, c.converters[i])
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
@@ -1138,8 +1172,8 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       m.genericConverter = srca == isGeneric or destIsGeneric
       return result
 
-proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, 
-                    arg: PNode): PNode = 
+proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                    arg: PNode): PNode =
   # arg.typ can be nil in 'suggest':
   if isNil(arg.typ): return nil
 
@@ -1181,12 +1215,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     arg = argSemantized
     argType = argType
     c = m.c
-  
+
   if tfHasStatic in fMaybeStatic.flags:
     # XXX: When implicit statics are the default
     # this will be done earlier - we just have to
     # make sure that static types enter here
-     
+
     # XXX: weaken tyGenericParam and call it tyGenericPlaceholder
     # and finally start using tyTypedesc for generic types properly.
     if argType.kind == tyGenericParam and tfWildcard in argType.flags:
@@ -1205,11 +1239,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
         arg.typ.sons = @[evaluated.typ]
         arg.typ.n = evaluated
         argType = arg.typ
- 
+
   var
     a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
         else: argType
- 
+
     r = typeRel(m, f, a)
 
   if r != isNone and m.calleeSym != nil and
@@ -1220,8 +1254,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     of isConvertible, isIntConv: inc(m.convMatches)
     of isSubtype, isSubrange: inc(m.subtypeMatches)
     of isGeneric, isInferred: inc(m.genericMatches)
-    of isInferredConvertible: inc(m.genericMatches); inc(m.convMatches)
     of isFromIntLit: inc(m.intConvMatches, 256)
+    of isInferredConvertible:
+      inc(m.convMatches)
     of isEqual: inc(m.exactMatches)
     of isNone: discard
 
@@ -1232,7 +1267,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     elif f.kind == tyStatic:
       return arg.typ.n
     else:
-      return argOrig
+      return argSemantized # argOrig
 
   if r != isNone and f.isInlineIterator:
     var inlined = newTypeS(tyStatic, c)
@@ -1244,21 +1279,22 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
   case r
   of isConvertible:
     inc(m.convMatches)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isIntConv:
     # I'm too lazy to introduce another ``*matches`` field, so we conflate
     # ``isIntConv`` and ``isIntLit`` here:
     inc(m.intConvMatches)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-  of isSubtype: 
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isSubtype:
     inc(m.subtypeMatches)
-    result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
+    result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isSubrange:
     inc(m.subtypeMatches)
-    #result = copyTree(arg)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    if f.kind == tyVar:
+      result = arg
+    else:
+      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isInferred, isInferredConvertible:
-    inc(m.genericMatches)
     if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
       result = c.semInferredLambda(c, m.bindings, arg)
     else:
@@ -1267,44 +1303,36 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     if r == isInferredConvertible:
       inc(m.convMatches)
       result = implicitConv(nkHiddenStdConv, f, result, m, c)
+    else:
+      inc(m.genericMatches)
   of isGeneric:
     inc(m.genericMatches)
-    when true:
-      if arg.typ == nil:
-        result = arg
-      elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
-        result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-      elif arg.typ.isEmptyContainer:
-        result = arg.copyTree
-        result.typ = getInstantiatedType(c, arg, m, f)
-      else:
-        result = arg
-    else:
-      # XXX Why is this ever necessary? arg's type should not be retrofitted
-      # to match formal's type in this way!
-      result = copyTree(arg)
+    if arg.typ == nil:
+      result = arg
+    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
+      result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    elif arg.typ.isEmptyContainer:
+      result = arg.copyTree
       result.typ = getInstantiatedType(c, arg, m, f)
-      # BUG: f may not be the right key!
-      if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
-        result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-        # BUGFIX: use ``result.typ`` and not `f` here
+    else:
+      result = arg
   of isFromIntLit:
     # too lazy to introduce another ``*matches`` field, so we conflate
     # ``isIntConv`` and ``isIntLit`` here:
     inc(m.intConvMatches, 256)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-  of isEqual: 
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isEqual:
     inc(m.exactMatches)
-    result = copyTree(arg)
+    result = arg
     if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
-      result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isNone:
     # do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
     if a.kind in {tyProxy, tyUnknown}:
       inc(m.genericMatches)
       m.fauxMatch = a.kind
-      return copyTree(arg)
-    result = userConvMatch(c, m, f, a, arg) 
+      return arg
+    result = userConvMatch(c, m, f, a, arg)
     # check for a base type match, which supports varargs[T] without []
     # constructor in a call:
     if result == nil and f.kind == tyVarargs:
@@ -1325,7 +1353,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
                       arg, argOrig: PNode): PNode =
   if arg == nil or arg.kind notin nkSymChoices:
     result = paramTypesMatchAux(m, f, a, arg, argOrig)
-  else: 
+  else:
     # CAUTION: The order depends on the used hashing scheme. Thus it is
     # incorrect to simply use the first fitting match. However, to implement
     # this correctly is inefficient. We have to copy `m` here to be able to
@@ -1339,28 +1367,37 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     y.calleeSym = m.calleeSym
     z.calleeSym = m.calleeSym
     var best = -1
-    for i in countup(0, sonsLen(arg) - 1): 
+    for i in countup(0, sonsLen(arg) - 1):
       if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
         copyCandidate(z, m)
+        z.callee = arg.sons[i].typ
+        z.calleeSym = arg.sons[i].sym
+        #if arg.sons[i].sym.name.s == "cmp":
+        #  ggDebug = true
+        #  echo "CALLLEEEEEEEE ", typeToString(z.callee)
         var r = typeRel(z, f, arg.sons[i].typ)
-        if r != isNone: 
+        #if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606:
+        #  echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ)
+        #  debug arg.sons[i].sym
+        #  writeMatches(z)
+        if r != isNone:
           case x.state
-          of csEmpty, csNoMatch: 
+          of csEmpty, csNoMatch:
             x = z
             best = i
             x.state = csMatch
-          of csMatch: 
+          of csMatch:
             var cmp = cmpCandidates(x, z)
             if cmp < 0:
               best = i
               x = z
             elif cmp == 0:
               y = z           # z is as good as x
-    if x.state == csEmpty: 
+    if x.state == csEmpty:
       result = nil
-    elif y.state == csMatch and cmpCandidates(x, y) == 0: 
-      if x.state != csMatch: 
-        internalError(arg.info, "x.state is not csMatch") 
+    elif y.state == csMatch and cmpCandidates(x, y) == 0:
+      if x.state != csMatch:
+        internalError(arg.info, "x.state is not csMatch")
       # ambiguous: more than one symbol fits!
       # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
       # anyway:
@@ -1373,7 +1410,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
 
-proc setSon(father: PNode, at: int, son: PNode) = 
+proc setSon(father: PNode, at: int, son: PNode) =
   if sonsLen(father) <= at: setLen(father.sons, at + 1)
   father.sons[at] = son
 
@@ -1417,7 +1454,7 @@ proc incrIndexType(t: PType) =
   inc t.sons[0].n.sons[1].intVal
 
 proc matchesAux(c: PContext, n, nOrig: PNode,
-                m: var TCandidate, marker: var IntSet) = 
+                m: var TCandidate, marker: var IntSet) =
   template checkConstraint(n: expr) {.immediate, dirty.} =
     if not formal.constraint.isNil:
       if matchNodeKinds(formal.constraint, n):
@@ -1447,20 +1484,20 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       # named param
       # check if m.callee has such a param:
       prepareNamedParam(n.sons[a])
-      if n.sons[a].sons[0].kind != nkIdent: 
+      if n.sons[a].sons[0].kind != nkIdent:
         localError(n.sons[a].info, errNamedParamHasToBeIdent)
         m.state = csNoMatch
-        return 
+        return
       formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
-      if formal == nil: 
+      if formal == nil:
         # no error message!
         m.state = csNoMatch
-        return 
-      if containsOrIncl(marker, formal.position): 
+        return
+      if containsOrIncl(marker, formal.position):
         # already in namedParams:
         localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
         m.state = csNoMatch
-        return 
+        return
       m.baseTypeMatch = false
       n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
       n.sons[a].typ = n.sons[a].sons[1].typ
@@ -1470,7 +1507,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         m.state = csNoMatch
         return
       checkConstraint(n.sons[a].sons[1])
-      if m.baseTypeMatch: 
+      if m.baseTypeMatch:
         #assert(container == nil)
         container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
         addSon(container, arg)
@@ -1507,7 +1544,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.state = csNoMatch
           return
       else:
-        if m.callee.n.sons[f].kind != nkSym: 
+        if m.callee.n.sons[f].kind != nkSym:
           internalError(n.sons[a].info, "matches")
           return
         formal = m.callee.n.sons[f].sym
@@ -1515,7 +1552,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           # already in namedParams:
           localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
           m.state = csNoMatch
-          return 
+          return
         m.baseTypeMatch = false
         n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
         var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
@@ -1528,7 +1565,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           if container.isNil:
             container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
           addSon(container, arg)
-          setSon(m.call, formal.position + 1, 
+          setSon(m.call, formal.position + 1,
                  implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
           #if f != formalLen - 1: container = nil
 
@@ -1603,7 +1640,7 @@ when not declared(tests):
 
 tests:
   var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
-  
+
   proc `|` (t1, t2: PType): PType =
     result = newType(tyOr, dummyOwner)
     result.rawAddSon(t1)
@@ -1624,12 +1661,12 @@ tests:
 
   proc array(x: int, t: PType): PType =
     result = newType(tyArray, dummyOwner)
-    
+
     var n = newNodeI(nkRange, UnknownLineInfo())
     addSon(n, newIntNode(nkIntLit, 0))
     addSon(n, newIntNode(nkIntLit, x))
     let range = newType(tyRange, dummyOwner)
-    
+
     result.rawAddSon(range)
     result.rawAddSon(t)
 
@@ -1655,7 +1692,7 @@ tests:
 
     setup:
       var c: TCandidate
-      InitCandidate(nil, c, nil)
+      initCandidate(nil, c, nil)
 
     template yes(x, y) =
       test astToStr(x) & " is " & astToStr(y):
@@ -1664,7 +1701,7 @@ tests:
     template no(x, y) =
       test astToStr(x) & " is not " & astToStr(y):
         check typeRel(c, y, x) == isNone
-    
+
     yes seq(any), array(10, int) | seq(any)
     # Sure, seq[any] is directly included
 
@@ -1672,16 +1709,16 @@ tests:
     yes seq(int), seq(number)
     # Sure, the int sequence is certainly
     # part of the number sequences (and all sequences)
-    
+
     no seq(any), seq(float)
     # Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
 
     yes seq(int|string), seq(any)
     # Sure
- 
+
     yes seq(int&string), seq(any)
     # Again
-    
+
     yes seq(int&string), seq(int)
     # A bit more complicated
     # seq[int&string] is not a real type, but it's analogous to
@@ -1690,23 +1727,23 @@ tests:
     no seq(int|string), seq(int|float)
     # Nope, seq[string] is not included in not included in
     # the seq[int|float] set
-    
+
     no seq(!(int|string)), seq(string)
     # A sequence that is neither seq[int] or seq[string]
     # is obviously not seq[string]
-     
+
     no seq(!int), seq(number)
     # Now your head should start to hurt a bit
     # A sequence that is not seq[int] is not necessarily a number sequence
     # it could well be seq[string] for example
-    
+
     yes seq(!(int|string)), seq(!string)
     # all sequnece types besides seq[int] and seq[string]
     # are subset of all sequence types that are not seq[string]
 
     no seq(!(int|string)), seq(!(string|TFoo))
     # Nope, seq[TFoo] is included in the first set, but not in the second
-    
+
     no seq(!string), seq(!number)
     # Nope, seq[int] in included in the first set, but not in the second
 
@@ -1714,7 +1751,7 @@ tests:
     yes seq(!int), seq(any)
     no seq(any), seq(!any)
     no seq(!int), seq(!any)
-    
+
     yes int, ordinal
     no  string, ordinal
 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 2f520aa20..325ce9d5e 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -17,27 +17,27 @@
 # * introduces method dispatchers
 # * performs lambda lifting for closure support
 
-import 
-  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, 
+import
+  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
   idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
   lambdalifting, sempass2, lowerings
 
 # implementation
 
-type 
+type
   PTransNode* = distinct PNode
-  
+
   PTransCon = ref TTransCon
   TTransCon{.final.} = object # part of TContext; stackable
     mapping: TIdNodeTable     # mapping from symbols to nodes
     owner: PSym               # current owner
     forStmt: PNode            # current for stmt
-    forLoopBody: PTransNode   # transformed for loop body 
-    yieldStmts: int           # we count the number of yield statements, 
+    forLoopBody: PTransNode   # transformed for loop body
+    yieldStmts: int           # we count the number of yield statements,
                               # because we need to introduce new variables
                               # if we encounter the 2nd yield statement
     next: PTransCon           # for stacking
-  
+
   TTransfContext = object of passes.TPassContext
     module: PSym
     transCon: PTransCon      # top of a TransCon stack
@@ -46,52 +46,52 @@ type
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
   PTransf = ref TTransfContext
 
-proc newTransNode(a: PNode): PTransNode {.inline.} = 
+proc newTransNode(a: PNode): PTransNode {.inline.} =
   result = PTransNode(shallowCopy(a))
 
-proc newTransNode(kind: TNodeKind, info: TLineInfo, 
-                  sons: int): PTransNode {.inline.} = 
+proc newTransNode(kind: TNodeKind, info: TLineInfo,
+                  sons: int): PTransNode {.inline.} =
   var x = newNodeI(kind, info)
   newSeq(x.sons, sons)
   result = x.PTransNode
 
-proc newTransNode(kind: TNodeKind, n: PNode, 
-                  sons: int): PTransNode {.inline.} = 
+proc newTransNode(kind: TNodeKind, n: PNode,
+                  sons: int): PTransNode {.inline.} =
   var x = newNodeIT(kind, n.info, n.typ)
   newSeq(x.sons, sons)
   x.typ = n.typ
   result = x.PTransNode
 
-proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} = 
+proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
   var n = PNode(a)
   n.sons[i] = PNode(x)
 
-proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} = 
+proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
   var n = PNode(a)
   result = n.sons[i].PTransNode
-  
+
 proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
 proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
 
-proc newTransCon(owner: PSym): PTransCon = 
+proc newTransCon(owner: PSym): PTransCon =
   assert owner != nil
   new(result)
   initIdNodeTable(result.mapping)
   result.owner = owner
 
-proc pushTransCon(c: PTransf, t: PTransCon) = 
+proc pushTransCon(c: PTransf, t: PTransCon) =
   t.next = c.transCon
   c.transCon = t
 
-proc popTransCon(c: PTransf) = 
+proc popTransCon(c: PTransf) =
   if (c.transCon == nil): internalError("popTransCon")
   c.transCon = c.transCon.next
 
-proc getCurrOwner(c: PTransf): PSym = 
+proc getCurrOwner(c: PTransf): PSym =
   if c.transCon != nil: result = c.transCon.owner
   else: result = c.module
-  
-proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym = 
+
+proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
   result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
   result.typ = skipTypes(typ, {tyGenericInst})
   incl(result.flags, sfFromGeneric)
@@ -100,10 +100,10 @@ proc transform(c: PTransf, n: PNode): PTransNode
 
 proc transformSons(c: PTransf, n: PNode): PTransNode =
   result = newTransNode(n)
-  for i in countup(0, sonsLen(n)-1): 
+  for i in countup(0, sonsLen(n)-1):
     result[i] = transform(c, n.sons[i])
 
-proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = 
+proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
   result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
   result[0] = PTransNode(le)
   result[1] = ri
@@ -113,30 +113,30 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   #  return liftIterSym(n)
   var b: PNode
   var tc = c.transCon
-  if sfBorrow in n.sym.flags: 
+  if sfBorrow in n.sym.flags:
     # simply exchange the symbol:
     b = n.sym.getBody
     if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
     b = newSymNode(b.sym)
     b.info = n.info
-  else: 
+  else:
     b = n
-  while tc != nil: 
+  while tc != nil:
     result = idNodeTableGet(tc.mapping, b.sym)
     if result != nil: return
     tc = tc.next
   result = b
 
-proc transformSym(c: PTransf, n: PNode): PTransNode = 
+proc transformSym(c: PTransf, n: PNode): PTransNode =
   result = PTransNode(transformSymAux(c, n))
 
 proc transformVarSection(c: PTransf, v: PNode): PTransNode =
   result = newTransNode(v)
   for i in countup(0, sonsLen(v)-1):
     var it = v.sons[i]
-    if it.kind == nkCommentStmt: 
+    if it.kind == nkCommentStmt:
       result[i] = PTransNode(it)
-    elif it.kind == nkIdentDefs: 
+    elif it.kind == nkIdentDefs:
       if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
       internalAssert(it.len == 3)
       var newVar = copySym(it.sons[0].sym)
@@ -152,13 +152,14 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
       defs[0] = newSymNode(newVar).PTransNode
       defs[1] = it.sons[1].PTransNode
       defs[2] = transform(c, it.sons[2])
+      newVar.ast = defs[2].PNode
       result[i] = defs
-    else: 
-      if it.kind != nkVarTuple: 
+    else:
+      if it.kind != nkVarTuple:
         internalError(it.info, "transformVarSection: not nkVarTuple")
       var L = sonsLen(it)
       var defs = newTransNode(it.kind, it.info, L)
-      for j in countup(0, L-3): 
+      for j in countup(0, L-3):
         var newVar = copySym(it.sons[j].sym)
         incl(newVar.flags, sfFromGeneric)
         newVar.owner = getCurrOwner(c)
@@ -188,12 +189,12 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
       else:
         result[i] = PTransNode(it)
 
-proc hasContinue(n: PNode): bool = 
+proc hasContinue(n: PNode): bool =
   case n.kind
   of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
   of nkContinueStmt: result = true
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
+  else:
+    for i in countup(0, sonsLen(n) - 1):
       if hasContinue(n.sons[i]): return true
 
 proc newLabel(c: PTransf, n: PNode): PSym =
@@ -224,10 +225,10 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
   discard c.breakSyms.pop
   result[0] = newSymNode(labl).PTransNode
 
-proc transformLoopBody(c: PTransf, n: PNode): PTransNode =  
-  # What if it contains "continue" and "break"? "break" needs 
+proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
+  # What if it contains "continue" and "break"? "break" needs
   # an explicit label too, but not the same!
-  
+
   # We fix this here by making every 'break' belong to its enclosing loop
   # and changing all breaks that belong to a 'block' by annotating it with
   # a label (if it hasn't one already).
@@ -239,7 +240,7 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
     result[0] = newSymNode(labl).PTransNode
     result[1] = transform(c, n)
     discard c.contSyms.pop()
-  else: 
+  else:
     result = transform(c, n)
 
 proc transformWhile(c: PTransf; n: PNode): PTransNode =
@@ -273,27 +274,27 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
     result = transformSons(c, n)
     result[0] = newSymNode(labl).PTransNode
 
-proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = 
+proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
   # XXX: BUG: what if `n` is an expression with side-effects?
-  for i in countup(0, sonsLen(c.transCon.forStmt) - 3): 
-    add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], 
+  for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
+    add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
         transform(c, newTupleAccess(n, i))))
 
-proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = 
+proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
   case n.kind
-  of nkSym: 
+  of nkSym:
     result = transformSym(c, n)
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
     # nothing to be done for leaves:
     result = PTransNode(n)
   of nkVarSection, nkLetSection:
     result = transformVarSection(c, n)
   else:
     result = newTransNode(n)
-    for i in countup(0, sonsLen(n)-1): 
+    for i in countup(0, sonsLen(n)-1):
       result[i] =  introduceNewLocalVars(c, n.sons[i])
 
-proc transformYield(c: PTransf, n: PNode): PTransNode = 
+proc transformYield(c: PTransf, n: PNode): PTransNode =
   result = newTransNode(nkStmtList, n.info, 0)
   var e = n.sons[0]
   # c.transCon.forStmt.len == 3 means that there is one for loop variable
@@ -301,21 +302,21 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
   if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
       c.transCon.forStmt.len != 3:
     e = skipConv(e)
-    if e.kind == nkPar: 
-      for i in countup(0, sonsLen(e) - 1): 
-        add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i], 
+    if e.kind == nkPar:
+      for i in countup(0, sonsLen(e) - 1):
+        add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
                                 transform(c, e.sons[i])))
-    else: 
+    else:
       unpackTuple(c, e, result)
-  else: 
+  else:
     var x = transform(c, e)
     add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
-  
+
   inc(c.transCon.yieldStmts)
   if c.transCon.yieldStmts <= 1:
     # common case
     add(result, c.transCon.forLoopBody)
-  else: 
+  else:
     # we need to introduce new local variables:
     add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
 
@@ -340,25 +341,25 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
     if n.sons[0].kind == a or n.sons[0].kind == b:
       # addr ( deref ( x )) --> x
       result = PTransNode(n.sons[0].sons[0])
-  
-proc transformConv(c: PTransf, n: PNode): PTransNode = 
+
+proc transformConv(c: PTransf, n: PNode): PTransNode =
   # numeric types need range checks:
   var dest = skipTypes(n.typ, abstractVarRange)
   var source = skipTypes(n.sons[1].typ, abstractVarRange)
   case dest.kind
-  of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32: 
+  of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
     # we don't include uint and uint64 here as these are no ordinal types ;-)
     if not isOrdinalType(source):
       # float -> int conversions. ugh.
       result = transformSons(c, n)
     elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
-        lastOrd(n.sons[1].typ) <= lastOrd(n.typ): 
+        lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
       # BUGFIX: simply leave n as it is; we need a nkConv node,
       # but no range check:
       result = transformSons(c, n)
-    else: 
+    else:
       # generate a range check:
-      if dest.kind == tyInt64 or source.kind == tyInt64: 
+      if dest.kind == tyInt64 or source.kind == tyInt64:
         result = newTransNode(nkChckRange64, n, 3)
       else:
         result = newTransNode(nkChckRange, n, 3)
@@ -368,7 +369,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
   of tyFloat..tyFloat128:
     # XXX int64 -> float conversion?
-    if skipTypes(n.typ, abstractVar).kind == tyRange: 
+    if skipTypes(n.typ, abstractVar).kind == tyRange:
       result = newTransNode(nkChckRangeF, n, 3)
       dest = skipTypes(n.typ, abstractVar)
       result[0] = transform(c, n.sons[1])
@@ -378,81 +379,81 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result = transformSons(c, n)
   of tyOpenArray, tyVarargs:
     result = transform(c, n.sons[1])
-  of tyCString: 
-    if source.kind == tyString: 
+  of tyCString:
+    if source.kind == tyString:
       result = newTransNode(nkStringToCString, n, 1)
       result[0] = transform(c, n.sons[1])
     else:
       result = transformSons(c, n)
-  of tyString: 
-    if source.kind == tyCString: 
+  of tyString:
+    if source.kind == tyCString:
       result = newTransNode(nkCStringToString, n, 1)
       result[0] = transform(c, n.sons[1])
     else:
       result = transformSons(c, n)
-  of tyRef, tyPtr: 
+  of tyRef, tyPtr:
     dest = skipTypes(dest, abstractPtrs)
     source = skipTypes(source, abstractPtrs)
-    if source.kind == tyObject: 
+    if source.kind == tyObject:
       var diff = inheritanceDiff(dest, source)
-      if diff < 0: 
+      if diff < 0:
         result = newTransNode(nkObjUpConv, n, 1)
         result[0] = transform(c, n.sons[1])
-      elif diff > 0: 
+      elif diff > 0 and diff != high(int):
         result = newTransNode(nkObjDownConv, n, 1)
         result[0] = transform(c, n.sons[1])
-      else: 
+      else:
         result = transform(c, n.sons[1])
     else:
       result = transformSons(c, n)
-  of tyObject: 
+  of tyObject:
     var diff = inheritanceDiff(dest, source)
-    if diff < 0: 
+    if diff < 0:
       result = newTransNode(nkObjUpConv, n, 1)
       result[0] = transform(c, n.sons[1])
-    elif diff > 0: 
+    elif diff > 0 and diff != high(int):
       result = newTransNode(nkObjDownConv, n, 1)
       result[0] = transform(c, n.sons[1])
-    else: 
+    else:
       result = transform(c, n.sons[1])
   of tyGenericParam, tyOrdinal:
     result = transform(c, n.sons[1])
     # happens sometimes for generated assignments, etc.
-  else: 
+  else:
     result = transformSons(c, n)
-  
-type 
-  TPutArgInto = enum 
+
+type
+  TPutArgInto = enum
     paDirectMapping, paFastAsgn, paVarAsgn
 
-proc putArgInto(arg: PNode, formal: PType): TPutArgInto = 
+proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
   # This analyses how to treat the mapping "formal <-> arg" in an
   # inline context.
   if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
     return paDirectMapping    # XXX really correct?
                               # what if ``arg`` has side-effects?
   case arg.kind
-  of nkEmpty..nkNilLit: 
+  of nkEmpty..nkNilLit:
     result = paDirectMapping
-  of nkPar, nkCurly, nkBracket: 
+  of nkPar, nkCurly, nkBracket:
     result = paFastAsgn
-    for i in countup(0, sonsLen(arg) - 1): 
-      if putArgInto(arg.sons[i], formal) != paDirectMapping: return 
+    for i in countup(0, sonsLen(arg) - 1):
+      if putArgInto(arg.sons[i], formal) != paDirectMapping: return
     result = paDirectMapping
-  else: 
+  else:
     if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
     else: result = paFastAsgn
-  
+
 proc findWrongOwners(c: PTransf, n: PNode) =
   if n.kind == nkVarSection:
     let x = n.sons[0].sons[0]
     if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
-      internalError(x.info, "bah " & x.sym.name.s & " " & 
+      internalError(x.info, "bah " & x.sym.name.s & " " &
         x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
   else:
     for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
 
-proc transformFor(c: PTransf, n: PNode): PTransNode = 
+proc transformFor(c: PTransf, n: PNode): PTransNode =
   # generate access statements for the parameters (unless they are constant)
   # put mapping from formal parameters to actual parameters
   if n.kind != nkForStmt: internalError(n.info, "transformFor")
@@ -466,26 +467,26 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   result[0] = newSymNode(labl).PTransNode
 
   if call.typ.kind != tyIter and
-    (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or 
+    (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
       call.sons[0].sym.kind != skIterator):
     n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
     result[1] = lambdalifting.liftForLoop(n).PTransNode
     discard c.breakSyms.pop
     return result
-  
+
   #echo "transforming: ", renderTree(n)
   var stmtList = newTransNode(nkStmtList, n.info, 0)
-  
+
   var loopBody = transformLoopBody(c, n.sons[length-1])
 
   result[1] = stmtList
   discard c.breakSyms.pop
 
   var v = newNodeI(nkVarSection, n.info)
-  for i in countup(0, length - 3): 
+  for i in countup(0, length - 3):
     addVar(v, copyTree(n.sons[i])) # declare new vars
   add(stmtList, v.PTransNode)
-  
+
   # Bugfix: inlined locals belong to the invoking routine, not to the invoked
   # iterator!
   let iter = call.sons[0].sym
@@ -496,9 +497,9 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   if iter.kind != skIterator: return result
   # generate access statements for the parameters (unless they are constant)
   pushTransCon(c, newC)
-  for i in countup(1, sonsLen(call) - 1): 
+  for i in countup(1, sonsLen(call) - 1):
     var arg = transform(c, call.sons[i]).PNode
-    var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym 
+    var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
     if arg.typ.kind == tyIter: continue
     case putArgInto(arg, formal.typ)
     of paDirectMapping:
@@ -527,20 +528,20 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   popInfoContext()
   popTransCon(c)
   # echo "transformed: ", stmtList.PNode.renderTree
-  
-proc getMagicOp(call: PNode): TMagic = 
+
+proc getMagicOp(call: PNode): TMagic =
   if call.sons[0].kind == nkSym and
-      call.sons[0].sym.kind in {skProc, skMethod, skConverter}: 
+      call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
     result = call.sons[0].sym.magic
   else:
     result = mNone
 
-proc transformCase(c: PTransf, n: PNode): PTransNode = 
+proc transformCase(c: PTransf, n: PNode): PTransNode =
   # removes `elif` branches of a case stmt
   # adds ``else: nil`` if needed for the code generator
   result = newTransNode(nkCaseStmt, n, 0)
   var ifs = PTransNode(nil)
-  for i in 0 .. sonsLen(n)-1: 
+  for i in 0 .. sonsLen(n)-1:
     var it = n.sons[i]
     var e = transform(c, it)
     case it.kind
@@ -564,8 +565,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
     var elseBranch = newTransNode(nkElse, n.info, 1)
     elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
     add(result, elseBranch)
-  
-proc transformArrayAccess(c: PTransf, n: PNode): PTransNode = 
+
+proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
   # XXX this is really bad; transf should use a proper AST visitor
   if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
     result = n.PTransNode
@@ -573,45 +574,45 @@ proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
     result = newTransNode(n)
     for i in 0 .. < n.len:
       result[i] = transform(c, skipConv(n.sons[i]))
-  
-proc getMergeOp(n: PNode): PSym = 
+
+proc getMergeOp(n: PNode): PSym =
   case n.kind
-  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, 
-     nkCallStrLit: 
+  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
+     nkCallStrLit:
     if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
-        (sfMerge in n.sons[0].sym.flags): 
+        (sfMerge in n.sons[0].sym.flags):
       result = n.sons[0].sym
   else: discard
 
-proc flattenTreeAux(d, a: PNode, op: PSym) = 
+proc flattenTreeAux(d, a: PNode, op: PSym) =
   let op2 = getMergeOp(a)
   if op2 != nil and
-      (op2.id == op.id or op.magic != mNone and op2.magic == op.magic): 
+      (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
     for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
-  else: 
+  else:
     addSon(d, copyTree(a))
-  
-proc flattenTree(root: PNode): PNode = 
+
+proc flattenTree(root: PNode): PNode =
   let op = getMergeOp(root)
-  if op != nil: 
+  if op != nil:
     result = copyNode(root)
     addSon(result, copyTree(root.sons[0]))
     flattenTreeAux(result, root, op)
-  else: 
+  else:
     result = root
 
-proc transformCall(c: PTransf, n: PNode): PTransNode = 
+proc transformCall(c: PTransf, n: PNode): PTransNode =
   var n = flattenTree(n)
   let op = getMergeOp(n)
   let magic = getMagic(n)
-  if op != nil and op.magic != mNone and n.len >= 3: 
+  if op != nil and op.magic != mNone and n.len >= 3:
     result = newTransNode(nkCall, n, 0)
     add(result, transform(c, n.sons[0]))
     var j = 1
-    while j < sonsLen(n): 
+    while j < sonsLen(n):
       var a = transform(c, n.sons[j]).PNode
       inc(j)
-      if isConstExpr(a): 
+      if isConstExpr(a):
         while (j < sonsLen(n)):
           let b = transform(c, n.sons[j]).PNode
           if not isConstExpr(b): break
@@ -640,7 +641,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
 proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
   # symbols that expand to a complex constant (array, etc.) should not be
   # inlined, unless it's the empty array:
-  result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and 
+  result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
       cnst.len != 0
 
 proc commonOptimizations*(c: PSym, n: PNode): PNode =
@@ -673,11 +674,11 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
     else:
       result = n
 
-proc transform(c: PTransf, n: PNode): PTransNode = 
+proc transform(c: PTransf, n: PNode): PTransNode =
   case n.kind
-  of nkSym: 
+  of nkSym:
     result = transformSym(c, n)
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
     # nothing to be done for leaves:
     result = PTransNode(n)
   of nkBracketExpr: result = transformArrayAccess(c, n)
@@ -702,7 +703,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
         n.sons[bodyPos] = PNode(transform(c, s.getBody))
         if n.kind == nkMethodDef: methodDef(s, false)
     result = PTransNode(n)
-  of nkForStmt: 
+  of nkForStmt:
     result = transformFor(c, n)
   of nkParForStmt:
     result = transformSons(c, n)
@@ -713,14 +714,14 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     add(result, PTransNode(newSymNode(labl)))
   of nkBreakStmt: result = transformBreak(c, n)
   of nkWhileStmt: result = transformWhile(c, n)
-  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, 
-     nkCallStrLit: 
+  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
+     nkCallStrLit:
     result = transformCall(c, n)
-  of nkAddr, nkHiddenAddr: 
+  of nkAddr, nkHiddenAddr:
     result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
-  of nkDerefExpr, nkHiddenDeref: 
+  of nkDerefExpr, nkHiddenDeref:
     result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     result = transformConv(c, n)
   of nkDiscardStmt:
     result = PTransNode(n)
@@ -730,7 +731,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
         # ensure that e.g. discard "some comment" gets optimized away
         # completely:
         result = PTransNode(newNode(nkCommentStmt))
-  of nkCommentStmt, nkTemplateDef: 
+  of nkCommentStmt, nkTemplateDef:
     return n.PTransNode
   of nkConstSection:
     # do not replace ``const c = 3`` with ``const 3 = 3``
@@ -744,10 +745,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
       result = transformVarSection(c, n)
     else:
       result = transformSons(c, n)
-  of nkYieldStmt: 
+  of nkYieldStmt:
     if c.inlining > 0:
       result = transformYield(c, n)
-    else: 
+    else:
       result = transformSons(c, n)
   of nkBlockStmt, nkBlockExpr:
     result = transformBlock(c, n)
@@ -764,7 +765,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   if cnst != nil and not dontInlineConstant(n, cnst):
     result = PTransNode(cnst) # do not miss an optimization
 
-proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = 
+proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
   # this step! We have to rely that the semantic pass transforms too errornous
   # nodes into an empty node.
@@ -774,7 +775,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   popTransCon(c)
   incl(result.flags, nfTransf)
 
-proc openTransf(module: PSym, filename: string): PTransf = 
+proc openTransf(module: PSym, filename: string): PTransf =
   new(result)
   result.contSyms = @[]
   result.breakSyms = @[]
diff --git a/compiler/types.nim b/compiler/types.nim
index 5c3be7553..5f506f10f 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -9,20 +9,20 @@
 
 # this module contains routines for accessing and iterating over types
 
-import 
+import
   intsets, ast, astalgo, trees, msgs, strutils, platform, renderer
 
 proc firstOrd*(t: PType): BiggestInt
 proc lastOrd*(t: PType): BiggestInt
 proc lengthOrd*(t: PType): BiggestInt
-type 
+type
   TPreferedDesc* = enum
     preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg
 
 proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
 proc base*(t: PType): PType
   # ------------------- type iterator: ----------------------------------------
-type 
+type
   TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop
   TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it
   TTypePredicate* = proc (t: PType): bool {.nimcall.}
@@ -32,7 +32,7 @@ proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool
 proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType
   # Returns result of `iter`.
 
-type 
+type
   TParamsEquality* = enum     # they are equal, but their
                               # identifiers or their return
                               # type differ (i.e. they cannot be
@@ -59,7 +59,7 @@ const
   abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal,
                    tyTypeDesc}
 
-  skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, 
+  skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
                tyTypeDesc}
   typedescPtrs* = abstractPtrs + {tyTypeDesc}
   typedescInst* = abstractInst + {tyTypeDesc}
@@ -75,9 +75,9 @@ proc getSize*(typ: PType): BiggestInt
 proc isPureObject*(typ: PType): bool
 proc invalidGenericInst*(f: PType): bool
   # for debugging
-type 
-  TTypeFieldResult* = enum 
-    frNone,                   # type has no object type field 
+type
+  TTypeFieldResult* = enum
+    frNone,                   # type has no object type field
     frHeader,                 # type has an object type field only in the header
     frEmbedded                # type has an object type field somewhere embedded
 
@@ -86,15 +86,15 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
   # made or intializing of the type field suffices or if there is no type field
   # at all in this type.
 
-proc invalidGenericInst(f: PType): bool = 
+proc invalidGenericInst(f: PType): bool =
   result = f.kind == tyGenericInst and lastSon(f) == nil
 
-proc isPureObject(typ: PType): bool = 
+proc isPureObject(typ: PType): bool =
   var t = typ
   while t.kind == tyObject and t.sons[0] != nil: t = t.sons[0]
   result = t.sym != nil and sfPure in t.sym.flags
 
-proc getOrdValue(n: PNode): BiggestInt = 
+proc getOrdValue(n: PNode): BiggestInt =
   case n.kind
   of nkCharLit..nkUInt64Lit: result = n.intVal
   of nkNilLit: result = 0
@@ -109,21 +109,21 @@ proc isIntLit*(t: PType): bool {.inline.} =
 proc isFloatLit*(t: PType): bool {.inline.} =
   result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit
 
-proc isCompatibleToCString(a: PType): bool = 
-  if a.kind == tyArray: 
+proc isCompatibleToCString(a: PType): bool =
+  if a.kind == tyArray:
     if (firstOrd(a.sons[0]) == 0) and
-        (skipTypes(a.sons[0], {tyRange, tyConst, 
-                               tyMutable, tyGenericInst}).kind in 
+        (skipTypes(a.sons[0], {tyRange, tyConst,
+                               tyMutable, tyGenericInst}).kind in
             {tyInt..tyInt64, tyUInt..tyUInt64}) and
-        (a.sons[1].kind == tyChar): 
+        (a.sons[1].kind == tyChar):
       result = true
-  
-proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = 
+
+proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   result = sym.owner.name.s & '.' & sym.name.s & '('
   var n = sym.typ.n
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var p = n.sons[i]
-    if p.kind == nkSym: 
+    if p.kind == nkSym:
       add(result, p.sym.name.s)
       add(result, ": ")
       add(result, typeToString(p.sym.typ, prefer))
@@ -134,7 +134,7 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   if n.sons[0].typ != nil:
     result.add(": " & typeToString(n.sons[0].typ, prefer))
 
-proc elemType*(t: PType): PType = 
+proc elemType*(t: PType): PType =
   assert(t != nil)
   case t.kind
   of tyGenericInst, tyDistinct: result = elemType(lastSon(t))
@@ -142,10 +142,10 @@ proc elemType*(t: PType): PType =
   else: result = t.lastSon
   assert(result != nil)
 
-proc skipGeneric(t: PType): PType = 
+proc skipGeneric(t: PType): PType =
   result = t
   while result.kind == tyGenericInst: result = lastSon(result)
-      
+
 proc isOrdinalType(t: PType): bool =
   assert(t != nil)
   # caution: uint, uint64 are no ordinal types!
@@ -153,134 +153,134 @@ proc isOrdinalType(t: PType): bool =
       (t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
        isOrdinalType(t.sons[0])
 
-proc enumHasHoles(t: PType): bool = 
+proc enumHasHoles(t: PType): bool =
   var b = t
   while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0]
   result = b.kind == tyEnum and tfEnumHasHoles in b.flags
 
-proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, 
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
                      closure: RootRef): bool
-proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, 
-                  closure: RootRef): bool = 
-  if n != nil: 
+proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter,
+                  closure: RootRef): bool =
+  if n != nil:
     case n.kind
-    of nkNone..nkNilLit: 
+    of nkNone..nkNilLit:
       # a leaf
       result = iterOverTypeAux(marker, n.typ, iter, closure)
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         result = iterOverNode(marker, n.sons[i], iter, closure)
-        if result: return 
-  
-proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, 
-                     closure: RootRef): bool = 
+        if result: return
+
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
+                     closure: RootRef): bool =
   result = false
-  if t == nil: return 
+  if t == nil: return
   result = iter(t, closure)
-  if result: return 
-  if not containsOrIncl(marker, t.id): 
+  if result: return
+  if not containsOrIncl(marker, t.id):
     case t.kind
-    of tyGenericInst, tyGenericBody: 
+    of tyGenericInst, tyGenericBody:
       result = iterOverTypeAux(marker, lastSon(t), iter, closure)
-    else: 
-      for i in countup(0, sonsLen(t) - 1): 
+    else:
+      for i in countup(0, sonsLen(t) - 1):
         result = iterOverTypeAux(marker, t.sons[i], iter, closure)
-        if result: return 
+        if result: return
       if t.n != nil: result = iterOverNode(marker, t.n, iter, closure)
-  
-proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = 
+
+proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool =
   var marker = initIntSet()
   result = iterOverTypeAux(marker, t, iter, closure)
 
-proc searchTypeForAux(t: PType, predicate: TTypePredicate, 
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
                       marker: var IntSet): bool
 
-proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, 
-                          marker: var IntSet): bool = 
+proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
+                          marker: var IntSet): bool =
   result = false
   case n.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
       result = searchTypeNodeForAux(n.sons[i], p, marker)
-      if result: return 
-  of nkRecCase: 
+      if result: return
+  of nkRecCase:
     assert(n.sons[0].kind == nkSym)
     result = searchTypeNodeForAux(n.sons[0], p, marker)
-    if result: return 
-    for i in countup(1, sonsLen(n) - 1): 
+    if result: return
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
-        if result: return 
+        if result: return
       else: internalError("searchTypeNodeForAux(record case branch)")
-  of nkSym: 
+  of nkSym:
     result = searchTypeForAux(n.sym.typ, p, marker)
   else: internalError(n.info, "searchTypeNodeForAux()")
-  
-proc searchTypeForAux(t: PType, predicate: TTypePredicate, 
-                      marker: var IntSet): bool = 
+
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
+                      marker: var IntSet): bool =
   # iterates over VALUE types!
   result = false
-  if t == nil: return 
-  if containsOrIncl(marker, t.id): return 
+  if t == nil: return
+  if containsOrIncl(marker, t.id): return
   result = predicate(t)
-  if result: return 
+  if result: return
   case t.kind
-  of tyObject: 
+  of tyObject:
     result = searchTypeForAux(t.sons[0], predicate, marker)
     if not result: result = searchTypeNodeForAux(t.n, predicate, marker)
-  of tyGenericInst, tyDistinct: 
+  of tyGenericInst, tyDistinct:
     result = searchTypeForAux(lastSon(t), predicate, marker)
-  of tyArray, tyArrayConstr, tySet, tyTuple: 
-    for i in countup(0, sonsLen(t) - 1): 
+  of tyArray, tyArrayConstr, tySet, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
       result = searchTypeForAux(t.sons[i], predicate, marker)
-      if result: return 
-  else: 
+      if result: return
+  else:
     discard
 
-proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = 
+proc searchTypeFor(t: PType, predicate: TTypePredicate): bool =
   var marker = initIntSet()
   result = searchTypeForAux(t, predicate, marker)
 
-proc isObjectPredicate(t: PType): bool = 
+proc isObjectPredicate(t: PType): bool =
   result = t.kind == tyObject
 
-proc containsObject(t: PType): bool = 
+proc containsObject(t: PType): bool =
   result = searchTypeFor(t, isObjectPredicate)
 
-proc isObjectWithTypeFieldPredicate(t: PType): bool = 
+proc isObjectWithTypeFieldPredicate(t: PType): bool =
   result = t.kind == tyObject and t.sons[0] == nil and
       not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
       tfFinal notin t.flags
 
-proc analyseObjectWithTypeFieldAux(t: PType, 
-                                   marker: var IntSet): TTypeFieldResult = 
+proc analyseObjectWithTypeFieldAux(t: PType,
+                                   marker: var IntSet): TTypeFieldResult =
   var res: TTypeFieldResult
   result = frNone
-  if t == nil: return 
+  if t == nil: return
   case t.kind
-  of tyObject: 
-    if (t.n != nil): 
-      if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): 
+  of tyObject:
+    if (t.n != nil):
+      if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
         return frEmbedded
-    for i in countup(0, sonsLen(t) - 1): 
+    for i in countup(0, sonsLen(t) - 1):
       res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
-      if res == frEmbedded: 
+      if res == frEmbedded:
         return frEmbedded
       if res == frHeader: result = frHeader
-    if result == frNone: 
+    if result == frNone:
       if isObjectWithTypeFieldPredicate(t): result = frHeader
-  of tyGenericInst, tyDistinct, tyConst, tyMutable: 
+  of tyGenericInst, tyDistinct, tyConst, tyMutable:
     result = analyseObjectWithTypeFieldAux(lastSon(t), marker)
-  of tyArray, tyArrayConstr, tyTuple: 
-    for i in countup(0, sonsLen(t) - 1): 
+  of tyArray, tyArrayConstr, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
       res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
-      if res != frNone: 
+      if res != frNone:
         return frEmbedded
-  else: 
+  else:
     discard
 
-proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = 
+proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
   var marker = initIntSet()
   result = analyseObjectWithTypeFieldAux(t, marker)
 
@@ -288,7 +288,7 @@ proc isGCRef(t: PType): bool =
   result = t.kind in GcTypeKinds or
     (t.kind == tyProc and t.callConv == ccClosure)
 
-proc containsGarbageCollectedRef(typ: PType): bool = 
+proc containsGarbageCollectedRef(typ: PType): bool =
   # returns true if typ contains a reference, sequence or string (all the
   # things that are garbage-collected)
   result = searchTypeFor(typ, isGCRef)
@@ -296,47 +296,47 @@ proc containsGarbageCollectedRef(typ: PType): bool =
 proc isTyRef(t: PType): bool =
   result = t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure)
 
-proc containsTyRef*(typ: PType): bool = 
+proc containsTyRef*(typ: PType): bool =
   # returns true if typ contains a 'ref'
   result = searchTypeFor(typ, isTyRef)
 
-proc isHiddenPointer(t: PType): bool = 
+proc isHiddenPointer(t: PType): bool =
   result = t.kind in {tyString, tySequence}
 
-proc containsHiddenPointer(typ: PType): bool = 
+proc containsHiddenPointer(typ: PType): bool =
   # returns true if typ contains a string, table or sequence (all the things
   # that need to be copied deeply)
   result = searchTypeFor(typ, isHiddenPointer)
 
 proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool
-proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = 
+proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool =
   result = false
-  if n != nil: 
+  if n != nil:
     result = canFormAcycleAux(marker, n.typ, startId)
-    if not result: 
+    if not result:
       case n.kind
-      of nkNone..nkNilLit: 
+      of nkNone..nkNilLit:
         discard
-      else: 
-        for i in countup(0, sonsLen(n) - 1): 
+      else:
+        for i in countup(0, sonsLen(n) - 1):
           result = canFormAcycleNode(marker, n.sons[i], startId)
-          if result: return 
-  
-proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = 
+          if result: return
+
+proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
   result = false
-  if typ == nil: return 
-  if tfAcyclic in typ.flags: return 
+  if typ == nil: return
+  if tfAcyclic in typ.flags: return
   var t = skipTypes(typ, abstractInst-{tyTypeDesc})
-  if tfAcyclic in t.flags: return 
+  if tfAcyclic in t.flags: return
   case t.kind
   of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray,
      tyVarargs:
-    if not containsOrIncl(marker, t.id): 
-      for i in countup(0, sonsLen(t) - 1): 
+    if not containsOrIncl(marker, t.id):
+      for i in countup(0, sonsLen(t) - 1):
         result = canFormAcycleAux(marker, t.sons[i], startId)
-        if result: return 
+        if result: return
       if t.n != nil: result = canFormAcycleNode(marker, t.n, startId)
-    else: 
+    else:
       result = t.id == startId
     # Inheritance can introduce cyclic types, however this is not relevant
     # as the type that is passed to 'new' is statically known!
@@ -351,29 +351,29 @@ proc canFormAcycle(typ: PType): bool =
   var marker = initIntSet()
   result = canFormAcycleAux(marker, typ, typ.id)
 
-proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, 
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
                    closure: RootRef): PType
-proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, 
-                closure: RootRef): PNode = 
+proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator,
+                closure: RootRef): PNode =
   result = nil
-  if n != nil: 
+  if n != nil:
     result = copyNode(n)
     result.typ = mutateTypeAux(marker, n.typ, iter, closure)
     case n.kind
-    of nkNone..nkNilLit: 
+    of nkNone..nkNilLit:
       # a leaf
       discard
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         addSon(result, mutateNode(marker, n.sons[i], iter, closure))
-  
-proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, 
-                   closure: RootRef): PType = 
+
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
+                   closure: RootRef): PType =
   result = nil
-  if t == nil: return 
+  if t == nil: return
   result = iter(t, closure)
-  if not containsOrIncl(marker, t.id): 
-    for i in countup(0, sonsLen(t) - 1): 
+  if not containsOrIncl(marker, t.id):
+    for i in countup(0, sonsLen(t) - 1):
       result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
     if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure)
   assert(result != nil)
@@ -393,7 +393,7 @@ proc rangeToStr(n: PNode): string =
   assert(n.kind == nkRange)
   result = valueToString(n.sons[0]) & ".." & valueToString(n.sons[1])
 
-const 
+const
   typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
     "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
     "GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
@@ -414,7 +414,7 @@ const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
 proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   var t = typ
   result = ""
-  if t == nil: return 
+  if t == nil: return
   if prefer in preferToResolveSymbols and t.sym != nil and
        sfAnon notin t.sym.flags:
     if t.kind == tyInt and isIntLit(t):
@@ -484,47 +484,51 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     result = "expr"
   of tyFromExpr, tyFieldAccessor:
     result = renderTree(t.n)
-  of tyArray: 
-    if t.sons[0].kind == tyRange: 
+  of tyArray:
+    if t.sons[0].kind == tyRange:
       result = "array[" & rangeToStr(t.sons[0].n) & ", " &
           typeToString(t.sons[1]) & ']'
-    else: 
+    else:
       result = "array[" & typeToString(t.sons[0]) & ", " &
           typeToString(t.sons[1]) & ']'
-  of tyArrayConstr: 
+  of tyArrayConstr:
     result = "Array constructor[" & rangeToStr(t.sons[0].n) & ", " &
         typeToString(t.sons[1]) & ']'
-  of tySequence: 
+  of tySequence:
     result = "seq[" & typeToString(t.sons[0]) & ']'
-  of tyOrdinal: 
+  of tyOrdinal:
     result = "ordinal[" & typeToString(t.sons[0]) & ']'
-  of tySet: 
+  of tySet:
     result = "set[" & typeToString(t.sons[0]) & ']'
-  of tyOpenArray: 
+  of tyOpenArray:
     result = "openarray[" & typeToString(t.sons[0]) & ']'
   of tyDistinct:
     result = "distinct " & typeToString(t.sons[0],
       if prefer == preferModuleInfo: preferModuleInfo else: preferName)
-  of tyTuple: 
+  of tyTuple:
     # we iterate over t.sons here, because t.n may be nil
-    result = "tuple["
-    if t.n != nil: 
+    if t.n != nil:
+      result = "tuple["
       assert(sonsLen(t.n) == sonsLen(t))
-      for i in countup(0, sonsLen(t.n) - 1): 
+      for i in countup(0, sonsLen(t.n) - 1):
         assert(t.n.sons[i].kind == nkSym)
         add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
         if i < sonsLen(t.n) - 1: add(result, ", ")
-    else: 
-      for i in countup(0, sonsLen(t) - 1): 
+      add(result, ']')
+    elif sonsLen(t) == 0:
+      result = "tuple[]"
+    else:
+      result = "("
+      for i in countup(0, sonsLen(t) - 1):
         add(result, typeToString(t.sons[i]))
         if i < sonsLen(t) - 1: add(result, ", ")
-    add(result, ']')
-  of tyPtr, tyRef, tyVar, tyMutable, tyConst: 
+      add(result, ')')
+  of tyPtr, tyRef, tyVar, tyMutable, tyConst:
     result = typeToStr[t.kind]
     if t.len >= 2:
       setLen(result, result.len-1)
       result.add '['
-      for i in countup(0, sonsLen(t) - 1): 
+      for i in countup(0, sonsLen(t) - 1):
         add(result, typeToString(t.sons[i]))
         if i < sonsLen(t) - 1: add(result, ", ")
       result.add ']'
@@ -536,7 +540,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       result.add("(" & typeToString(t.sons[0]) & ")")
   of tyProc:
     result = if tfIterator in t.flags: "iterator (" else: "proc ("
-    for i in countup(1, sonsLen(t) - 1): 
+    for i in countup(1, sonsLen(t) - 1):
       add(result, typeToString(t.sons[i]))
       if i < sonsLen(t) - 1: add(result, ", ")
     add(result, ')')
@@ -554,29 +558,29 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if len(prag) != 0: add(result, "{." & prag & ".}")
   of tyVarargs, tyIter:
     result = typeToStr[t.kind] % typeToString(t.sons[0])
-  else: 
+  else:
     result = typeToStr[t.kind]
   if tfShared in t.flags: result = "shared " & result
   if tfNotNil in t.flags: result.add(" not nil")
 
-proc resultType(t: PType): PType = 
+proc resultType(t: PType): PType =
   assert(t.kind == tyProc)
   result = t.sons[0]          # nil is allowed
-  
-proc base(t: PType): PType = 
+
+proc base(t: PType): PType =
   result = t.sons[0]
 
-proc firstOrd(t: PType): BiggestInt = 
+proc firstOrd(t: PType): BiggestInt =
   case t.kind
   of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
     result = 0
   of tySet, tyVar: result = firstOrd(t.sons[0])
   of tyArray, tyArrayConstr: result = firstOrd(t.sons[0])
-  of tyRange: 
+  of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[0])
-  of tyInt: 
+  of tyInt:
     if platform.intSize == 4: result = - (2147483646) - 2
     else: result = 0x8000000000000000'i64
   of tyInt8: result = - 128
@@ -584,11 +588,11 @@ proc firstOrd(t: PType): BiggestInt =
   of tyInt32: result = - 2147483646 - 2
   of tyInt64: result = 0x8000000000000000'i64
   of tyUInt..tyUInt64: result = 0
-  of tyEnum: 
+  of tyEnum:
     # if basetype <> nil then return firstOrd of basetype
-    if (sonsLen(t) > 0) and (t.sons[0] != nil): 
+    if (sonsLen(t) > 0) and (t.sons[0] != nil):
       result = firstOrd(t.sons[0])
-    else: 
+    else:
       assert(t.n.sons[0].kind == nkSym)
       result = t.n.sons[0].sym.position
   of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor:
@@ -600,31 +604,31 @@ proc firstOrd(t: PType): BiggestInt =
     internalError("invalid kind for first(" & $t.kind & ')')
     result = 0
 
-proc lastOrd(t: PType): BiggestInt = 
+proc lastOrd(t: PType): BiggestInt =
   case t.kind
   of tyBool: result = 1
   of tyChar: result = 255
   of tySet, tyVar: result = lastOrd(t.sons[0])
   of tyArray, tyArrayConstr: result = lastOrd(t.sons[0])
-  of tyRange: 
+  of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[1])
-  of tyInt: 
+  of tyInt:
     if platform.intSize == 4: result = 0x7FFFFFFF
     else: result = 0x7FFFFFFFFFFFFFFF'i64
   of tyInt8: result = 0x0000007F
   of tyInt16: result = 0x00007FFF
   of tyInt32: result = 0x7FFFFFFF
   of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyUInt: 
+  of tyUInt:
     if platform.intSize == 4: result = 0xFFFFFFFF
     else: result = 0x7FFFFFFFFFFFFFFF'i64
   of tyUInt8: result = 0xFF
   of tyUInt16: result = 0xFFFF
   of tyUInt32: result = 0xFFFFFFFF
   of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyEnum: 
+  of tyEnum:
     assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
     result = t.n.sons[sonsLen(t.n) - 1].sym.position
   of tyGenericInst, tyDistinct, tyConst, tyMutable,
@@ -638,7 +642,7 @@ proc lastOrd(t: PType): BiggestInt =
     internalError("invalid kind for last(" & $t.kind & ')')
     result = 0
 
-proc lengthOrd(t: PType): BiggestInt = 
+proc lengthOrd(t: PType): BiggestInt =
   case t.kind
   of tyInt64, tyInt32, tyInt: result = lastOrd(t)
   of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
@@ -654,7 +658,7 @@ type
     dcEqOrDistinctOf       ## a equals b or a is distinct of b
 
   TTypeCmpFlag* = enum
-    IgnoreTupleFields
+    IgnoreTupleFields      ## NOTE: Only set this flag for backends!
     IgnoreCC
     ExactTypeDescValues
     ExactGenericParams
@@ -673,7 +677,7 @@ type
 proc initSameTypeClosure: TSameTypeClosure =
   # we do the initialization lazily for performance (avoids memory allocations)
   discard
-  
+
 proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
   result = not isNil(c.s) and c.s.contains((a.id, b.id))
   if not result:
@@ -700,17 +704,17 @@ proc sameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
     if a == nil or b == nil: result = false
     else: result = sameType(a, b, flags)
 
-proc equalParam(a, b: PSym): TParamsEquality = 
+proc equalParam(a, b: PSym): TParamsEquality =
   if sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and
       exprStructuralEquivalent(a.constraint, b.constraint):
-    if a.ast == b.ast: 
+    if a.ast == b.ast:
       result = paramsEqual
-    elif a.ast != nil and b.ast != nil: 
+    elif a.ast != nil and b.ast != nil:
       if exprStructuralEquivalent(a.ast, b.ast): result = paramsEqual
       else: result = paramsIncompatible
-    elif a.ast != nil: 
+    elif a.ast != nil:
       result = paramsEqual
-    elif b.ast != nil: 
+    elif b.ast != nil:
       result = paramsIncompatible
   else:
     result = paramsNotEqual
@@ -723,70 +727,70 @@ proc sameConstraints(a, b: PNode): bool =
       return false
   return true
 
-proc equalParams(a, b: PNode): TParamsEquality = 
+proc equalParams(a, b: PNode): TParamsEquality =
   result = paramsEqual
   var length = sonsLen(a)
-  if length != sonsLen(b): 
+  if length != sonsLen(b):
     result = paramsNotEqual
-  else: 
-    for i in countup(1, length - 1): 
+  else:
+    for i in countup(1, length - 1):
       var m = a.sons[i].sym
       var n = b.sons[i].sym
       assert((m.kind == skParam) and (n.kind == skParam))
       case equalParam(m, n)
-      of paramsNotEqual: 
+      of paramsNotEqual:
         return paramsNotEqual
-      of paramsEqual: 
+      of paramsEqual:
         discard
-      of paramsIncompatible: 
+      of paramsIncompatible:
         result = paramsIncompatible
-      if (m.name.id != n.name.id): 
+      if (m.name.id != n.name.id):
         # BUGFIX
         return paramsNotEqual # paramsIncompatible;
       # continue traversal! If not equal, we can return immediately; else
       # it stays incompatible
     if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}):
-      if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): 
+      if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
         result = paramsNotEqual # one proc has a result, the other not is OK
-      else: 
+      else:
         result = paramsIncompatible # overloading by different
                                     # result types does not work
-  
-proc sameLiteral(x, y: PNode): bool = 
-  if x.kind == y.kind: 
+
+proc sameLiteral(x, y: PNode): bool =
+  if x.kind == y.kind:
     case x.kind
     of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal
     of nkFloatLit..nkFloat64Lit: result = x.floatVal == y.floatVal
     of nkNilLit: result = true
     else: assert(false)
-  
-proc sameRanges(a, b: PNode): bool = 
+
+proc sameRanges(a, b: PNode): bool =
   result = sameLiteral(a.sons[0], b.sons[0]) and
            sameLiteral(a.sons[1], b.sons[1])
 
-proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = 
+proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
   # two tuples are equivalent iff the names, types and positions are the same;
   # however, both types may not have any field names (t.n may be nil) which
   # complicates the matter a bit.
   if sonsLen(a) == sonsLen(b):
     result = true
-    for i in countup(0, sonsLen(a) - 1): 
+    for i in countup(0, sonsLen(a) - 1):
       var x = a.sons[i]
       var y = b.sons[i]
       if IgnoreTupleFields in c.flags:
-        x = skipTypes(x, {tyRange})
-        y = skipTypes(y, {tyRange})
-      
+        x = skipTypes(x, {tyRange, tyGenericInst})
+        y = skipTypes(y, {tyRange, tyGenericInst})
+
       result = sameTypeAux(x, y, c)
-      if not result: return 
+      if not result: return
     if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags:
-      for i in countup(0, sonsLen(a.n) - 1): 
-        # check field names: 
+      for i in countup(0, sonsLen(a.n) - 1):
+        # check field names:
         if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym:
           var x = a.n.sons[i].sym
           var y = b.n.sons[i].sym
           result = x.name.id == y.name.id
-          if not result: break 
+          if not result: break
         else: internalError(a.n.info, "sameTuple")
 
 template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
@@ -797,7 +801,7 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
     # expensive structural equality test; however due to the way generic and
     # objects work, if one of the types does **not** contain tfFromGeneric,
     # they cannot be equal. The check ``a.sym.id == b.sym.id`` checks
-    # for the same origin and is essential because we don't want "pure" 
+    # for the same origin and is essential because we don't want "pure"
     # structural type equivalence:
     #
     # type
@@ -823,8 +827,13 @@ proc sameEnumTypes*(a, b: PType): bool {.inline.} =
 proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
   if a == b:
     result = true
-  elif (a != nil) and (b != nil) and (a.kind == b.kind):
-    if sameTypeOrNilAux(a.typ, b.typ, c):
+  elif a != nil and b != nil and a.kind == b.kind:
+    var x = a.typ
+    var y = b.typ
+    if IgnoreTupleFields in c.flags:
+      if x != nil: x = skipTypes(x, {tyRange, tyGenericInst})
+      if y != nil: y = skipTypes(y, {tyRange, tyGenericInst})
+    if sameTypeOrNilAux(x, y, c):
       case a.kind
       of nkSym:
         # same symbol as string is enough:
@@ -835,9 +844,9 @@ proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
       of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
       of nkEmpty, nkNilLit, nkType: result = true
       else:
-        if sonsLen(a) == sonsLen(b): 
-          for i in countup(0, sonsLen(a) - 1): 
-            if not sameObjectTree(a.sons[i], b.sons[i], c): return 
+        if sonsLen(a) == sonsLen(b):
+          for i in countup(0, sonsLen(a) - 1):
+            if not sameObjectTree(a.sons[i], b.sons[i], c): return
           result = true
 
 proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
@@ -853,7 +862,7 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
   result = true
   for i in countup(0, sonsLen(a) - 1):
     result = sameTypeOrNilAux(a.sons[i], b.sons[i], c)
-    if not result: return 
+    if not result: return
 
 proc isGenericAlias*(t: PType): bool =
   return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst
@@ -866,7 +875,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     # believe it or not, the direct check for ``containsOrIncl(c, a, b)``
     # increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat
     # again: Since the recursion check is only to not get caught in an endless
-    # recursion, we use a counter and only if it's value is over some 
+    # recursion, we use a counter and only if it's value is over some
     # threshold we perform the expensive exact cycle check:
     if c.recCheck < 3:
       inc c.recCheck
@@ -874,11 +883,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       if containsOrIncl(c, a, b): return true
 
   proc sameFlags(a, b: PType): bool {.inline.} =
-    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags   
+    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
 
   if x == y: return true
   var a = skipTypes(x, {tyGenericInst})
-  var b = skipTypes(y, {tyGenericInst})  
+  var b = skipTypes(y, {tyGenericInst})
   assert(a != nil)
   assert(b != nil)
   if a.kind != b.kind:
@@ -891,7 +900,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     of dcEqOrDistinctOf:
       while a.kind == tyDistinct: a = a.sons[0]
       if a.kind != b.kind: return false
-  
+
   if x.kind == tyGenericInst:
     let
       lhs = x.skipGenericAlias
@@ -916,11 +925,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       result = sameObjectStructures(a, b, c) and sameFlags(a, b)
   of tyDistinct:
     cycleCheck()
-    if c.cmp == dcEq:      
+    if c.cmp == dcEq:
       if sameFlags(a, b):
         ifFastObjectTypeCheckFailed(a, b):
-          result = sameTypeAux(a.sons[0], b.sons[0], c)     
-    else: 
+          result = sameTypeAux(a.sons[0], b.sons[0], c)
+    else:
       result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
   of tyEnum, tyForward:
     # XXX generic enums do not make much sense, but require structural checking
@@ -957,13 +966,13 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
         sameValue(a.n.sons[0], b.n.sons[0]) and
         sameValue(a.n.sons[1], b.n.sons[1])
   of tyGenericInst: discard
-  of tyNone: result = false  
+  of tyNone: result = false
 
 proc sameBackendType*(x, y: PType): bool =
   var c = initSameTypeClosure()
   c.flags.incl IgnoreTupleFields
   result = sameTypeAux(x, y, c)
-  
+
 proc compareTypes*(x, y: PType,
                    cmp: TDistinctCompare = dcEq,
                    flags: TTypeCmpFlags = {}): bool =
@@ -972,8 +981,8 @@ proc compareTypes*(x, y: PType,
   c.cmp = cmp
   c.flags = flags
   result = sameTypeAux(x, y, c)
-  
-proc inheritanceDiff*(a, b: PType): int = 
+
+proc inheritanceDiff*(a, b: PType): int =
   # | returns: 0 iff `a` == `b`
   # | returns: -x iff `a` is the x'th direct superclass of `b`
   # | returns: +x iff `a` is the x'th direct subclass of `b`
@@ -985,14 +994,14 @@ proc inheritanceDiff*(a, b: PType): int =
   result = 0
   while x != nil:
     x = skipTypes(x, skipPtrs)
-    if sameObjectTypes(x, b): return 
+    if sameObjectTypes(x, b): return
     x = x.sons[0]
     dec(result)
   var y = b
   result = 0
   while y != nil:
     y = skipTypes(y, skipPtrs)
-    if sameObjectTypes(y, a): return 
+    if sameObjectTypes(y, a): return
     y = y.sons[0]
     inc(result)
   result = high(int)
@@ -1066,7 +1075,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     if kind == skConst: return t
     var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
     case t2.kind
-    of tyVar: 
+    of tyVar:
       if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
     of tyOpenArray:
       if kind != skParam: result = t
@@ -1075,9 +1084,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
       if kind notin {skParam, skResult}: result = t
       else: result = typeAllowedAux(marker, t2, kind, flags)
   of tyProc:
-    for i in countup(1, sonsLen(t) - 1): 
+    for i in countup(1, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], skParam, flags)
-      if result != nil: break 
+      if result != nil: break
     if result.isNil and t.sons[0] != nil:
       result = typeAllowedAux(marker, t.sons[0], skResult, flags)
   of tyExpr, tyStmt, tyTypeDesc, tyStatic:
@@ -1092,7 +1101,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     result = t
   of tyNil:
     if kind != skConst: result = t
-  of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: 
+  of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
     result = nil
   of tyOrdinal:
     if kind != skParam: result = t
@@ -1132,13 +1141,13 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     # prevent cascading errors:
     result = nil
 
-proc typeAllowed*(t: PType, kind: TSymKind): PType = 
+proc typeAllowed*(t: PType, kind: TSymKind): PType =
   # returns 'nil' on success and otherwise the part of the type that is
   # wrong!
   var marker = initIntSet()
   result = typeAllowedAux(marker, t, kind, {})
 
-proc align(address, alignment: BiggestInt): BiggestInt = 
+proc align(address, alignment: BiggestInt): BiggestInt =
   result = (address + (alignment - 1)) and not (alignment - 1)
 
 const
@@ -1147,17 +1156,17 @@ const
   szUnknownSize* = -1
 
 proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt
-proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = 
+proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
   var maxAlign, maxSize, b, res: BiggestInt
   case n.kind
-  of nkRecCase: 
+  of nkRecCase:
     assert(n.sons[0].kind == nkSym)
     result = computeRecSizeAux(n.sons[0], a, currOffset)
     maxSize = 0
     maxAlign = 1
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         res = computeRecSizeAux(lastSon(n.sons[i]), b, currOffset)
         if res < 0: return res
         maxSize = max(maxSize, res)
@@ -1166,17 +1175,17 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
     currOffset = align(currOffset, maxAlign) + maxSize
     result = align(result, maxAlign) + maxSize
     a = maxAlign
-  of nkRecList: 
+  of nkRecList:
     result = 0
     maxAlign = 1
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       res = computeRecSizeAux(n.sons[i], b, currOffset)
       if res < 0: return res
       currOffset = align(currOffset, b) + res
       result = align(result, b) + res
       if b > maxAlign: maxAlign = b
     a = maxAlign
-  of nkSym: 
+  of nkSym:
     result = computeSizeAux(n.sym.typ, a)
     n.sym.offset = int(currOffset)
   else:
@@ -1193,31 +1202,31 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     # size already computed
     result = typ.size
     a = typ.align
-    return 
+    return
   typ.size = szIllegalRecursion # mark as being computed
   case typ.kind
-  of tyInt, tyUInt: 
+  of tyInt, tyUInt:
     result = intSize
     a = result
-  of tyInt8, tyUInt8, tyBool, tyChar: 
+  of tyInt8, tyUInt8, tyBool, tyChar:
     result = 1
     a = result
-  of tyInt16, tyUInt16: 
+  of tyInt16, tyUInt16:
     result = 2
     a = result
-  of tyInt32, tyUInt32, tyFloat32: 
+  of tyInt32, tyUInt32, tyFloat32:
     result = 4
     a = result
-  of tyInt64, tyUInt64, tyFloat64: 
+  of tyInt64, tyUInt64, tyFloat64:
     result = 8
     a = result
   of tyFloat128:
     result = 16
     a = result
-  of tyFloat: 
+  of tyFloat:
     result = floatSize
     a = result
-  of tyProc: 
+  of tyProc:
     if typ.callConv == ccClosure: result = 2 * ptrSize
     else: result = ptrSize
     a = ptrSize
@@ -1232,17 +1241,17 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     let elemSize = computeSizeAux(typ.sons[1], a)
     if elemSize < 0: return elemSize
     result = lengthOrd(typ.sons[0]) * elemSize
-  of tyEnum: 
-    if firstOrd(typ) < 0: 
+  of tyEnum:
+    if firstOrd(typ) < 0:
       result = 4              # use signed int32
-    else: 
+    else:
       length = lastOrd(typ)   # BUGFIX: use lastOrd!
       if length + 1 < `shl`(1, 8): result = 1
       elif length + 1 < `shl`(1, 16): result = 2
       elif length + 1 < `shl`(BiggestInt(1), 32): result = 4
       else: result = 8
     a = result
-  of tySet: 
+  of tySet:
     length = lengthOrd(typ.sons[0])
     if length <= 8: result = 1
     elif length <= 16: result = 2
@@ -1251,32 +1260,32 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     elif align(length, 8) mod 8 == 0: result = align(length, 8) div 8
     else: result = align(length, 8) div 8 + 1
     a = result
-  of tyRange: 
+  of tyRange:
     result = computeSizeAux(typ.sons[0], a)
-  of tyTuple: 
+  of tyTuple:
     result = 0
     maxAlign = 1
-    for i in countup(0, sonsLen(typ) - 1): 
+    for i in countup(0, sonsLen(typ) - 1):
       res = computeSizeAux(typ.sons[i], a)
       if res < 0: return res
       maxAlign = max(maxAlign, a)
       result = align(result, a) + res
     result = align(result, maxAlign)
     a = maxAlign
-  of tyObject: 
-    if typ.sons[0] != nil: 
+  of tyObject:
+    if typ.sons[0] != nil:
       result = computeSizeAux(typ.sons[0], a)
-      if result < 0: return 
+      if result < 0: return
       maxAlign = a
-    elif isObjectWithTypeFieldPredicate(typ): 
+    elif isObjectWithTypeFieldPredicate(typ):
       result = intSize
       maxAlign = result
-    else: 
+    else:
       result = 0
       maxAlign = 1
     currOffset = result
     result = computeRecSizeAux(typ.n, a, currOffset)
-    if result < 0: return 
+    if result < 0: return
     if a < maxAlign: a = maxAlign
     result = align(result, a)
   of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
@@ -1290,7 +1299,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
   typ.size = result
   typ.align = int16(a)
 
-proc computeSize(typ: PType): BiggestInt = 
+proc computeSize(typ: PType): BiggestInt =
   var a: BiggestInt = 1
   result = computeSizeAux(typ, a)
 
@@ -1299,7 +1308,7 @@ proc getReturnType*(s: PSym): PType =
   assert s.kind in skProcKinds
   result = s.typ.sons[0]
 
-proc getSize(typ: PType): BiggestInt = 
+proc getSize(typ: PType): BiggestInt =
   result = computeSize(typ)
   if result < 0: internalError("getSize: " & $typ.kind)
 
@@ -1317,7 +1326,7 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
 
   return false
 
-proc containsGenericType*(t: PType): bool = 
+proc containsGenericType*(t: PType): bool =
   result = iterOverType(t, containsGenericTypeIter, nil)
 
 proc baseOfDistinct*(t: PType): PType =
@@ -1336,7 +1345,7 @@ proc baseOfDistinct*(t: PType): PType =
 
 proc safeInheritanceDiff*(a, b: PType): int =
   # same as inheritanceDiff but checks for tyError:
-  if a.kind == tyError or b.kind == tyError: 
+  if a.kind == tyError or b.kind == tyError:
     result = -1
   else:
     result = inheritanceDiff(a, b)
@@ -1356,7 +1365,7 @@ proc compatibleEffects*(formal, actual: PType): bool =
   assert formal.kind == tyProc and actual.kind == tyProc
   internalAssert formal.n.sons[0].kind == nkEffectList
   internalAssert actual.n.sons[0].kind == nkEffectList
-  
+
   var spec = formal.n.sons[0]
   if spec.len != 0:
     var real = actual.n.sons[0]
diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim
index 995fe7f50..700356ab7 100644
--- a/compiler/typesrenderer.nim
+++ b/compiler/typesrenderer.nim
@@ -68,7 +68,6 @@ proc renderType(n: PNode): string =
       assert n[i].kind == nkIdent
       result.add(',' & typeStr)
   of nkTupleTy:
-    assert len(n) > 0
     result = "tuple["
     for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
     result[<len(result)] = ']'
diff --git a/compiler/vm.nim b/compiler/vm.nim
index f0a0135e8..3b5c8e7f3 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -814,7 +814,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
               leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
         stackTrace(c, tos, pc, errGenerated,
           msgKindToString(errIllegalConvFromXtoY) % [
-          "unknown type" , "unknown type"])
+          $regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
     of opcIndCall, opcIndCallAsgn:
       # dest = call regStart, n; where regStart = fn, arg1, ...
       let rb = instr.regB
diff --git a/config/nim.cfg b/config/nim.cfg
index 32709137d..cb3f897d4 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -108,7 +108,7 @@ path="$lib/pure/unidecode"
   gcc.options.always = "-w"
   gcc.cpp.options.always = "-w -fpermissive"
 @else:
-  gcc.options.always = "-w" 
+  gcc.options.always = "-w"
   gcc.cpp.options.always = "-w -fpermissive"
 @end
 
@@ -151,7 +151,7 @@ clang.options.size = "-Os"
 vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
 vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
 vcc.options.always = "/nologo"
-vcc.options.speed = "/Ox /arch:SSE2"
+vcc.options.speed = "/O2 /arch:SSE2"
 vcc.options.size = "/O1"
 
 # Configuration for the Digital Mars C/C++ compiler:
diff --git a/doc/advopt.txt b/doc/advopt.txt
index d4b1b7e57..195122cc7 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -12,19 +12,6 @@ Advanced commands:
                             module dependency graph
   //dump                    dump all defined conditionals and search paths
   //check                   checks the project for syntax and semantic
-  //idetools                compiler support for IDEs: possible options:
-    --track:FILE,LINE,COL   track a file/cursor position
-    --trackDirty:DIRTY_FILE,ORIG_FILE,LINE,COL
-                            track a file, currently not saved to disk
-    --suggest               suggest all possible symbols at position
-    --def                   list all possible definitions at position
-    --context               list possible invocation context
-    --usages                list all usages of the symbol at position
-    --eval                  evaluates an expression
-  //serve                   start the compiler as a service mode (CAAS)
-    --server.type:TYPE      either stdin or tcp
-    --server.port:PORT      port for tcp mode, by default 6000
-    --server.address:HOST   binds to that address, by default ""
 
 Advanced options:
   -o, --out:FILE            set the output filename
@@ -81,7 +68,7 @@ Advanced options:
   --dynlibOverride:SYMBOL   marks SYMBOL so that dynlib:SYMBOL
                             has no effect and can be statically linked instead;
                             symbol matching is fuzzy so
-                            that --dynlibOverride:lua matches 
+                            that --dynlibOverride:lua matches
                             dynlib: "liblua.so.3"
   --listCmd                 list the commands used to execute external programs
   --parallelBuild:0|1|...   perform a parallel build
diff --git a/doc/basicopt.txt b/doc/basicopt.txt
index 7d08f1159..6a905bd53 100644
--- a/doc/basicopt.txt
+++ b/doc/basicopt.txt
@@ -29,6 +29,7 @@ Options:
   --infChecks:on|off        turn Inf checks on|off
   --deadCodeElim:on|off     whole program dead code elimination on|off
   --opt:none|speed|size     optimize not at all or for speed|size
+                            Note: use -d:release for a release build!
   --debugger:native|endb    use native debugger (gdb) | ENDB (experimental)
   --app:console|gui|lib|staticlib
                             generate a console app|GUI app|DLL|static library
diff --git a/doc/lib.txt b/doc/lib.txt
index 76920c6a9..385e7a91a 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -175,6 +175,9 @@ Generic Operating System Services
   This module implements the ability to monitor a directory/file for changes
   using Posix's inotify API.
 
+* `asyncfile <asyncfile.html>`_
+  This module implements asynchronous file reading and writing using
+  ``asyncdispatch``.
 
 Math libraries
 --------------
diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt
index f48dfc6b9..9b04bf518 100644
--- a/doc/manual/procs.txt
+++ b/doc/manual/procs.txt
@@ -351,7 +351,7 @@ dispatch.
 
 .. code-block:: nim
   type
-    Expression = object ## abstract base class for an expression
+    Expression = object of RootObj ## abstract base class for an expression
     Literal = object of Expression
       x: int
     PlusExpr = object of Expression
@@ -387,7 +387,7 @@ dispatching:
 
 .. code-block:: nim
   type
-    Thing = object
+    Thing = object of RootObj
     Unit = object of Thing
       x: int
       
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 0888a8767..f73dbd241 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -60,7 +60,7 @@ type
     nnkStmtListType, nnkBlockType,
     nnkWith, nnkWithout,
     nnkTypeOfExpr, nnkObjectTy,
-    nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
+    nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
     nnkRecList, nnkRecCase, nnkRecWhen,
     nnkRefTy, nnkPtrTy, nnkVarTy,
     nnkConstTy, nnkMutableTy,
diff --git a/lib/impure/osinfo_posix.nim b/lib/impure/osinfo_posix.nim
index 0ed4289c4..0362fca12 100644
--- a/lib/impure/osinfo_posix.nim
+++ b/lib/impure/osinfo_posix.nim
@@ -1,77 +1,10 @@
-import posix, strutils, os
-
-when false:
-  type
-    Tstatfs {.importc: "struct statfs64", 
-              header: "<sys/statfs.h>", final, pure.} = object
-      f_type: int
-      f_bsize: int
-      f_blocks: int
-      f_bfree: int
-      f_bavail: int
-      f_files: int
-      f_ffree: int
-      f_fsid: int
-      f_namelen: int
-
-  proc statfs(path: string, buf: var Tstatfs): int {.
-    importc, header: "<sys/vfs.h>".}
-
-
-proc getSystemVersion*(): string =
-  result = ""
-  
-  var unix_info: TUtsname
-  
-  if uname(unix_info) != 0:
-    os.raiseOSError(osLastError())
-  
-  if $unix_info.sysname == "Linux":
-    # Linux
-    result.add("Linux ")
-
-    result.add($unix_info.release & " ")
-    result.add($unix_info.machine)
-  elif $unix_info.sysname == "Darwin":
-    # Darwin
-    result.add("Mac OS X ")
-    if "14" in $unix_info.release:
-      result.add("v10.10 Yosemite")
-    elif "13" in $unix_info.release:
-      result.add("v10.9 Mavericks")
-    elif "12" in $unix_info.release:
-      result.add("v10.8 Mountian Lion")
-    elif "11" in $unix_info.release:
-      result.add("v10.7 Lion")
-    elif "10" in $unix_info.release:
-      result.add("v10.6 Snow Leopard")
-    elif "9" in $unix_info.release:
-      result.add("v10.5 Leopard")
-    elif "8" in $unix_info.release:
-      result.add("v10.4 Tiger")
-    elif "7" in $unix_info.release:
-      result.add("v10.3 Panther")
-    elif "6" in $unix_info.release:
-      result.add("v10.2 Jaguar")
-    elif "1.4" in $unix_info.release:
-      result.add("v10.1 Puma")
-    elif "1.3" in $unix_info.release:
-      result.add("v10.0 Cheetah")
-    elif "0" in $unix_info.release:
-      result.add("Server 1.0 Hera")
-  else:
-    result.add($unix_info.sysname & " " & $unix_info.release)
-    
-    
-when false:
-  var unix_info: TUtsname
-  echo(uname(unix_info))
-  echo(unix_info.sysname)
-  echo("8" in $unix_info.release)
-
-  echo(getSystemVersion())
-
-  var stfs: TStatfs
-  echo(statfs("sysinfo_posix.nim", stfs))
-  echo(stfs.f_files)
-  
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.error: "This module has been moved to the 'osinfo' nimble package.".}
diff --git a/lib/impure/osinfo_win.nim b/lib/impure/osinfo_win.nim
index 94a27eb03..0362fca12 100644
--- a/lib/impure/osinfo_win.nim
+++ b/lib/impure/osinfo_win.nim
@@ -1,411 +1,10 @@
-# XXX clean up this mess!
-
-import winlean
-
-const
-  INVALID_HANDLE_VALUE = int(- 1) # GetStockObject
-
-type
-  TMEMORYSTATUSEX {.final, pure.} = object
-    dwLength: int32
-    dwMemoryLoad: int32
-    ullTotalPhys: int64
-    ullAvailPhys: int64
-    ullTotalPageFile: int64
-    ullAvailPageFile: int64
-    ullTotalVirtual: int64
-    ullAvailVirtual: int64
-    ullAvailExtendedVirtual: int64
-    
-  SYSTEM_INFO* {.final, pure.} = object
-    wProcessorArchitecture*: int16
-    wReserved*: int16
-    dwPageSize*: int32
-    lpMinimumApplicationAddress*: pointer
-    lpMaximumApplicationAddress*: pointer
-    dwActiveProcessorMask*: int32
-    dwNumberOfProcessors*: int32
-    dwProcessorType*: int32
-    dwAllocationGranularity*: int32
-    wProcessorLevel*: int16
-    wProcessorRevision*: int16
-
-  LPSYSTEM_INFO* = ptr SYSTEM_INFO
-  TSYSTEMINFO* = SYSTEM_INFO
-
-  TMemoryInfo* = object
-    MemoryLoad*: int ## occupied memory, in percent
-    TotalPhysMem*: int64 ## Total Physical memory, in bytes
-    AvailablePhysMem*: int64 ## Available physical memory, in bytes
-    TotalPageFile*: int64 ## The current committed memory limit 
-                          ## for the system or the current process, whichever is smaller, in bytes.
-    AvailablePageFile*: int64 ## The maximum amount of memory the current process can commit, in bytes.
-    TotalVirtualMem*: int64 ## Total virtual memory, in bytes
-    AvailableVirtualMem*: int64 ## Available virtual memory, in bytes
-    
-  TOSVERSIONINFOEX {.final, pure.} = object
-    dwOSVersionInfoSize: int32
-    dwMajorVersion: int32
-    dwMinorVersion: int32
-    dwBuildNumber: int32
-    dwPlatformId: int32
-    szCSDVersion: array[0..127, char]
-    wServicePackMajor: int16
-    wServicePackMinor: int16
-    wSuiteMask: int16
-    wProductType: int8
-    wReserved: char
-    
-  TVersionInfo* = object
-    majorVersion*: int
-    minorVersion*: int
-    buildNumber*: int
-    platformID*: int
-    SPVersion*: string ## Full Service pack version string
-    SPMajor*: int ## Major service pack version
-    SPMinor*: int ## Minor service pack version
-    SuiteMask*: int
-    ProductType*: int
-    
-  TPartitionInfo* = tuple[FreeSpace, TotalSpace: Tfiletime]
-  
-const
-  # SuiteMask - VersionInfo.SuiteMask
-  VER_SUITE_BACKOFFICE* = 0x00000004
-  VER_SUITE_BLADE* = 0x00000400
-  VER_SUITE_COMPUTE_SERVER* = 0x00004000
-  VER_SUITE_DATACENTER* = 0x00000080
-  VER_SUITE_ENTERPRISE* = 0x00000002
-  VER_SUITE_EMBEDDEDNT* = 0x00000040
-  VER_SUITE_PERSONAL* = 0x00000200
-  VER_SUITE_SINGLEUSERTS* = 0x00000100
-  VER_SUITE_SMALLBUSINESS* = 0x00000001
-  VER_SUITE_SMALLBUSINESS_RESTRICTED* = 0x00000020
-  VER_SUITE_STORAGE_SERVER* = 0x00002000
-  VER_SUITE_TERMINAL* = 0x00000010
-  VER_SUITE_WH_SERVER* = 0x00008000
-
-  # ProductType - VersionInfo.ProductType
-  VER_NT_DOMAIN_CONTROLLER* = 0x0000002
-  VER_NT_SERVER* = 0x0000003
-  VER_NT_WORKSTATION* = 0x0000001
-  
-  VER_PLATFORM_WIN32_NT* = 2
-  
-  # Product Info - getProductInfo() - (Remove unused ones ?)
-  PRODUCT_BUSINESS* = 0x00000006
-  PRODUCT_BUSINESS_N* = 0x00000010
-  PRODUCT_CLUSTER_SERVER* = 0x00000012
-  PRODUCT_DATACENTER_SERVER* = 0x00000008
-  PRODUCT_DATACENTER_SERVER_CORE* = 0x0000000C
-  PRODUCT_DATACENTER_SERVER_CORE_V* = 0x00000027
-  PRODUCT_DATACENTER_SERVER_V* = 0x00000025
-  PRODUCT_ENTERPRISE* = 0x00000004
-  PRODUCT_ENTERPRISE_E* = 0x00000046
-  PRODUCT_ENTERPRISE_N* = 0x0000001B
-  PRODUCT_ENTERPRISE_SERVER* = 0x0000000A
-  PRODUCT_ENTERPRISE_SERVER_CORE* = 0x0000000E
-  PRODUCT_ENTERPRISE_SERVER_CORE_V* = 0x00000029
-  PRODUCT_ENTERPRISE_SERVER_IA64* = 0x0000000F
-  PRODUCT_ENTERPRISE_SERVER_V* = 0x00000026
-  PRODUCT_HOME_BASIC* = 0x00000002
-  PRODUCT_HOME_BASIC_E* = 0x00000043
-  PRODUCT_HOME_BASIC_N* = 0x00000005
-  PRODUCT_HOME_PREMIUM* = 0x00000003
-  PRODUCT_HOME_PREMIUM_E* = 0x00000044
-  PRODUCT_HOME_PREMIUM_N* = 0x0000001A
-  PRODUCT_HYPERV* = 0x0000002A
-  PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT* = 0x0000001E
-  PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING* = 0x00000020
-  PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY* = 0x0000001F
-  PRODUCT_PROFESSIONAL* = 0x00000030
-  PRODUCT_PROFESSIONAL_E* = 0x00000045
-  PRODUCT_PROFESSIONAL_N* = 0x00000031
-  PRODUCT_SERVER_FOR_SMALLBUSINESS* = 0x00000018
-  PRODUCT_SERVER_FOR_SMALLBUSINESS_V* = 0x00000023
-  PRODUCT_SERVER_FOUNDATION* = 0x00000021
-  PRODUCT_SMALLBUSINESS_SERVER* = 0x00000009
-  PRODUCT_STANDARD_SERVER* = 0x00000007
-  PRODUCT_STANDARD_SERVER_CORE * = 0x0000000D
-  PRODUCT_STANDARD_SERVER_CORE_V* = 0x00000028
-  PRODUCT_STANDARD_SERVER_V* = 0x00000024
-  PRODUCT_STARTER* = 0x0000000B
-  PRODUCT_STARTER_E* = 0x00000042
-  PRODUCT_STARTER_N* = 0x0000002F
-  PRODUCT_STORAGE_ENTERPRISE_SERVER* = 0x00000017
-  PRODUCT_STORAGE_EXPRESS_SERVER* = 0x00000014
-  PRODUCT_STORAGE_STANDARD_SERVER* = 0x00000015
-  PRODUCT_STORAGE_WORKGROUP_SERVER* = 0x00000016
-  PRODUCT_UNDEFINED* = 0x00000000
-  PRODUCT_ULTIMATE* = 0x00000001
-  PRODUCT_ULTIMATE_E* = 0x00000047
-  PRODUCT_ULTIMATE_N* = 0x0000001C
-  PRODUCT_WEB_SERVER* = 0x00000011
-  PRODUCT_WEB_SERVER_CORE* = 0x0000001D
-  
-  PROCESSOR_ARCHITECTURE_AMD64* = 9 ## x64 (AMD or Intel)
-  PROCESSOR_ARCHITECTURE_IA64* = 6 ## Intel Itanium Processor Family (IPF)
-  PROCESSOR_ARCHITECTURE_INTEL* = 0 ## x86
-  PROCESSOR_ARCHITECTURE_UNKNOWN* = 0xffff ## Unknown architecture.
-  
-  # GetSystemMetrics
-  SM_SERVERR2 = 89 
-  
-proc globalMemoryStatusEx*(lpBuffer: var TMEMORYSTATUSEX){.stdcall, dynlib: "kernel32",
-    importc: "GlobalMemoryStatusEx".}
-    
-proc getMemoryInfo*(): TMemoryInfo =
-  ## Retrieves memory info
-  var statex: TMEMORYSTATUSEX
-  statex.dwLength = sizeof(statex).int32
-
-  globalMemoryStatusEx(statex)
-  result.MemoryLoad = statex.dwMemoryLoad
-  result.TotalPhysMem = statex.ullTotalPhys
-  result.AvailablePhysMem = statex.ullAvailPhys
-  result.TotalPageFile = statex.ullTotalPageFile
-  result.AvailablePageFile = statex.ullAvailPageFile
-  result.TotalVirtualMem = statex.ullTotalVirtual
-  result.AvailableVirtualMem = statex.ullAvailExtendedVirtual
-
-proc getVersionEx*(lpVersionInformation: var TOSVERSIONINFOEX): WINBOOL{.stdcall,
-    dynlib: "kernel32", importc: "GetVersionExA".}
-
-proc getProcAddress*(hModule: int, lpProcName: cstring): pointer{.stdcall,
-    dynlib: "kernel32", importc: "GetProcAddress".}
-
-proc getModuleHandleA*(lpModuleName: cstring): int{.stdcall,
-     dynlib: "kernel32", importc: "GetModuleHandleA".}
-
-proc getVersionInfo*(): TVersionInfo =
-  ## Retrieves operating system info
-  var osvi: TOSVERSIONINFOEX
-  osvi.dwOSVersionInfoSize = sizeof(osvi).int32
-  discard getVersionEx(osvi)
-  result.majorVersion = osvi.dwMajorVersion
-  result.minorVersion = osvi.dwMinorVersion
-  result.buildNumber = osvi.dwBuildNumber
-  result.platformID = osvi.dwPlatformId
-  result.SPVersion = $osvi.szCSDVersion
-  result.SPMajor = osvi.wServicePackMajor
-  result.SPMinor = osvi.wServicePackMinor
-  result.SuiteMask = osvi.wSuiteMask
-  result.ProductType = osvi.wProductType
-
-proc getProductInfo*(majorVersion, minorVersion, SPMajorVersion, 
-                     SPMinorVersion: int): int =
-  ## Retrieves Windows' ProductInfo, this function only works in Vista and 7
-  var pGPI = cast[proc (dwOSMajorVersion, dwOSMinorVersion, 
-              dwSpMajorVersion, dwSpMinorVersion: int32, outValue: Pint32){.stdcall.}](getProcAddress(
-                getModuleHandleA("kernel32.dll"), "GetProductInfo"))
-                
-  if pGPI != nil:
-    var dwType: int32
-    pGPI(int32(majorVersion), int32(minorVersion), int32(SPMajorVersion), int32(SPMinorVersion), addr(dwType))
-    result = int(dwType)
-  else:
-    return PRODUCT_UNDEFINED
-
-proc getSystemInfo*(lpSystemInfo: LPSYSTEM_INFO){.stdcall, dynlib: "kernel32",
-    importc: "GetSystemInfo".}
-    
-proc getSystemInfo*(): TSYSTEM_INFO =
-  ## Returns the SystemInfo
-
-  # Use GetNativeSystemInfo if it's available
-  var pGNSI = cast[proc (lpSystemInfo: LPSYSTEM_INFO){.stdcall.}](getProcAddress(
-                getModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"))
-                
-  var systemi: TSYSTEM_INFO              
-  if pGNSI != nil:
-    pGNSI(addr(systemi))
-  else:
-    getSystemInfo(addr(systemi))
-
-  return systemi
-
-proc getSystemMetrics*(nIndex: int32): int32{.stdcall, dynlib: "user32",
-    importc: "GetSystemMetrics".}
-
-proc `$`*(osvi: TVersionInfo): string =
-  ## Turns a VersionInfo object, into a string
-
-  if osvi.platformID == VER_PLATFORM_WIN32_NT and osvi.majorVersion > 4:
-    result = "Microsoft "
-    
-    var si = getSystemInfo()
-    # Test for the specific product
-    if osvi.majorVersion == 6:
-      if osvi.minorVersion == 0:
-        if osvi.ProductType == VER_NT_WORKSTATION:
-          result.add("Windows Vista ")
-        else: result.add("Windows Server 2008 ")
-      elif osvi.minorVersion == 1:
-        if osvi.ProductType == VER_NT_WORKSTATION:
-          result.add("Windows 7 ")
-        else: result.add("Windows Server 2008 R2 ")
-      elif osvi.minorVersion == 2:
-        if osvi.ProductType == VER_NT_WORKSTATION:
-          result.add("Windows 8 ")
-        else: result.add("Windows Server 2012 ")
-      elif osvi.minorVersion == 3:
-        if osvi.ProductType == VER_NT_WORKSTATION:
-          result.add("Windows 8.1 ")
-        else: result.add("Windows Server 2012 R2 ")
-    
-      var dwType = getProductInfo(osvi.majorVersion, osvi.minorVersion, 0, 0)
-      case dwType
-      of PRODUCT_ULTIMATE:
-        result.add("Ultimate Edition")
-      of PRODUCT_PROFESSIONAL:
-        result.add("Professional")
-      of PRODUCT_HOME_PREMIUM:
-        result.add("Home Premium Edition")
-      of PRODUCT_HOME_BASIC:
-        result.add("Home Basic Edition")
-      of PRODUCT_ENTERPRISE:
-        result.add("Enterprise Edition")
-      of PRODUCT_BUSINESS:
-        result.add("Business Edition")
-      of PRODUCT_STARTER:
-        result.add("Starter Edition")
-      of PRODUCT_CLUSTER_SERVER:
-        result.add("Cluster Server Edition")
-      of PRODUCT_DATACENTER_SERVER:
-        result.add("Datacenter Edition")
-      of PRODUCT_DATACENTER_SERVER_CORE:
-        result.add("Datacenter Edition (core installation)")
-      of PRODUCT_ENTERPRISE_SERVER:
-        result.add("Enterprise Edition")
-      of PRODUCT_ENTERPRISE_SERVER_CORE:
-        result.add("Enterprise Edition (core installation)")
-      of PRODUCT_ENTERPRISE_SERVER_IA64:
-        result.add("Enterprise Edition for Itanium-based Systems")
-      of PRODUCT_SMALLBUSINESS_SERVER:
-        result.add("Small Business Server")
-      of PRODUCT_STANDARD_SERVER:
-        result.add("Standard Edition")
-      of PRODUCT_STANDARD_SERVER_CORE:
-        result.add("Standard Edition (core installation)")
-      of PRODUCT_WEB_SERVER:
-        result.add("Web Server Edition")
-      else:
-        discard
-    # End of Windows 6.*
-
-    if osvi.majorVersion == 5 and osvi.minorVersion == 2:
-      if getSystemMetrics(SM_SERVERR2) != 0:
-        result.add("Windows Server 2003 R2, ")
-      elif (osvi.SuiteMask and VER_SUITE_PERSONAL) != 0: # Not sure if this will work
-        result.add("Windows Storage Server 2003")
-      elif (osvi.SuiteMask and VER_SUITE_WH_SERVER) != 0:
-        result.add("Windows Home Server")
-      elif osvi.ProductType == VER_NT_WORKSTATION and 
-          si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64:
-        result.add("Windows XP Professional x64 Edition")
-      else:
-        result.add("Windows Server 2003, ")
-      
-      # Test for the specific product
-      if osvi.ProductType != VER_NT_WORKSTATION:
-        if ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_IA64:
-          if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-            result.add("Datacenter Edition for Itanium-based Systems")
-          elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-            result.add("Enterprise Edition for Itanium-based Systems")
-        elif ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_AMD64:
-          if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-            result.add("Datacenter x64 Edition")
-          elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-            result.add("Enterprise x64 Edition")
-          else:
-            result.add("Standard x64 Edition")
-        else:
-          if (osvi.SuiteMask and VER_SUITE_COMPUTE_SERVER) != 0:
-            result.add("Compute Cluster Edition")
-          elif (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-            result.add("Datacenter Edition")
-          elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-            result.add("Enterprise Edition")
-          elif (osvi.SuiteMask and VER_SUITE_BLADE) != 0:
-            result.add("Web Edition")
-          else:
-            result.add("Standard Edition")
-    # End of 5.2
-    
-    if osvi.majorVersion == 5 and osvi.minorVersion == 1:
-      result.add("Windows XP ")
-      if (osvi.SuiteMask and VER_SUITE_PERSONAL) != 0:
-        result.add("Home Edition")
-      else:
-        result.add("Professional")
-    # End of 5.1
-    
-    if osvi.majorVersion == 5 and osvi.minorVersion == 0:
-      result.add("Windows 2000 ")
-      if osvi.ProductType == VER_NT_WORKSTATION:
-        result.add("Professional")
-      else:
-        if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-          result.add("Datacenter Server")
-        elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-          result.add("Advanced Server")
-        else:
-          result.add("Server")
-    # End of 5.0
-    
-    # Include service pack (if any) and build number.
-    if len(osvi.SPVersion) > 0:
-      result.add(" ")
-      result.add(osvi.SPVersion)
-    
-    result.add(" (build " & $osvi.buildNumber & ")")
-    
-    if osvi.majorVersion >= 6:
-      if ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_AMD64:
-        result.add(", 64-bit")
-      elif ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_INTEL:
-        result.add(", 32-bit")
-    
-  else:
-    # Windows 98 etc...
-    result = "Unknown version of windows[Kernel version <= 4]"
-    
-
-proc getFileSize*(file: string): BiggestInt =
-  var fileData: TWIN32_FIND_DATA
-
-  when useWinUnicode:
-    var aa = newWideCString(file)
-    var hFile = findFirstFileW(aa, fileData)
-  else:
-    var hFile = findFirstFileA(file, fileData)
-  
-  if hFile == INVALID_HANDLE_VALUE:
-    raise newException(IOError, $getLastError())
-  
-  return fileData.nFileSizeLow
-
-proc getDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
-                         lpTotalNumberOfBytes,
-                         lpTotalNumberOfFreeBytes: var TFiletime): WINBOOL{.
-    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}
-
-proc getPartitionInfo*(partition: string): TPartitionInfo =
-  ## Retrieves partition info, for example ``partition`` may be ``"C:\"``
-  var freeBytes, totalBytes, totalFreeBytes: TFiletime 
-  discard getDiskFreeSpaceEx(r"C:\", freeBytes, totalBytes, 
-                               totalFreeBytes)
-  return (freeBytes, totalBytes)
-
-when isMainModule:
-  var r = getMemoryInfo()
-  echo("Memory load: ", r.MemoryLoad, "%")
-  
-  var osvi = getVersionInfo()
-  
-  echo($osvi)
-
-  echo(getFileSize(r"lib\impure\osinfo_win.nim") div 1024, " KB")
-  
-  echo(rdFileTime(getPartitionInfo(r"C:\")[0]))
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.error: "This module has been moved to the 'osinfo' nimble package.".}
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
index aaf2ed1ca..55f8c5d32 100644
--- a/lib/impure/rdstdin.nim
+++ b/lib/impure/rdstdin.nim
@@ -8,16 +8,16 @@
 #
 
 ## This module contains code for reading from `stdin`:idx:. On UNIX the GNU
-## readline library is wrapped and set up to provide default key bindings 
+## readline library is wrapped and set up to provide default key bindings
 ## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine``
-## is used. This suffices because Windows' console already provides the 
+## is used. This suffices because Windows' console already provides the
 ## wanted functionality.
 
 {.deadCodeElim: on.}
 
 when defined(Windows):
   proc readLineFromStdin*(prompt: string): TaintedString {.
-                          tags: [ReadIOEffect, WriteIOEffect].} = 
+                          tags: [ReadIOEffect, WriteIOEffect].} =
     ## Reads a line from stdin.
     stdout.write(prompt)
     result = readLine(stdin)
@@ -33,27 +33,71 @@ when defined(Windows):
     stdout.write(prompt)
     result = readLine(stdin, line)
 
+  import winlean
+
+  const
+    VK_SHIFT* = 16
+    VK_CONTROL* = 17
+    VK_MENU* = 18
+    KEY_EVENT* = 1
+
+  type
+    KEY_EVENT_RECORD = object
+      bKeyDown: WinBool
+      wRepeatCount: uint16
+      wVirtualKeyCode: uint16
+      wVirtualScanCode: uint16
+      unicodeChar: uint16
+      dwControlKeyState: uint32
+    INPUT_RECORD = object
+      eventType*: int16
+      reserved*: int16
+      event*: KEY_EVENT_RECORD
+      safetyBuffer: array[0..5, DWORD]
+
+  proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD,
+                          nLength: uint32,
+                          lpNumberOfEventsRead: var uint32): WINBOOL{.
+      stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}
+
+  proc getch(): uint16 =
+    let hStdin = getStdHandle(STD_INPUT_HANDLE)
+    var
+      irInputRecord: INPUT_RECORD
+      dwEventsRead: uint32
+
+    while readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) != 0:
+      if irInputRecord.eventType == KEY_EVENT and
+          irInputRecord.event.wVirtualKeyCode notin {VK_SHIFT, VK_MENU, VK_CONTROL}:
+         result = irInputRecord.event.unicodeChar
+         discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead)
+         return result
+
+  from unicode import toUTF8, Rune, runeLenAt
+
   proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
                               bool {.tags: [ReadIOEffect, WriteIOEffect].} =
     ## Reads a `password` from stdin without printing it. `password` must not
     ## be ``nil``! Returns ``false`` if the end of the file has been reached,
     ## ``true`` otherwise.
-    proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
-
     password.setLen(0)
-    var c: char
     stdout.write(prompt)
     while true:
-      c = getch().char
-      case c
+      let c = getch()
+      case c.char
       of '\r', chr(0xA):
         break
       of '\b':
-        password.setLen(password.len - 1)
+        # ensure we delete the whole UTF-8 character:
+        var i = 0
+        var x = 1
+        while i < password.len:
+          x = runeLenAt(password, i)
+          inc i, x
+        password.setLen(password.len - x)
       else:
-        password.add(c)
+        password.add(toUTF8(c.Rune))
     stdout.write "\n"
-    # TODO: How to detect EOF on Windows?
 
 else:
   import readline, history, termios, unsigned
diff --git a/lib/nimbase.h b/lib/nimbase.h
index a1d4d1e27..e9dad0bb7 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -406,4 +406,6 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
 #  include <sys/types.h>
 #  include <types/vxWind.h>
 #  include <tool/gnu/toolMacros.h>
+#elif defined(__FreeBSD__)
+#  include <sys/types.h>
 #endif
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 20976e788..08d224dfd 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -11,15 +11,15 @@
 
 type
   SortOrder* = enum   ## sort order
-    Descending, Ascending 
+    Descending, Ascending
 
 {.deprecated: [TSortOrder: SortOrder].}
 
 
-proc `*`*(x: int, order: SortOrder): int {.inline.} = 
+proc `*`*(x: int, order: SortOrder): int {.inline.} =
   ## flips `x` if ``order == Descending``;
   ## if ``order == Ascending`` then `x` is returned.
-  ## `x` is supposed to be the result of a comparator, ie ``< 0`` for 
+  ## `x` is supposed to be the result of a comparator, ie ``< 0`` for
   ## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
   var y = order.ord - 1
   result = (x xor y) - y
@@ -73,14 +73,15 @@ const
   onlySafeCode = true
 
 proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
-  ## same as binarySearch except that if key is not in `a` then this 
+  ## same as binarySearch except that if key is not in `a` then this
   ## returns the location where `key` would be if it were. In other
-  ## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm))
-  ## the sequence will still be sorted
+  ## words if you have a sorted sequence and you call
+  ## insert(thing, elm, lowerBound(thing, elm))
+  ## the sequence will still be sorted.
+  ##
+  ## `cmp` is the comparator function to use, the expected return values are
+  ## the same as that of system.cmp.
   ##
-  ## `cmp` is the comparator function to use, the expected return values are the same as
-  ## that of system.cmp
-  ## 
   ## example::
   ##
   ##   var arr = @[1,2,3,5,6,7,8,9]
@@ -102,9 +103,9 @@ proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.})
       count = step
 
 proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
-proc merge[T](a, b: var openArray[T], lo, m, hi: int, 
+proc merge[T](a, b: var openArray[T], lo, m, hi: int,
               cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
-  template `<-` (a, b: expr) = 
+  template `<-` (a, b: expr) =
     when false:
       a = b
     elif onlySafeCode:
@@ -151,10 +152,10 @@ proc merge[T](a, b: var openArray[T], lo, m, hi: int,
 proc sort*[T](a: var openArray[T],
               cmp: proc (x, y: T): int {.closure.},
               order = SortOrder.Ascending) =
-  ## Default Nim sort. The sorting is guaranteed to be stable and 
+  ## Default Nim sort. The sorting is guaranteed to be stable and
   ## the worst case is guaranteed to be O(n log n).
   ## The current implementation uses an iterative
-  ## mergesort to achieve this. It uses a temporary sequence of 
+  ## mergesort to achieve this. It uses a temporary sequence of
   ## length ``a.len div 2``. Currently Nim does not support a
   ## sensible default argument for ``cmp``, so you have to provide one
   ## of your own. However, the ``system.cmp`` procs can be used:
@@ -187,14 +188,15 @@ proc sort*[T](a: var openArray[T],
       dec(m, s*2)
     s = s*2
 
-proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, order = SortOrder.Ascending): seq[T] =
+proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
+                order = SortOrder.Ascending): seq[T] =
   ## returns `a` sorted by `cmp` in the specified `order`.
   result = newSeq[T](a.len)
   for i in 0 .. a.high:
     result[i] = a[i]
   sort(result, cmp, order)
 
-template sortByIt*(seq1, op: expr): expr =
+template sortedByIt*(seq1, op: expr): expr =
   ## Convenience template around the ``sorted`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
@@ -202,10 +204,23 @@ template sortByIt*(seq1, op: expr): expr =
   ##
   ## .. code-block:: nim
   ##
-  ##     var users: seq[tuple[id: int, name: string]] =
-  ##       @[(0, "Smith"), (1, "Pratt"), (2, "Sparrow")]
+  ##   type Person = tuple[name: string, age: int]
+  ##   var
+  ##     p1: Person = (name: "p1", age: 60)
+  ##     p2: Person = (name: "p2", age: 20)
+  ##     p3: Person = (name: "p3", age: 30)
+  ##     p4: Person = (name: "p4", age: 30)
+  ##
+  ##   people = @[p1,p2,p4,p3]
+  ##
+  ##   echo people.sortedByIt(it.name)
+  ##
+  ## Because the underlying ``cmp()`` is defined for tuples you can do
+  ## a nested sort like in the following example:
+  ##
+  ## .. code-block:: nim
   ##
-  ##     echo users.sortByIt(it.name)
+  ##   echo people.sortedByIt((it.age, it.name))
   ##
   var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
     var it {.inject.} = x
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index d6ed66030..a8caf809e 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -121,7 +121,7 @@ export Port, SocketFlag
 ##
 ## Limitations/Bugs
 ## ----------------
-## 
+##
 ## * ``except`` statement (without `try`) does not work inside async procedures.
 ## * The effect system (``raises: []``) does not work with async procedures.
 ## * Can't await in a ``except`` body
@@ -379,7 +379,7 @@ when defined(windows) or defined(nimdoc):
     if p.handles.len == 0 and p.timers.len == 0:
       raise newException(ValueError,
         "No handles or timers registered in dispatcher.")
-    
+
     let llTimeout =
       if timeout ==  -1: winlean.INFINITE
       else: timeout.int32
@@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc):
     if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
       raiseOSError(osLastError())
 
-  proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint, 
+  proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
                   lpSendBuffer: pointer, dwSendDataLength: Dword,
                   lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
     if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
     let fun =
-      cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, 
+      cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
          lpSendBuffer: pointer, dwSendDataLength: Dword,
          lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
 
@@ -475,7 +475,7 @@ when defined(windows) or defined(nimdoc):
                  dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
                  LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
                 RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
-    
+
     fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
                   dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
                   RemoteSockaddr, RemoteSockaddrLength)
@@ -514,7 +514,7 @@ when defined(windows) or defined(nimdoc):
             else:
               retFuture.fail(newException(OSError, osErrorMsg(errcode)))
       )
-      
+
       var ret = connectEx(socket.SocketHandle, it.ai_addr,
                           sizeof(Sockaddr_in).cint, nil, 0, nil,
                           cast[POVERLAPPED](ol))
@@ -565,7 +565,7 @@ when defined(windows) or defined(nimdoc):
     var dataBuf: TWSABuf
     dataBuf.buf = cast[cstring](alloc0(size))
     dataBuf.len = size
-    
+
     var bytesReceived: Dword
     var flagsio = flags.toOSFlags().Dword
     var ol = PCustomOverlapped()
@@ -612,9 +612,9 @@ when defined(windows) or defined(nimdoc):
       # the empty string (which signals a disconnection) when there is
       # nothing left to read.
       retFuture.complete("")
-      # TODO: "For message-oriented sockets, where a zero byte message is often 
-      # allowable, a failure with an error code of WSAEDISCON is used to 
-      # indicate graceful closure." 
+      # TODO: "For message-oriented sockets, where a zero byte message is often
+      # allowable, a failure with an error code of WSAEDISCON is used to
+      # indicate graceful closure."
       # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
     else:
       # Request to read completed immediately.
@@ -748,7 +748,7 @@ when defined(windows) or defined(nimdoc):
 
     # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
     let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
-                       dwReceiveDataLength, 
+                       dwReceiveDataLength,
                        dwLocalAddressLength,
                        dwRemoteAddressLength,
                        addr dwBytesReceived, cast[POVERLAPPED](ol))
@@ -803,7 +803,7 @@ else:
   else:
     from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
                       MSG_NOSIGNAL
-  
+
   type
     TAsyncFD* = distinct cint
     TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
@@ -849,7 +849,7 @@ else:
     result = newRawSocket(domain, typ, protocol).TAsyncFD
     result.SocketHandle.setBlocking(false)
     register(result)
-  
+
   proc closeSocket*(sock: TAsyncFD) =
     let disp = getGlobalDispatcher()
     sock.SocketHandle.close()
@@ -864,14 +864,14 @@ else:
       raise newException(ValueError, "File descriptor not registered.")
     p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
     update(fd, p.selector[fd.SocketHandle].events + {EvRead})
-  
+
   proc addWrite*(fd: TAsyncFD, cb: TCallback) =
     let p = getGlobalDispatcher()
     if fd.SocketHandle notin p.selector:
       raise newException(ValueError, "File descriptor not registered.")
     p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
     update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
-  
+
   proc poll*(timeout = 500) =
     let p = getGlobalDispatcher()
     for info in p.selector.select(timeout):
@@ -892,7 +892,7 @@ else:
           if not cb(data.fd):
             # Callback wants to be called again.
             data.readCBs.add(cb)
-      
+
       if EvWrite in info.events:
         let currentCBs = data.writeCBs
         data.writeCBs = @[]
@@ -900,7 +900,7 @@ else:
           if not cb(data.fd):
             # Callback wants to be called again.
             data.writeCBs.add(cb)
-      
+
       if info.key in p.selector:
         var newEvents: set[Event]
         if data.readCBs.len != 0: newEvents = {EvRead}
@@ -913,16 +913,16 @@ else:
         discard
 
     processTimers(p)
-  
+
   proc connect*(socket: TAsyncFD, address: string, port: Port,
     af = AF_INET): Future[void] =
     var retFuture = newFuture[void]("connect")
-    
+
     proc cb(fd: TAsyncFD): bool =
       # We have connected.
       retFuture.complete()
       return true
-    
+
     var aiList = getAddrInfo(address, port, af)
     var success = false
     var lastError: OSErrorCode
@@ -952,7 +952,7 @@ else:
   proc recv*(socket: TAsyncFD, size: int,
              flags = {SocketFlag.SafeDisconn}): Future[string] =
     var retFuture = newFuture[string]("recv")
-    
+
     var readBuffer = newString(size)
 
     proc cb(sock: TAsyncFD): bool =
@@ -983,9 +983,9 @@ else:
   proc send*(socket: TAsyncFD, data: string,
              flags = {SocketFlag.SafeDisconn}): Future[void] =
     var retFuture = newFuture[void]("send")
-    
+
     var written = 0
-    
+
     proc cb(sock: TAsyncFD): bool =
       result = true
       let netSize = data.len-written
@@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
   of nnkTryStmt:
     # try: await x; except: ...
     result = newNimNode(nnkStmtList, node)
-    template wrapInTry(n, tryBody: PNimrodNode) =
+    template wrapInTry(n, tryBody: expr) =
       var temp = n
       n[0] = tryBody
       tryBody = temp
@@ -1315,29 +1315,40 @@ macro async*(prc: stmt): stmt {.immediate.} =
     if returnType.kind == nnkEmpty: newIdentNode("void")
     else: returnType[1]
   outerProcBody.add(
-    newVarStmt(retFutureSym, 
+    newVarStmt(retFutureSym,
       newCall(
         newNimNode(nnkBracketExpr, prc[6]).add(
           newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
           subRetType),
       newLit(prc[0].getName)))) # Get type from return type of this proc
-  
-  # -> iterator nameIter(): FutureBase {.closure.} = 
+
+  # -> iterator nameIter(): FutureBase {.closure.} =
+  # ->   {.push warning[resultshadowed]: off.}
   # ->   var result: T
+  # ->   {.pop.}
   # ->   <proc_body>
   # ->   complete(retFuture, result)
   var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
   var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
   if not subtypeIsVoid:
-    procBody.insert(0, newNimNode(nnkVarSection, prc[6]).add(
+    procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
+      newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
+        newIdentNode("warning"), newIdentNode("resultshadowed")),
+      newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
+
+    procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
       newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
+
+    procBody.insert(2, newNimNode(nnkPragma).add(
+      newIdentNode("pop"))) # -> {.pop.})
+
     procBody.add(
       newCall(newIdentNode("complete"),
         retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
   else:
     # -> complete(retFuture)
     procBody.add(newCall(newIdentNode("complete"), retFutureSym))
-  
+
   var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
                                 procBody, nnkIteratorDef)
   closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
@@ -1351,7 +1362,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
 
   # -> return retFuture
   outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
-  
+
   result = prc
 
   # Remove the 'async' pragma.
@@ -1377,7 +1388,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ## If a full line is read ``\r\L`` is not
   ## added to ``line``, however if solely ``\r\L`` is read then ``line``
   ## will be set to it.
-  ## 
+  ##
   ## If the socket is disconnected, ``line`` will be set to ``""``.
   ##
   ## If the socket is disconnected in the middle of a line (before ``\r\L``
@@ -1388,7 +1399,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ##
   ## **Note**: This procedure is mostly used for testing. You likely want to
   ## use ``asyncnet.recvLine`` instead.
-  
+
   template addNLIfEmpty(): stmt =
     if result.len == 0:
       result.add("\c\L")
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index 752c01eac..25e121183 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements asynchronous file handling.
+## This module implements asynchronous file reading and writing.
 ##
 ## .. code-block:: Nim
 ##    import asyncfile, asyncdispatch, os
@@ -24,17 +24,17 @@
 
 import asyncdispatch, os
 
-when defined(windows):
+when defined(windows) or defined(nimdoc):
   import winlean
 else:
   import posix
 
 type
-  AsyncFile = ref object
+  AsyncFile* = ref object
     fd: TAsyncFd
     offset: int64
 
-when defined(windows):
+when defined(windows) or defined(nimdoc):
   proc getDesiredAccess(mode: FileMode): int32 =
     case mode
     of fmRead:
@@ -70,7 +70,7 @@ else:
 
 proc getFileSize(f: AsyncFile): int64 =
   ## Retrieves the specified file's size.
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     var high: DWord
     let low = getFileSize(f.fd.THandle, addr high)
     if low == INVALID_FILE_SIZE:
@@ -81,7 +81,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
   ## Opens a file specified by the path in ``filename`` using
   ## the specified ``mode`` asynchronously.
   new result
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
     let desiredAccess = getDesiredAccess(mode)
     let creationDisposition = getCreationDisposition(mode, filename)
@@ -120,7 +120,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
   ## returned.
   var retFuture = newFuture[string]("asyncfile.read")
 
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     var buffer = alloc0(size)
 
     var ol = PCustomOverlapped()
@@ -224,7 +224,7 @@ proc setFilePos*(f: AsyncFile, pos: int64) =
   ## Sets the position of the file pointer that is used for read/write
   ## operations. The file's first byte has the index zero. 
   f.offset = pos
-  when not defined(windows):
+  when not defined(windows) and not defined(nimdoc):
     let ret = lseek(f.fd.cint, pos, SEEK_SET)
     if ret == -1:
       raiseOSError(osLastError())
@@ -245,7 +245,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
   ## specified file.
   var retFuture = newFuture[void]("asyncfile.write")
   var copy = data
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     var buffer = alloc0(data.len)
     copyMem(buffer, addr copy[0], data.len)
 
@@ -316,7 +316,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
 
 proc close*(f: AsyncFile) =
   ## Closes the file specified.
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     if not closeHandle(f.fd.THandle).bool:
       raiseOSError(osLastError())
   else:
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index e690e8eba..edb904cc6 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -47,6 +47,24 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       result[i] = itm
       inc(i)
 
+proc repeat*[T](s: seq[T], n: Natural): seq[T] =
+  ## Returns a new sequence with the items of `s` repeated `n` times.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:
+  ##
+  ##   let
+  ##     s = @[1, 2, 3]
+  ##     total = s.repeat(3)
+  ##   assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  result = newSeq[T](n * s.len)
+  var o = 0
+  for x in 1..n:
+    for e in s:
+      result[o] = e
+      inc o
+
 proc deduplicate*[T](seq1: seq[T]): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
@@ -86,7 +104,7 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
   newSeq(result, m)
   for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
 
-proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
+proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
   ## Splits and distributes a sequence `s` into `num` sub sequences.
   ##
   ## Returns a sequence of `num` sequences. For some input values this is the
@@ -113,11 +131,12 @@ proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
   ##   assert numbers.distribute(6)[0] == @[1, 2]
   ##   assert numbers.distribute(6)[5] == @[7]
   assert(not s.isNil, "`s` can't be nil")
-  assert(num > 0, "`num` has to be greater than zero")
   if num < 2:
     result = @[s]
     return
 
+  let num = int(num) # XXX probably only needed because of .. bug
+
   # Create the result and calculate the stride size and the remainder if any.
   result = newSeq[seq[T]](num)
   var
@@ -587,4 +606,14 @@ when isMainModule:
     seq2D[0][1] = true
     doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
 
+  block: # repeat tests
+    let
+      a = @[1, 2, 3]
+      b: seq[int] = @[]
+    
+    doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+    doAssert a.repeat(0) == @[]
+    #doAssert a.repeat(-1) == @[] # will not compile!
+    doAssert b.repeat(3) == @[]
+
   echo "Finished doc tests"
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 959688d6a..93a7591ac 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -196,7 +196,11 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
   var hc: THash
   var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
-  else: raise newException(KeyError, "key not found: " & $key)
+  else:
+    when compiles($key):
+      raise newException(KeyError, "key not found: " & $key)
+    else:
+      raise newException(KeyError, "key not found")
 
 iterator allValues*[A, B](t: Table[A, B]; key: A): B =
   ## iterates over any value in the table `t` that belongs to the given `key`.
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 30daaf2dc..a16342d44 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -33,8 +33,8 @@
 ##  proc hash(x: Something): THash =
 ##    ## Computes a THash from `x`.
 ##    var h: THash = 0
-##    h = h &! hash(x.foo)
-##    h = h &! hash(x.bar)
+##    h = h !& hash(x.foo)
+##    h = h !& hash(x.bar)
 ##    result = !$h
 
 import 
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 37af14df3..f11101511 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -390,8 +390,11 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = if proxy == nil: parseUri(url) else: proxy.url
   var headers = substr(httpMethod, len("http"))
+  # TODO: Use generateHeaders further down once it supports proxies.
   if proxy == nil:
-    headers.add(" " & r.path)
+    headers.add ' '
+    if r.path[0] != '/': headers.add '/'
+    headers.add(r.path)
     if r.query.len > 0:
       headers.add("?" & r.query)
   else:
@@ -567,9 +570,12 @@ proc downloadFile*(url: string, outputFilename: string,
 
 proc generateHeaders(r: Uri, httpMethod: string,
                      headers: StringTableRef): string =
+  # TODO: Use this in the blocking HttpClient once it supports proxies.
   result = substr(httpMethod, len("http"))
   # TODO: Proxies
-  result.add(" " & r.path)
+  result.add ' '
+  if r.path[0] != '/': result.add '/'
+  result.add(r.path)
   if r.query.len > 0:
     result.add("?" & r.query)
   result.add(" HTTP/1.1\c\L")
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index b64437c89..16c36e1f0 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -217,7 +217,7 @@ method log*(logger: RollingFileLogger, level: Level,
       logger.curLine = 0
       logger.f = open(logger.baseName, logger.baseMode)
     
-    writeln(logger.f, LevelNames[level], " ", frmt % args)
+    writeln(logger.f, LevelNames[level], " ",substituteLog(logger.fmtStr), frmt % args)
     logger.curLine.inc
 
 # --------
diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim
index c6228af50..5ee301b15 100644
--- a/lib/pure/md5.nim
+++ b/lib/pure/md5.nim
@@ -213,13 +213,13 @@ proc toMD5*(s: string): MD5Digest =
   md5Update(c, cstring(s), len(s))
   md5Final(c, result)
 
-proc `$`*(D: MD5Digest): string =
+proc `$`*(d: MD5Digest): string =
   ## converts a MD5Digest value into its string representation
   const digits = "0123456789abcdef"
   result = ""
   for i in 0..15:
-    add(result, digits[(D[i] shr 4) and 0xF])
-    add(result, digits[D[i] and 0xF])
+    add(result, digits[(d[i] shr 4) and 0xF])
+    add(result, digits[d[i] and 0xF])
 
 proc getMD5*(s: string): string =
   ## computes an MD5 value of `s` and returns its string representation
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index bed751542..ffbc6e320 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -81,6 +81,23 @@ type
     TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
     TSocketImpl: SocketImpl].}
 
+type
+  IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
+    IPv6, ## IPv6 address
+    IPv4  ## IPv4 address
+
+  TIpAddress* = object ## stores an arbitrary IP address    
+    case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
+    of IpAddressFamily.IPv6:
+      address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
+                                       ## case of IPv6
+    of IpAddressFamily.IPv4:
+      address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
+                                      ## case of IPv4
+
+proc isIpAddress*(address_str: string): bool {.tags: [].}
+proc parseIpAddress*(address_str: string): TIpAddress
+
 proc isDisconnectionError*(flags: set[SocketFlag],
     lastError: OSErrorCode): bool =
   ## Determines whether ``lastError`` is a disconnection error. Only does this
@@ -511,6 +528,12 @@ proc connect*(socket: Socket, address: string, port = Port(0),
   
   when defined(ssl):
     if socket.isSSL:
+      # RFC3546 for SNI specifies that IP addresses are not allowed.
+      if not isIpAddress(address):
+        # Discard result in case OpenSSL version doesn't support SNI, or we're
+        # not using TLSv1+
+        discard SSL_set_tlsext_host_name(socket.sslHandle, address)
+
       let ret = SSLConnect(socket.sslHandle)
       socketError(socket, ret)
 
@@ -969,20 +992,6 @@ proc isSsl*(socket: Socket): bool =
 proc getFd*(socket: Socket): SocketHandle = return socket.fd
   ## Returns the socket's file descriptor
 
-type
-  IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
-    IPv6, ## IPv6 address
-    IPv4  ## IPv4 address
-
-  TIpAddress* = object ## stores an arbitrary IP address    
-    case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
-    of IpAddressFamily.IPv6:
-      address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
-                                       ## case of IPv6
-    of IpAddressFamily.IPv4:
-      address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
-                                      ## case of IPv4
-
 proc IPv4_any*(): TIpAddress =
   ## Returns the IPv4 any address, which can be used to listen on all available
   ## network adapters
@@ -1241,7 +1250,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
     raise newException(ValueError,
       "Invalid IP Address. The address consists of too many groups")
 
-proc parseIpAddress*(address_str: string): TIpAddress =
+proc parseIpAddress(address_str: string): TIpAddress =
   ## Parses an IP address
   ## Raises EInvalidValue on error
   if address_str == nil:
@@ -1250,3 +1259,13 @@ proc parseIpAddress*(address_str: string): TIpAddress =
     return parseIPv6Address(address_str)
   else:
     return parseIPv4Address(address_str)
+
+
+proc isIpAddress(address_str: string): bool =
+  ## Checks if a string is an IP address
+  ## Returns true if it is, false otherwise
+  try:
+    discard parseIpAddress(address_str)
+  except ValueError:
+    return false
+  return true
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index bf581667b..d2e112c18 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1997,6 +1997,8 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
     rawToFormalFileInfo(rawInfo, result)
 
 proc getFileInfo*(file: File): FileInfo =
+  if file.isNil:
+    raise newException(IOError, "File is nil")
   result = getFileInfo(file.getFileHandle())
 
 proc getFileInfo*(path: string, followSymlink = true): FileInfo =
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index b957c0cf7..2663c5b2f 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
   my.kind = xmlError
   my.a = ""
   my.b = ""
+  my.c = nil
   my.options = options
   
 proc close*(my: var XmlParser) {.inline.} = 
@@ -138,43 +139,43 @@ proc kind*(my: XmlParser): XmlEventKind {.inline.} =
   ## returns the current event type for the XML parser
   return my.kind
 
-proc charData*(my: XmlParser): string {.inline.} = 
+template charData*(my: XmlParser): string =
   ## returns the character data for the events: ``xmlCharData``, 
   ## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
   assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData, 
                      xmlSpecial})
-  return my.a
+  my.a
 
-proc elementName*(my: XmlParser): string {.inline.} = 
+template elementName*(my: XmlParser): string =
   ## returns the element name for the events: ``xmlElementStart``, 
   ## ``xmlElementEnd``, ``xmlElementOpen``
   assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen})
-  return my.a
+  my.a
 
-proc entityName*(my: XmlParser): string {.inline.} = 
+template entityName*(my: XmlParser): string =
   ## returns the entity name for the event: ``xmlEntity``
   assert(my.kind == xmlEntity)
-  return my.a
+  my.a
   
-proc attrKey*(my: XmlParser): string {.inline.} = 
+template attrKey*(my: XmlParser): string =
   ## returns the attribute key for the event ``xmlAttribute``
   assert(my.kind == xmlAttribute)
-  return my.a
+  my.a
   
-proc attrValue*(my: XmlParser): string {.inline.} = 
+template attrValue*(my: XmlParser): string =
   ## returns the attribute value for the event ``xmlAttribute``
   assert(my.kind == xmlAttribute)
-  return my.b
+  my.b
 
-proc piName*(my: XmlParser): string {.inline.} = 
+template piName*(my: XmlParser): string =
   ## returns the processing instruction name for the event ``xmlPI``
   assert(my.kind == xmlPI)
-  return my.a
+  my.a
 
-proc piRest*(my: XmlParser): string {.inline.} = 
+template piRest*(my: XmlParser): string =
   ## returns the rest of the processing instruction for the event ``xmlPI``
   assert(my.kind == xmlPI)
-  return my.b
+  my.b
 
 proc rawData*(my: XmlParser): string {.inline.} =
   ## returns the underlying 'data' string by reference.
@@ -621,7 +622,7 @@ proc next*(my: var XmlParser) =
   of stateEmptyElementTag:
     my.state = stateNormal
     my.kind = xmlElementEnd
-    if not isNil(my.c):
+    if not my.c.isNil:
       my.a = my.c
   of stateError: 
     my.kind = xmlError
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 419554de5..04c75ecae 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -29,7 +29,7 @@ when useUnicode:
 const
   InlineThreshold = 5  ## number of leaves; -1 to disable inlining
   MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that
-                       ## can be captured. More subpatterns cannot be captured! 
+                       ## can be captured. More subpatterns cannot be captured!
 
 type
   PegKind = enum
@@ -85,14 +85,14 @@ type
     of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
     else: sons: seq[TNode]
   NonTerminal* = ref NonTerminalObj
-  
+
   Peg* = TNode ## type that represents a PEG
 
 {.deprecated: [TPeg: Peg].}
 
 proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
   ## constructs a PEG from a terminal string
-  if t.len != 1:  
+  if t.len != 1:
     result.kind = pkTerminal
     result.term = t
   else:
@@ -116,7 +116,7 @@ proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
   assert t != '\0'
   result.kind = pkChar
   result.ch = t
-  
+
 proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG from a character set `s`
   assert '\0' notin s
@@ -129,12 +129,12 @@ proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
 
 proc addChoice(dest: var Peg, elem: Peg) =
   var L = dest.len-1
-  if L >= 0 and dest.sons[L].kind == pkCharChoice: 
+  if L >= 0 and dest.sons[L].kind == pkCharChoice:
     # caution! Do not introduce false aliasing here!
     case elem.kind
     of pkCharChoice:
       dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
-    of pkChar: 
+    of pkChar:
       dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
     else: add(dest, elem)
   else: add(dest, elem)
@@ -158,12 +158,12 @@ proc `/`*(a: varargs[Peg]): Peg {.
 
 proc addSequence(dest: var Peg, elem: Peg) =
   var L = dest.len-1
-  if L >= 0 and dest.sons[L].kind == pkTerminal: 
+  if L >= 0 and dest.sons[L].kind == pkTerminal:
     # caution! Do not introduce false aliasing here!
     case elem.kind
-    of pkTerminal: 
+    of pkTerminal:
       dest.sons[L] = term(dest.sons[L].term & elem.term)
-    of pkChar: 
+    of pkChar:
       dest.sons[L] = term(dest.sons[L].term & elem.ch)
     else: add(dest, elem)
   else: add(dest, elem)
@@ -172,7 +172,7 @@ proc sequence*(a: varargs[Peg]): Peg {.
   nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a sequence with all the PEGs from `a`
   multipleOp(pkSequence, addSequence)
- 
+
 proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
   ## constructs an optional for the PEG `a`
   if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
@@ -207,7 +207,7 @@ proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
   result.kind = pkSearch
   result.sons = @[a]
 
-proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl, 
+proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
                              extern: "npgegsCapturedSearch".} =
   ## constructs a "captured search" for the PEG `a`
   result.kind = pkCapturedSearch
@@ -216,7 +216,7 @@ proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
 proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
   ## constructs a "greedy positive repetition" with the PEG `a`
   return sequence(a, *a)
-  
+
 proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
   ## constructs an "and predicate" with the PEG `a`
   result.kind = pkAndPredicate
@@ -239,33 +239,33 @@ proc newLine*: Peg {.inline.} =
   ## constructs the PEG `newline`:idx: (``\n``)
   result.kind = pkNewLine
 
-proc unicodeLetter*: Peg {.inline.} = 
+proc unicodeLetter*: Peg {.inline.} =
   ## constructs the PEG ``\letter`` which matches any Unicode letter.
   result.kind = pkLetter
-  
-proc unicodeLower*: Peg {.inline.} = 
+
+proc unicodeLower*: Peg {.inline.} =
   ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
-  result.kind = pkLower 
+  result.kind = pkLower
 
-proc unicodeUpper*: Peg {.inline.} = 
+proc unicodeUpper*: Peg {.inline.} =
   ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
   result.kind = pkUpper
-  
-proc unicodeTitle*: Peg {.inline.} = 
+
+proc unicodeTitle*: Peg {.inline.} =
   ## constructs the PEG ``\title`` which matches any Unicode title letter.
   result.kind = pkTitle
 
-proc unicodeWhitespace*: Peg {.inline.} = 
-  ## constructs the PEG ``\white`` which matches any Unicode 
+proc unicodeWhitespace*: Peg {.inline.} =
+  ## constructs the PEG ``\white`` which matches any Unicode
   ## whitespace character.
   result.kind = pkWhitespace
 
-proc startAnchor*: Peg {.inline.} = 
-  ## constructs the PEG ``^`` which matches the start of the input.  
+proc startAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``^`` which matches the start of the input.
   result.kind = pkStartAnchor
 
-proc endAnchor*: Peg {.inline.} = 
-  ## constructs the PEG ``$`` which matches the end of the input.  
+proc endAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``$`` which matches the end of the input.
   result = !any()
 
 proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
@@ -274,21 +274,21 @@ proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
   result.sons = @[a]
 
 proc backref*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1.
   result.kind = pkBackRef
   result.index = index-1
 
 proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores case for matching.
   result.kind = pkBackRefIgnoreCase
   result.index = index-1
 
 proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".}= 
+  nosideEffect, rtl, extern: "npegs$1".}=
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores style for matching.
   result.kind = pkBackRefIgnoreStyle
@@ -298,7 +298,7 @@ proc spaceCost(n: Peg): int =
   case n.kind
   of pkEmpty: discard
   of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
-     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, 
+     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
      pkAny..pkWhitespace, pkGreedyAny:
     result = 1
   of pkNonTerminal:
@@ -310,7 +310,7 @@ proc spaceCost(n: Peg): int =
       if result >= InlineThreshold: break
 
 proc nonterminal*(n: NonTerminal): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG that consists of the nonterminal symbol
   assert n != nil
   if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
@@ -331,7 +331,7 @@ proc newNonTerminal*(name: string, line, column: int): NonTerminal {.
 template letters*: expr =
   ## expands to ``charset({'A'..'Z', 'a'..'z'})``
   charSet({'A'..'Z', 'a'..'z'})
-  
+
 template digits*: expr =
   ## expands to ``charset({'0'..'9'})``
   charSet({'0'..'9'})
@@ -339,11 +339,11 @@ template digits*: expr =
 template whitespace*: expr =
   ## expands to ``charset({' ', '\9'..'\13'})``
   charSet({' ', '\9'..'\13'})
-  
+
 template identChars*: expr =
   ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
   charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
-  
+
 template identStartChars*: expr =
   ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
   charSet({'a'..'z', 'A'..'Z', '_'})
@@ -352,14 +352,14 @@ template ident*: expr =
   ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
   sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
            *charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
-  
+
 template natural*: expr =
   ## same as ``\d+``
   +digits
 
 # ------------------------- debugging -----------------------------------------
 
-proc esc(c: char, reserved = {'\0'..'\255'}): string = 
+proc esc(c: char, reserved = {'\0'..'\255'}): string =
   case c
   of '\b': result = "\\b"
   of '\t': result = "\\t"
@@ -374,38 +374,38 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
   elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
   elif c in reserved: result = '\\' & c
   else: result = $c
-  
+
 proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
 
-proc singleQuoteEsc(str: string): string = 
+proc singleQuoteEsc(str: string): string =
   result = "'"
   for c in items(str): add result, esc(c, {'\''})
   add result, '\''
-  
-proc charSetEscAux(cc: set[char]): string = 
+
+proc charSetEscAux(cc: set[char]): string =
   const reserved = {'^', '-', ']'}
   result = ""
   var c1 = 0
-  while c1 <= 0xff: 
-    if chr(c1) in cc: 
+  while c1 <= 0xff:
+    if chr(c1) in cc:
       var c2 = c1
       while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
-      if c1 == c2: 
+      if c1 == c2:
         add result, esc(chr(c1), reserved)
-      elif c2 == succ(c1): 
+      elif c2 == succ(c1):
         add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
-      else: 
+      else:
         add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
       c1 = c2
     inc(c1)
-  
+
 proc charSetEsc(cc: set[char]): string =
-  if card(cc) >= 128+64: 
+  if card(cc) >= 128+64:
     result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
-  else: 
+  else:
     result = '[' & charSetEscAux(cc) & ']'
-  
-proc toStrAux(r: Peg, res: var string) = 
+
+proc toStrAux(r: Peg, res: var string) =
   case r.kind
   of pkEmpty: add(res, "()")
   of pkAny: add(res, '.')
@@ -469,25 +469,25 @@ proc toStrAux(r: Peg, res: var string) =
     toStrAux(r.sons[0], res)
   of pkCapture:
     add(res, '{')
-    toStrAux(r.sons[0], res)    
+    toStrAux(r.sons[0], res)
     add(res, '}')
-  of pkBackRef: 
+  of pkBackRef:
     add(res, '$')
     add(res, $r.index)
-  of pkBackRefIgnoreCase: 
+  of pkBackRefIgnoreCase:
     add(res, "i$")
     add(res, $r.index)
-  of pkBackRefIgnoreStyle: 
+  of pkBackRefIgnoreStyle:
     add(res, "y$")
     add(res, $r.index)
   of pkRule:
-    toStrAux(r.sons[0], res)    
+    toStrAux(r.sons[0], res)
     add(res, " <- ")
     toStrAux(r.sons[1], res)
   of pkList:
     for i in 0 .. high(r.sons):
       toStrAux(r.sons[i], res)
-      add(res, "\n")  
+      add(res, "\n")
   of pkStartAnchor:
     add(res, '^')
 
@@ -506,8 +506,8 @@ type
 
 {.deprecated: [TCaptures: Captures].}
 
-proc bounds*(c: Captures, 
-             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = 
+proc bounds*(c: Captures,
+             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
   ## returns the bounds ``[first..last]`` of the `i`'th capture.
   result = c.matches[i]
 
@@ -527,7 +527,7 @@ when not useUnicode:
 
 proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
                nosideEffect, rtl, extern: "npegs$1".} =
-  ## low-level matching proc that implements the PEG interpreter. Use this 
+  ## low-level matching proc that implements the PEG interpreter. Use this
   ## for maximum efficiency (every other PEG operation ends up calling this
   ## proc).
   ## Returns -1 if it does not match, else the length of the match
@@ -541,7 +541,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       result = runeLenAt(s, start)
     else:
       result = -1
-  of pkLetter: 
+  of pkLetter:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -550,7 +550,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkLower: 
+  of pkLower:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -559,7 +559,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkUpper: 
+  of pkUpper:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -568,16 +568,16 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkTitle: 
+  of pkTitle:
     if s[start] != '\0':
       var a: Rune
       result = start
       fastRuneAt(s, result, a)
-      if isTitle(a): dec(result, start) 
+      if isTitle(a): dec(result, start)
       else: result = -1
     else:
       result = -1
-  of pkWhitespace: 
+  of pkWhitespace:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -641,7 +641,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
     when false: echo "leave: ", p.nt.name
     if result < 0: c.ml = oldMl
   of pkSequence:
-    var oldMl = c.ml  
+    var oldMl = c.ml
     result = 0
     for i in 0..high(p.sons):
       var x = rawMatch(s, p.sons[i], start+result, c)
@@ -723,11 +723,11 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       #else: silently ignore the capture
     else:
       c.ml = idx
-  of pkBackRef..pkBackRefIgnoreStyle: 
+  of pkBackRef..pkBackRefIgnoreStyle:
     if p.index >= c.ml: return -1
     var (a, b) = c.matches[p.index]
     var n: Peg
-    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) 
+    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
     n.term = s.substr(a, b)
     result = rawMatch(s, n, start, c)
   of pkStartAnchor:
@@ -755,7 +755,7 @@ proc match*(s: string, pattern: Peg, matches: var openArray[string],
   result = rawMatch(s, pattern, start, c) == len(s) - start
   if result: fillMatches(s, matches, c)
 
-proc match*(s: string, pattern: Peg, 
+proc match*(s: string, pattern: Peg,
             start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
   ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
   var c: Captures
@@ -773,7 +773,7 @@ proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
   result = rawMatch(s, pattern, start, c)
   if result >= 0: fillMatches(s, matches, c)
 
-proc matchLen*(s: string, pattern: Peg, 
+proc matchLen*(s: string, pattern: Peg,
                start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## the same as ``match``, but it returns the length of the match,
   ## if there is no match, -1 is returned. Note that a match length
@@ -797,11 +797,11 @@ proc find*(s: string, pattern: Peg, matches: var openArray[string],
       return i
   return -1
   # could also use the pattern here: (!P .)* P
-  
+
 proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
                  start = 0): tuple[first, last: int] {.
                  nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## returns the starting position and end position of ``pattern`` in ``s`` 
+  ## returns the starting position and end position of ``pattern`` in ``s``
   ## and the captured
   ## substrings in the array ``matches``. If it does not match, nothing
   ## is written into ``matches`` and (-1,0) is returned.
@@ -814,8 +814,8 @@ proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
       fillMatches(s, matches, c)
       return (i, i+L-1)
   return (-1, 0)
-  
-proc find*(s: string, pattern: Peg, 
+
+proc find*(s: string, pattern: Peg,
            start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## returns the starting position of ``pattern`` in ``s``. If it does not
   ## match, -1 is returned.
@@ -824,8 +824,8 @@ proc find*(s: string, pattern: Peg,
   for i in start .. s.len-1:
     if rawMatch(s, pattern, i, c) >= 0: return i
   return -1
-  
-iterator findAll*(s: string, pattern: Peg, start = 0): string = 
+
+iterator findAll*(s: string, pattern: Peg, start = 0): string =
   ## yields all matching *substrings* of `s` that match `pattern`.
   var c: Captures
   c.origStart = start
@@ -838,23 +838,23 @@ iterator findAll*(s: string, pattern: Peg, start = 0): string =
     else:
       yield substr(s, i, i+L-1)
       inc(i, L)
-    
+
 proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## returns all matching *substrings* of `s` that match `pattern`.
   ## If it does not match, @[] is returned.
   accumulateResult(findAll(s, pattern, start))
 
 when not defined(nimhygiene):
   {.pragma: inject.}
-  
+
 template `=~`*(s: string, pattern: Peg): bool =
-  ## This calls ``match`` with an implicit declared ``matches`` array that 
-  ## can be used in the scope of the ``=~`` call: 
-  ## 
+  ## This calls ``match`` with an implicit declared ``matches`` array that
+  ## can be used in the scope of the ``=~`` call:
+  ##
   ## .. code-block:: nim
   ##
-  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": 
+  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
   ##     # matches a key=value pair:
   ##     echo("Key: ", matches[0])
   ##     echo("Value: ", matches[1])
@@ -865,7 +865,7 @@ template `=~`*(s: string, pattern: Peg): bool =
   ##     echo("comment: ", matches[0])
   ##   else:
   ##     echo("syntax error")
-  ##  
+  ##
   bind MaxSubpatterns
   when not declaredInScope(matches):
     var matches {.inject.}: array[0..MaxSubpatterns-1, string]
@@ -902,7 +902,7 @@ proc replacef*(s: string, sub: Peg, by: string): string {.
   ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
   ##
   ## .. code-block:: nim
-  ##   "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
+  ##   "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")
   ##
   ## Results in:
   ##
@@ -941,10 +941,10 @@ proc replace*(s: string, sub: Peg, by = ""): string {.
       add(result, by)
       inc(i, x)
   add(result, substr(s, i))
-  
+
 proc parallelReplace*(s: string, subs: varargs[
                       tuple[pattern: Peg, repl: string]]): string {.
-                      nosideEffect, rtl, extern: "npegs$1".} = 
+                      nosideEffect, rtl, extern: "npegs$1".} =
   ## Returns a modified copy of `s` with the substitutions in `subs`
   ## applied in parallel.
   result = ""
@@ -964,8 +964,8 @@ proc parallelReplace*(s: string, subs: varargs[
       add(result, s[i])
       inc(i)
   # copy the rest:
-  add(result, substr(s, i))  
-  
+  add(result, substr(s, i))
+
 proc transformFile*(infile, outfile: string,
                     subs: varargs[tuple[pattern: Peg, repl: string]]) {.
                     rtl, extern: "npegs$1".} =
@@ -974,7 +974,7 @@ proc transformFile*(infile, outfile: string,
   ## error occurs. This is supposed to be used for quick scripting.
   var x = readFile(infile).string
   writeFile(outfile, x.parallelReplace(subs))
-  
+
 iterator split*(s: string, sep: Peg): string =
   ## Splits the string `s` into substrings.
   ##
@@ -1049,14 +1049,14 @@ type
     tkBackref,          ## '$'
     tkDollar,           ## '$'
     tkHat               ## '^'
-  
+
   TToken {.final.} = object  ## a token
     kind: TTokKind           ## the type of the token
     modifier: TModifier
     literal: string          ## the parsed (string) literal
     charset: set[char]       ## if kind == tkCharSet
     index: int               ## if kind == tkBackref
-  
+
   PegLexer {.inheritable.} = object          ## the lexer object.
     bufpos: int               ## the current position within the buffer
     buf: cstring              ## the buffer itself
@@ -1086,7 +1086,7 @@ proc handleLF(L: var PegLexer, pos: int): int =
   result = pos+1
   L.lineStart = result
 
-proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = 
+proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
   L.buf = input
   L.bufpos = 0
   L.lineNumber = line
@@ -1094,69 +1094,69 @@ proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
   L.lineStart = 0
   L.filename = filename
 
-proc getColumn(L: PegLexer): int {.inline.} = 
+proc getColumn(L: PegLexer): int {.inline.} =
   result = abs(L.bufpos - L.lineStart) + L.colOffset
 
-proc getLine(L: PegLexer): int {.inline.} = 
+proc getLine(L: PegLexer): int {.inline.} =
   result = L.lineNumber
-  
+
 proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
   var line = if line < 0: getLine(L) else: line
   var col = if col < 0: getColumn(L) else: col
   result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
 
-proc handleHexChar(c: var PegLexer, xi: var int) = 
+proc handleHexChar(c: var PegLexer, xi: var int) =
   case c.buf[c.bufpos]
-  of '0'..'9': 
+  of '0'..'9':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
     inc(c.bufpos)
-  of 'a'..'f': 
+  of 'a'..'f':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
     inc(c.bufpos)
-  of 'A'..'F': 
+  of 'A'..'F':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
   else: discard
 
-proc getEscapedChar(c: var PegLexer, tok: var TToken) = 
+proc getEscapedChar(c: var PegLexer, tok: var TToken) =
   inc(c.bufpos)
   case c.buf[c.bufpos]
-  of 'r', 'R', 'c', 'C': 
+  of 'r', 'R', 'c', 'C':
     add(tok.literal, '\c')
     inc(c.bufpos)
-  of 'l', 'L': 
+  of 'l', 'L':
     add(tok.literal, '\L')
     inc(c.bufpos)
-  of 'f', 'F': 
+  of 'f', 'F':
     add(tok.literal, '\f')
     inc(c.bufpos)
-  of 'e', 'E': 
+  of 'e', 'E':
     add(tok.literal, '\e')
     inc(c.bufpos)
-  of 'a', 'A': 
+  of 'a', 'A':
     add(tok.literal, '\a')
     inc(c.bufpos)
-  of 'b', 'B': 
+  of 'b', 'B':
     add(tok.literal, '\b')
     inc(c.bufpos)
-  of 'v', 'V': 
+  of 'v', 'V':
     add(tok.literal, '\v')
     inc(c.bufpos)
-  of 't', 'T': 
+  of 't', 'T':
     add(tok.literal, '\t')
     inc(c.bufpos)
-  of 'x', 'X': 
+  of 'x', 'X':
     inc(c.bufpos)
     var xi = 0
     handleHexChar(c, xi)
     handleHexChar(c, xi)
     if xi == 0: tok.kind = tkInvalid
     else: add(tok.literal, chr(xi))
-  of '0'..'9': 
+  of '0'..'9':
     var val = ord(c.buf[c.bufpos]) - ord('0')
     inc(c.bufpos)
     var i = 1
-    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): 
+    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
       val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
       inc(c.bufpos)
       inc(i)
@@ -1169,32 +1169,32 @@ proc getEscapedChar(c: var PegLexer, tok: var TToken) =
   else:
     add(tok.literal, c.buf[c.bufpos])
     inc(c.bufpos)
-  
-proc skip(c: var PegLexer) = 
+
+proc skip(c: var PegLexer) =
   var pos = c.bufpos
   var buf = c.buf
-  while true: 
+  while true:
     case buf[pos]
-    of ' ', '\t': 
+    of ' ', '\t':
       inc(pos)
     of '#':
       while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
     of '\c':
       pos = handleCR(c, pos)
       buf = c.buf
-    of '\L': 
+    of '\L':
       pos = handleLF(c, pos)
       buf = c.buf
-    else: 
+    else:
       break                   # EndOfFile also leaves the loop
   c.bufpos = pos
-  
-proc getString(c: var PegLexer, tok: var TToken) = 
+
+proc getString(c: var PegLexer, tok: var TToken) =
   tok.kind = tkStringLit
   var pos = c.bufpos + 1
   var buf = c.buf
   var quote = buf[pos-1]
-  while true: 
+  while true:
     case buf[pos]
     of '\\':
       c.bufpos = pos
@@ -1205,13 +1205,13 @@ proc getString(c: var PegLexer, tok: var TToken) =
       break
     elif buf[pos] == quote:
       inc(pos)
-      break      
+      break
     else:
       add(tok.literal, buf[pos])
       inc(pos)
   c.bufpos = pos
-  
-proc getDollar(c: var PegLexer, tok: var TToken) = 
+
+proc getDollar(c: var PegLexer, tok: var TToken) =
   var pos = c.bufpos + 1
   var buf = c.buf
   if buf[pos] in {'0'..'9'}:
@@ -1223,8 +1223,8 @@ proc getDollar(c: var PegLexer, tok: var TToken) =
   else:
     tok.kind = tkDollar
   c.bufpos = pos
-  
-proc getCharSet(c: var PegLexer, tok: var TToken) = 
+
+proc getCharSet(c: var PegLexer, tok: var TToken) =
   tok.kind = tkCharSet
   tok.charset = {}
   var pos = c.bufpos + 1
@@ -1247,7 +1247,7 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
     of '\C', '\L', '\0':
       tok.kind = tkInvalid
       break
-    else: 
+    else:
       ch = buf[pos]
       inc(pos)
     incl(tok.charset, ch)
@@ -1267,18 +1267,18 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
         of '\C', '\L', '\0':
           tok.kind = tkInvalid
           break
-        else: 
+        else:
           ch2 = buf[pos]
           inc(pos)
         for i in ord(ch)+1 .. ord(ch2):
           incl(tok.charset, chr(i))
   c.bufpos = pos
   if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
-  
-proc getSymbol(c: var PegLexer, tok: var TToken) = 
+
+proc getSymbol(c: var PegLexer, tok: var TToken) =
   var pos = c.bufpos
   var buf = c.buf
-  while true: 
+  while true:
     add(tok.literal, buf[pos])
     inc(pos)
     if buf[pos] notin strutils.IdentChars: break
@@ -1294,7 +1294,7 @@ proc getBuiltin(c: var PegLexer, tok: var TToken) =
     tok.kind = tkEscaped
     getEscapedChar(c, tok) # may set tok.kind to tkInvalid
 
-proc getTok(c: var PegLexer, tok: var TToken) = 
+proc getTok(c: var PegLexer, tok: var TToken) =
   tok.kind = tkInvalid
   tok.modifier = modNone
   setLen(tok.literal, 0)
@@ -1309,11 +1309,11 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     else:
       tok.kind = tkCurlyLe
       add(tok.literal, '{')
-  of '}': 
+  of '}':
     tok.kind = tkCurlyRi
     inc(c.bufpos)
     add(tok.literal, '}')
-  of '[': 
+  of '[':
     getCharSet(c, tok)
   of '(':
     tok.kind = tkParLe
@@ -1323,7 +1323,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkParRi
     inc(c.bufpos)
     add(tok.literal, ')')
-  of '.': 
+  of '.':
     tok.kind = tkAny
     inc(c.bufpos)
     add(tok.literal, '.')
@@ -1331,16 +1331,16 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkAnyRune
     inc(c.bufpos)
     add(tok.literal, '_')
-  of '\\': 
+  of '\\':
     getBuiltin(c, tok)
   of '\'', '"': getString(c, tok)
   of '$': getDollar(c, tok)
-  of '\0': 
+  of '\0':
     tok.kind = tkEof
     tok.literal = "[EOF]"
   of 'a'..'z', 'A'..'Z', '\128'..'\255':
     getSymbol(c, tok)
-    if c.buf[c.bufpos] in {'\'', '"'} or 
+    if c.buf[c.bufpos] in {'\'', '"'} or
         c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
       case tok.literal
       of "i": tok.modifier = modIgnoreCase
@@ -1388,7 +1388,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkAt
     inc(c.bufpos)
     add(tok.literal, '@')
-    if c.buf[c.bufpos] == '@': 
+    if c.buf[c.bufpos] == '@':
       tok.kind = tkCurlyAt
       inc(c.bufpos)
       add(tok.literal, '@')
@@ -1407,7 +1407,7 @@ proc arrowIsNextTok(c: PegLexer): bool =
   result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
 
 # ----------------------------- parser ----------------------------------------
-    
+
 type
   EInvalidPeg* = object of ValueError ## raised if an invalid
                                          ## PEG has been detected
@@ -1425,7 +1425,7 @@ proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
   e.msg = errorStr(p, msg, line, col)
   raise e
 
-proc getTok(p: var PegParser) = 
+proc getTok(p: var PegParser) =
   getTok(p, p.tok)
   if p.tok.kind == tkInvalid: pegError(p, "invalid token")
 
@@ -1475,7 +1475,7 @@ proc builtin(p: var PegParser): Peg =
   of "white": result = unicodeWhitespace()
   else: pegError(p, "unknown built-in: " & p.tok.literal)
 
-proc token(terminal: Peg, p: PegParser): Peg = 
+proc token(terminal: Peg, p: PegParser): Peg =
   if p.skip.kind == pkEmpty: result = terminal
   else: result = sequence(p.skip, terminal)
 
@@ -1496,7 +1496,7 @@ proc primary(p: var PegParser): Peg =
   else: discard
   case p.tok.kind
   of tkIdentifier:
-    if p.identIsVerbatim: 
+    if p.identIsVerbatim:
       var m = p.tok.modifier
       if m == modNone: m = p.modifier
       result = modifiedTerm(p.tok.literal, m).token(p)
@@ -1539,17 +1539,17 @@ proc primary(p: var PegParser): Peg =
   of tkEscaped:
     result = term(p.tok.literal[0]).token(p)
     getTok(p)
-  of tkDollar: 
+  of tkDollar:
     result = endAnchor()
     getTok(p)
-  of tkHat: 
+  of tkHat:
     result = startAnchor()
     getTok(p)
   of tkBackref:
     var m = p.tok.modifier
     if m == modNone: m = p.modifier
     result = modifiedBackref(p.tok.index, m).token(p)
-    if p.tok.index < 0 or p.tok.index > p.captures: 
+    if p.tok.index < 0 or p.tok.index > p.captures:
       pegError(p, "invalid back reference index: " & $p.tok.index)
     getTok(p)
   else:
@@ -1573,7 +1573,7 @@ proc seqExpr(p: var PegParser): Peg =
   while true:
     case p.tok.kind
     of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
-       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, 
+       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
        tkHat, tkCurlyAt:
       result = sequence(result, primary(p))
     of tkIdentifier:
@@ -1587,7 +1587,7 @@ proc parseExpr(p: var PegParser): Peg =
   while p.tok.kind == tkBar:
     getTok(p)
     result = result / seqExpr(p)
-  
+
 proc parseRule(p: var PegParser): NonTerminal =
   if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
     result = getNonTerminal(p, p.tok.literal)
@@ -1601,7 +1601,7 @@ proc parseRule(p: var PegParser): NonTerminal =
     incl(result.flags, ntDeclared) # NOW inlining may be attempted
   else:
     pegError(p, "rule expected, but found: " & p.tok.literal)
-  
+
 proc rawParse(p: var PegParser): Peg =
   ## parses a rule or a PEG expression
   while p.tok.kind == tkBuiltin:
@@ -1680,7 +1680,7 @@ when isMainModule:
   assert(not match("W_HI_L", peg"\y 'while'"))
   assert(not match("W_HI_Le", peg"\y v'while'"))
   assert match("W_HI_Le", peg"y'while'")
-  
+
   assert($ +digits == $peg"\d+")
   assert "0158787".match(peg"\d+")
   assert "ABC 0232".match(peg"\w+\s+\d+")
@@ -1693,14 +1693,14 @@ when isMainModule:
 
   var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
   assert matchLen("key1=  cal9", pattern) == 11
-  
+
   var ws = newNonTerminal("ws", 1, 1)
   ws.rule = *whitespace
-  
+
   var expr = newNonTerminal("expr", 1, 1)
   expr.rule = sequence(capture(ident), *sequence(
                 nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
-  
+
   var c: Captures
   var s = "a+b +  c +d+e+f"
   assert rawMatch(s, expr.rule, 0, c) == len(s)
@@ -1722,7 +1722,7 @@ when isMainModule:
     assert matches[0] == "abc"
   else:
     assert false
-  
+
   var g2 = peg"""S <- A B / C D
                  A <- 'a'+
                  B <- 'b'+
@@ -1753,13 +1753,13 @@ when isMainModule:
 
   for x in findAll("abcdef", peg"^{.}", 3):
     assert x == "d"
-    
+
   if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
     assert matches[0] == "f"
     assert matches[1] == "a, b"
   else:
     assert false
-  
+
   assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
   # ß is not a lower cased letter?!
   assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
diff --git a/lib/pure/rawsockets.pretty.nim b/lib/pure/rawsockets.pretty.nim
deleted file mode 100644
index 726c07301..000000000
--- a/lib/pure/rawsockets.pretty.nim
+++ /dev/null
@@ -1,426 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2015 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements a low-level cross-platform sockets interface. Look
-## at the ``net`` module for the higher-level version.
-
-# TODO: Clean up the exports a bit and everything else in general.
-
-import unsigned, os
-
-when hostOS == "solaris":
-  {.passl: "-lsocket -lnsl".}
-
-const useWinVersion = defined(Windows) or defined(nimdoc)
-
-when useWinVersion:
-  import winlean
-  export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
-         WSAEDISCON, ERROR_NETNAME_DELETED
-else:
-  import posix
-  export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
-    EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET
-
-export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
-  inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto
-
-export
-  SO_ERROR,
-  SOL_SOCKET,
-  SOMAXCONN,
-  SO_ACCEPTCONN, SO_BROADCAST, SO_DEBUG, SO_DONTROUTE,
-  SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR,
-  MSG_PEEK
-
-type
-  Port* = distinct uint16  ## port type
-  
-  Domain* = enum    ## domain, which specifies the protocol family of the
-                    ## created socket. Other domains than those that are listed
-                    ## here are unsupported.
-    AF_UNIX,        ## for local socket (using a file). Unsupported on Windows.
-    AF_INET = 2,    ## for network protocol IPv4 or
-    AF_INET6 = 23   ## for network protocol IPv6.
-
-  SockType* = enum     ## second argument to `socket` proc
-    SOCK_STREAM = 1,   ## reliable stream-oriented service or Stream Sockets
-    SOCK_DGRAM = 2,    ## datagram service or Datagram Sockets
-    SOCK_RAW = 3,      ## raw protocols atop the network layer.
-    SOCK_SEQPACKET = 5 ## reliable sequenced packet service
-
-  Protocol* = enum      ## third argument to `socket` proc
-    IPPROTO_TCP = 6,    ## Transmission control protocol. 
-    IPPROTO_UDP = 17,   ## User datagram protocol.
-    IPPROTO_IP,         ## Internet protocol. Unsupported on Windows.
-    IPPROTO_IPV6,       ## Internet Protocol Version 6. Unsupported on Windows.
-    IPPROTO_RAW,        ## Raw IP Packets Protocol. Unsupported on Windows.
-    IPPROTO_ICMP        ## Control message protocol. Unsupported on Windows.
-
-  Servent* = object ## information about a service
-    name*: string
-    aliases*: seq[string]
-    port*: Port
-    proto*: string
-
-  Hostent* = object ## information about a given host
-    name*: string
-    aliases*: seq[string]
-    addrtype*: Domain
-    length*: int
-    addrList*: seq[string]
-
-{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType,
-    TProtocol: Protocol, TServent: Servent, THostent: Hostent].}
-
-when useWinVersion:
-  let
-    osInvalidSocket* = winlean.INVALID_SOCKET
-
-  const
-    IOCPARM_MASK* = 127
-    IOC_IN* = int(-2147483648)
-    FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or 
-                             (102 shl 8) or 126
-
-  proc ioctlsocket*(s: SocketHandle, cmd: clong, 
-                   argptr: ptr clong): cint {.
-                   stdcall, importc: "ioctlsocket", dynlib: "ws2_32.dll".}
-else:
-  let
-    osInvalidSocket* = posix.INVALID_SOCKET
-
-proc `==`*(a, b: Port): bool {.borrow.}
-  ## ``==`` for ports.
-
-proc `$`*(p: Port): string {.borrow.}
-  ## returns the port number as a string
-
-proc toInt*(domain: Domain): cint
-  ## Converts the TDomain enum to a platform-dependent ``cint``.
-
-proc toInt*(typ: SockType): cint
-  ## Converts the TType enum to a platform-dependent ``cint``.
-
-proc toInt*(p: Protocol): cint
-  ## Converts the TProtocol enum to a platform-dependent ``cint``.
-
-when not useWinVersion:
-  proc toInt(domain: Domain): cint =
-    case domain
-    of AF_UNIX:        result = posix.AF_UNIX
-    of AF_INET:        result = posix.AF_INET
-    of AF_INET6:       result = posix.AF_INET6
-    else: discard
-
-  proc toInt(typ: SockType): cint =
-    case typ
-    of SOCK_STREAM:    result = posix.SOCK_STREAM
-    of SOCK_DGRAM:     result = posix.SOCK_DGRAM
-    of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
-    of SOCK_RAW:       result = posix.SOCK_RAW
-    else: discard
-
-  proc toInt(p: Protocol): cint =
-    case p
-    of IPPROTO_TCP:    result = posix.IPPROTO_TCP
-    of IPPROTO_UDP:    result = posix.IPPROTO_UDP
-    of IPPROTO_IP:     result = posix.IPPROTO_IP
-    of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
-    of IPPROTO_RAW:    result = posix.IPPROTO_RAW
-    of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
-    else: discard
-
-else:
-  proc toInt(domain: Domain): cint = 
-    result = toU16(ord(domain))
-
-  proc toInt(typ: SockType): cint =
-    result = cint(ord(typ))
-  
-  proc toInt(p: Protocol): cint =
-    result = cint(ord(p))
-
-
-proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
-             protocol: Protocol = IPPROTO_TCP): SocketHandle =
-  ## Creates a new socket; returns `InvalidSocket` if an error occurs.
-  socket(toInt(domain), toInt(typ), toInt(protocol))
-
-proc close*(socket: SocketHandle) =
-  ## closes a socket.
-  when useWinVersion:
-    discard winlean.closesocket(socket)
-  else:
-    discard posix.close(socket)
-  # TODO: These values should not be discarded. An EOS should be raised.
-  # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
-
-proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint =
-  result = bindSocket(socket, name, namelen)
-
-proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEffect].} =
-  ## Marks ``socket`` as accepting connections. 
-  ## ``Backlog`` specifies the maximum length of the 
-  ## queue of pending connections.
-  when useWinVersion:
-    result = winlean.listen(socket, cint(backlog))
-  else:
-    result = posix.listen(socket, cint(backlog))
-
-proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockType = SOCK_STREAM,
-                 prot: Protocol = IPPROTO_TCP): ptr AddrInfo =
-  ##
-  ##
-  ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``!
-  var hints: AddrInfo
-  result = nil
-  hints.ai_family = toInt(af)
-  hints.ai_socktype = toInt(typ)
-  hints.ai_protocol = toInt(prot)
-  var gaiResult = getaddrinfo(address, $port, addr(hints), result)
-  if gaiResult != 0'i32:
-    when useWinVersion:
-      raiseOSError(osLastError())
-    else:
-      raise newException(OSError, $gai_strerror(gaiResult))
-
-proc dealloc*(ai: ptr AddrInfo) =
-  freeaddrinfo(ai)
-
-proc ntohl*(x: int32): int32 = 
-  ## Converts 32-bit integers from network to host byte order.
-  ## On machines where the host byte order is the same as network byte order,
-  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
-  when cpuEndian == bigEndian: result = x
-  else: result = (x shr 24'i32) or
-                 (x shr 8'i32 and 0xff00'i32) or
-                 (x shl 8'i32 and 0xff0000'i32) or
-                 (x shl 24'i32)
-
-proc ntohs*(x: int16): int16 =
-  ## Converts 16-bit integers from network to host byte order. On machines
-  ## where the host byte order is the same as network byte order, this is
-  ## a no-op; otherwise, it performs a 2-byte swap operation.
-  when cpuEndian == bigEndian: result = x
-  else: result = (x shr 8'i16) or (x shl 8'i16)
-
-proc htonl*(x: int32): int32 =
-  ## Converts 32-bit integers from host to network byte order. On machines
-  ## where the host byte order is the same as network byte order, this is
-  ## a no-op; otherwise, it performs a 4-byte swap operation.
-  result = rawsockets.ntohl(x)
-
-proc htons*(x: int16): int16 =
-  ## Converts 16-bit positive integers from host to network byte order.
-  ## On machines where the host byte order is the same as network byte
-  ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
-  result = rawsockets.ntohs(x)
-
-proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
-  ## Searches the database from the beginning and finds the first entry for 
-  ## which the service name specified by ``name`` matches the s_name member
-  ## and the protocol name specified by ``proto`` matches the s_proto member.
-  ##
-  ## On posix this will search through the ``/etc/services`` file.
-  when useWinVersion:
-    var s = winlean.getservbyname(name, proto)
-  else:
-    var s = posix.getservbyname(name, proto)
-  if s == nil: raise newException(OSError, "Service not found.")
-  result.name = $s.s_name
-  result.aliases = cstringArrayToSeq(s.s_aliases)
-  result.port = Port(s.s_port)
-  result.proto = $s.s_proto
-  
-proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = 
-  ## Searches the database from the beginning and finds the first entry for 
-  ## which the port specified by ``port`` matches the s_port member and the 
-  ## protocol name specified by ``proto`` matches the s_proto member.
-  ##
-  ## On posix this will search through the ``/etc/services`` file.
-  when useWinVersion:
-    var s = winlean.getservbyport(ze(int16(port)).cint, proto)
-  else:
-    var s = posix.getservbyport(ze(int16(port)).cint, proto)
-  if s == nil: raise newException(OSError, "Service not found.")
-  result.name = $s.s_name
-  result.aliases = cstringArrayToSeq(s.s_aliases)
-  result.port = Port(s.s_port)
-  result.proto = $s.s_proto
-
-proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
-  ## This function will lookup the hostname of an IP Address.
-  var myaddr: InAddr
-  myaddr.s_addr = inet_addr(ip)
-  
-  when useWinVersion:
-    var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
-                                  cint(rawsockets.AF_INET))
-    if s == nil: raiseOSError(osLastError())
-  else:
-    var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, 
-                                cint(posix.AF_INET))
-    if s == nil:
-      raise newException(OSError, $hstrerror(h_errno))
-  
-  result.name = $s.h_name
-  result.aliases = cstringArrayToSeq(s.h_aliases)
-  when useWinVersion:
-    result.addrtype = Domain(s.h_addrtype)
-  else:
-    if s.h_addrtype == posix.AF_INET:
-      result.addrtype = AF_INET
-    elif s.h_addrtype == posix.AF_INET6:
-      result.addrtype = AF_INET6
-    else:
-      raise newException(OSError, "unknown h_addrtype")
-  result.addrList = cstringArrayToSeq(s.h_addr_list)
-  result.length = int(s.h_length)
-
-proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = 
-  ## This function will lookup the IP address of a hostname.
-  when useWinVersion:
-    var s = winlean.gethostbyname(name)
-  else:
-    var s = posix.gethostbyname(name)
-  if s == nil: raiseOSError(osLastError())
-  result.name = $s.h_name
-  result.aliases = cstringArrayToSeq(s.h_aliases)
-  when useWinVersion:
-    result.addrtype = Domain(s.h_addrtype)
-  else:
-    if s.h_addrtype == posix.AF_INET:
-      result.addrtype = AF_INET
-    elif s.h_addrtype == posix.AF_INET6:
-      result.addrtype = AF_INET6
-    else:
-      raise newException(OSError, "unknown h_addrtype")
-  result.addrList = cstringArrayToSeq(s.h_addr_list)
-  result.length = int(s.h_length)
-
-proc getSockName*(socket: SocketHandle): Port = 
-  ## returns the socket's associated port number.
-  var name: Sockaddr_in
-  when useWinVersion:
-    name.sin_family = int16(ord(AF_INET))
-  else:
-    name.sin_family = posix.AF_INET
-  #name.sin_port = htons(cint16(port))
-  #name.sin_addr.s_addr = htonl(INADDR_ANY)
-  var namelen = sizeof(name).SockLen
-  if getsockname(socket, cast[ptr SockAddr](addr(name)),
-                 addr(namelen)) == -1'i32:
-    raiseOSError(osLastError())
-  result = Port(rawsockets.ntohs(name.sin_port))
-
-proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {.
-  tags: [ReadIOEffect].} = 
-  ## getsockopt for integer options.
-  var res: cint
-  var size = sizeof(res).SockLen
-  if getsockopt(socket, cint(level), cint(optname), 
-                addr(res), addr(size)) < 0'i32:
-    raiseOSError(osLastError())
-  result = int(res)
-
-proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {.
-  tags: [WriteIOEffect].} =
-  ## setsockopt for integer options.
-  var value = cint(optval)
-  if setsockopt(socket, cint(level), cint(optname), addr(value),  
-                sizeof(value).SockLen) < 0'i32:
-    raiseOSError(osLastError())
-
-proc setBlocking*(s: SocketHandle, blocking: bool) =
-  ## Sets blocking mode on socket.
-  ##
-  ## Raises EOS on error.
-  when useWinVersion:
-    var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
-    if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
-      raiseOSError(osLastError())
-  else: # BSD sockets
-    var x: int = fcntl(s, F_GETFL, 0)
-    if x == -1:
-      raiseOSError(osLastError())
-    else:
-      var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
-      if fcntl(s, F_SETFL, mode) == -1:
-        raiseOSError(osLastError())
-
-proc timeValFromMilliseconds(timeout = 500): Timeval =
-  if timeout != -1:
-    var seconds = timeout div 1000
-    result.tv_sec = seconds.int32
-    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
-
-proc createFdSet(fd: var FdSet, s: seq[SocketHandle], m: var int) = 
-  FD_ZERO(fd)
-  for i in items(s): 
-    m = max(m, int(i))
-    fdSet(i, fd)
-   
-proc pruneSocketSet(s: var seq[SocketHandle], fd: var FdSet) = 
-  var i = 0
-  var L = s.len
-  while i < L:
-    if FD_ISSET(s[i], fd) == 0'i32:
-      s[i] = s[L-1]
-      dec(L)
-    else:
-      inc(i)
-  setLen(s, L)
-
-proc select*(readfds: var seq[SocketHandle], timeout = 500): int =
-  ## Traditional select function. This function will return the number of
-  ## sockets that are ready to be read from, written to, or which have errors.
-  ## If there are none; 0 is returned. 
-  ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
-  ## 
-  ## A socket is removed from the specific ``seq`` when it has data waiting to
-  ## be read/written to or has errors (``exceptfds``).
-  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
-  var rd: FdSet
-  var m = 0
-  createFdSet((rd), readfds, m)
-  
-  if timeout != -1:
-    result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
-  else:
-    result = int(select(cint(m+1), addr(rd), nil, nil, nil))
-  
-  pruneSocketSet(readfds, (rd))
-
-proc selectWrite*(writefds: var seq[SocketHandle],
-                  timeout = 500): int {.tags: [ReadIOEffect].} =
-  ## When a socket in ``writefds`` is ready to be written to then a non-zero
-  ## value will be returned specifying the count of the sockets which can be
-  ## written to. The sockets which can be written to will also be removed
-  ## from ``writefds``.
-  ##
-  ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
-  ## an unlimited time.
-  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
-  var wr: FdSet
-  var m = 0
-  createFdSet((wr), writefds, m)
-  
-  if timeout != -1:
-    result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv)))
-  else:
-    result = int(select(cint(m+1), nil, addr(wr), nil, nil))
-  
-  pruneSocketSet(writefds, (wr))
-
-when defined(Windows):
-  var wsa: WSAData
-  if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 52d81b3a4..64d3e1470 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -798,6 +798,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
   
   return r.readInteger()
 
+# HyperLogLog
+
+proc pfadd*(r: Redis, key: string, elements: varargs[string]): RedisInteger = 
+  ## Add variable number of elements into special 'HyperLogLog' set type
+  r.sendCommand("PFADD", key, elements)
+  return r.readInteger()
+
+proc pfcount*(r: Redis, key: string): RedisInteger =
+  ## Count approximate number of elements in 'HyperLogLog'
+  r.sendCommand("PFCOUNT", key)
+  return r.readInteger()
+
+proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
+  ## Merge several source HyperLogLog's into one specified by destKey
+  r.sendCommand("PFMERGE", destination, sources)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
 
 # Pub/Sub
 
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index e0e2aa247..df637dcb6 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -45,7 +45,6 @@ when defined(windows):
   var
     oldAttr = getAttributes()
 
-  proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
 else:
   import termios, unsigned
 
@@ -344,7 +343,7 @@ proc isatty*(f: File): bool =
   else:
     proc isatty(fildes: FileHandle): cint {.
       importc: "_isatty", header: "<io.h>".}
-  
+
   result = isatty(getFileHandle(f)) != 0'i32
 
 proc styledEchoProcessArg(s: string) = write stdout, s
@@ -364,12 +363,11 @@ macro styledEcho*(m: varargs[expr]): stmt =
   result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
   result.add(newCall(bindSym"resetAttributes"))
 
-proc getch*(): char =
-  ## Read a single character from the terminal, blocking until it is entered.
-  ## The character is not printed to the terminal.
-  when defined(windows):
-    result = winGetch().char
-  else:
+when not defined(windows):
+  proc getch*(): char =
+    ## Read a single character from the terminal, blocking until it is entered.
+    ## The character is not printed to the terminal. This is not available for
+    ## Windows.
     let fd = getFileHandle(stdin)
     var oldMode: Termios
     discard fd.tcgetattr(addr oldMode)
@@ -387,5 +385,5 @@ when isMainModule:
   setForeGroundColor(fgBlue)
   writeln(stdout, "ordinary text")
 
-  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore}) 
-  
+  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
+
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index c39667611..25f6b85f6 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -26,9 +26,10 @@ type
   WeekDay* = enum ## represents a weekday
     dMon, dTue, dWed, dThu, dFri, dSat, dSun
 
-var
-  timezone {.importc, header: "<time.h>".}: int
-  tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
+when not defined(JS):
+  var
+    timezone {.importc, header: "<time.h>".}: int
+    tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
 
 when defined(posix) and not defined(JS):
   type
@@ -48,6 +49,11 @@ when defined(posix) and not defined(JS):
   proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
     importc: "gettimeofday", header: "<sys/time.h>".}
 
+  # we also need tzset() to make sure that tzname is initialized
+  proc tzset() {.importc, header: "<sys/time.h>".}
+  # calling tzset() implicitly to initialize tzname data.
+  tzset()
+
 elif defined(windows):
   import winlean
   
@@ -482,7 +488,7 @@ elif defined(JS):
     return newDate()
 
   const
-    weekDays: array [0..6, TWeekDay] = [
+    weekDays: array [0..6, WeekDay] = [
       dSun, dMon, dTue, dWed, dThu, dFri, dSat]
   
   proc getLocalTime(t: Time): TimeInfo =
@@ -490,7 +496,7 @@ elif defined(JS):
     result.minute = t.getMinutes()
     result.hour = t.getHours()
     result.monthday = t.getDate()
-    result.month = TMonth(t.getMonth())
+    result.month = Month(t.getMonth())
     result.year = t.getFullYear()
     result.weekday = weekDays[t.getDay()]
     result.yearday = 0
@@ -500,7 +506,7 @@ elif defined(JS):
     result.minute = t.getUTCMinutes()
     result.hour = t.getUTCHours()
     result.monthday = t.getUTCDate()
-    result.month = TMonth(t.getUTCMonth())
+    result.month = Month(t.getUTCMonth())
     result.year = t.getUTCFullYear()
     result.weekday = weekDays[t.getUTCDay()]
     result.yearday = 0
@@ -554,7 +560,7 @@ proc `$`*(day: WeekDay): string =
   return lookup[day]
 
 proc `$`*(m: Month): string =
-  ## stingify operator for ``TMonth``.
+  ## stingify operator for ``Month``.
   const lookup: array[Month, string] = ["January", "February", "March", 
       "April", "May", "June", "July", "August", "September", "October",
       "November", "December"]
@@ -1104,4 +1110,4 @@ when isMainModule:
   # Kitchen     = "3:04PM"
   s = "3:04PM"
   f = "h:mmtt"
-  echo "Kitchen: " & $s.parse(f)
\ No newline at end of file
+  echo "Kitchen: " & $s.parse(f)
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 42e6a3195..a6f8f916b 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -118,21 +118,35 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
   elif i <=% 0x07FF:
     result = newString(2)
     result[0] = chr((i shr 6) or 0b110_00000)
-    result[1] = chr((i and ones(6)) or 0b10_000000)
+    result[1] = chr((i and ones(6)) or 0b10_0000_00)
   elif i <=% 0xFFFF:
     result = newString(3)
     result[0] = chr(i shr 12 or 0b1110_0000)
     result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
     result[2] = chr(i and ones(6) or 0b10_0000_00)
-  elif i <=% 0x0010FFFF:
+  elif i <=% 0x001FFFFF:
     result = newString(4)
     result[0] = chr(i shr 18 or 0b1111_0000)
     result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
     result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
     result[3] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x03FFFFFF:
+    result = newString(5)
+    result[0] = chr(i shr 24 or 0b111110_00)
+    result[1] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x7FFFFFFF:
+    result = newString(6)
+    result[0] = chr(i shr 30 or 0b1111110_0)
+    result[1] = chr(i shr 24 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[5] = chr(i and ones(6) or 0b10_0000_00)
   else:
-    result = newString(1)
-    result[0] = chr(i)
+    discard # error, exception?
 
 proc `$`*(rune: Rune): string =
   ## converts a rune to a string
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 9a6e273a8..b0afb75f9 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -286,6 +286,16 @@ proc `$`*(u: Uri): string =
 
 when isMainModule:
   block:
+    let str = "http://localhost"
+    let test = parseUri(str)
+    doAssert test.path == ""
+
+  block:
+    let str = "http://localhost/"
+    let test = parseUri(str)
+    doAssert test.path == "/"
+
+  block:
     let str = "http://localhost:8080/test"
     let test = parseUri(str)
     doAssert test.scheme == "http"
diff --git a/lib/system.nim b/lib/system.nim
index abf31c821..ea35bd54a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -89,7 +89,7 @@ type
   SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
     ## type class matching all ordinal types; however this includes enums with
     ## holes.
-  
+
   SomeReal* = float|float32|float64
     ## type class matching all floating point number types
 
@@ -181,7 +181,7 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
   ## freeing the object. Note: The `finalizer` refers to the type `T`, not to
   ## the object! This means that for each object of type `T` the finalizer
   ## will be called!
-  
+
 proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
   ## resets an object `obj` to its initial (binary zero) value. This needs to
   ## be called before any possible `object branch transition`:idx:.
@@ -348,7 +348,7 @@ type
                   ## This field is filled automatically in the
                   ## ``raise`` statement.
     msg* {.exportc: "message".}: string ## the exception's message. Not
-                                        ## providing an exception message 
+                                        ## providing an exception message
                                         ## is bad style.
     trace: string
 
@@ -483,7 +483,7 @@ type
 
   E_Base: Exception, ESystem: SystemError, EIO: IOError,
   EOS: OSError, EInvalidLibrary: LibraryError,
-  EResourceExhausted: ResourceExhaustedError, 
+  EResourceExhausted: ResourceExhaustedError,
   EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
   EOverflow: OverflowError, EAccessViolation: AccessViolationError,
   EAssertionFailed: AssertionError, EInvalidValue: ValueError,
@@ -494,7 +494,7 @@ type
   EInvalidObjectAssignment: ObjectAssignmentError,
   EInvalidObjectConversion: ObjectConversionError,
   EDeadThread: DeadThreadError,
-  EFloatInexact: FloatInexactError, 
+  EFloatInexact: FloatInexactError,
   EFloatUnderflow: FloatUnderflowError,
   EFloatingPoint: FloatingPointError,
   EFloatInvalidOp: FloatInvalidOpError,
@@ -511,11 +511,11 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
 
 proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
   ## unary ``<`` that can be used for nice looking excluding ranges:
-  ## 
+  ##
   ## .. code-block:: nim
   ##   for i in 0 .. <10: echo i
   ##
-  ## Semantically this is the same as ``pred``. 
+  ## Semantically this is the same as ``pred``.
 
 proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
   ## returns the ``y``-th successor of the value ``x``. ``T`` has to be
@@ -536,7 +536,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
   ## decrements the ordinal ``x`` by ``y``. If such a value does not
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = pred(x, y)``.
-  
+
 proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
   ## This is equivalent to ``s = @[]; setlen(s, len)``, but more
@@ -636,7 +636,7 @@ when not defined(JS):
 
   proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
     ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
-    ## from `x`.    
+    ## from `x`.
   proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
     ## treats `x` as unsigned and converts it to an ``int16`` by taking the last
     ## 16 bits from `x`.
@@ -800,7 +800,7 @@ proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.}
   ## The result is truncated to fit into the result.
   ## This implements modulo arithmetic.
   ## No overflow errors are possible.
-  
+
 proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
 proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
   ## treats `x` and `y` as unsigned and compares them.
@@ -889,7 +889,7 @@ template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x)
 
 proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
   ## Checks if T is of the same type as S
-  ## 
+  ##
   ## .. code-block:: Nim
   ##   proc test[T](a: T): int =
   ##     when (T is int):
@@ -924,7 +924,7 @@ proc cmp*(x, y: string): int {.noSideEffect, procvar.}
 proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
   magic: "ArrToSeq", nosideeffect.}
   ## turns an array into a sequence. This most often useful for constructing
-  ## sequences with the array constructor: ``@[1, 2, 3]`` has the type 
+  ## sequences with the array constructor: ``@[1, 2, 3]`` has the type
   ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
 
 proc setLen*[T](s: var seq[T], newlen: int) {.
@@ -933,14 +933,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
   ## ``T`` may be any sequence type.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
-  ## a size, use ``newSeq`` instead. 
+  ## a size, use ``newSeq`` instead.
 
 proc setLen*(s: var string, newlen: int) {.
   magic: "SetLengthStr", noSideEffect.}
   ## sets the length of `s` to `newlen`.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
-  ## a size, use ``newString`` instead. 
+  ## a size, use ``newString`` instead.
 
 proc newString*(len: int): string {.
   magic: "NewString", importc: "mnewString", noSideEffect.}
@@ -953,7 +953,7 @@ proc newString*(len: int): string {.
 proc newStringOfCap*(cap: int): string {.
   magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
   ## returns a new string of length ``0`` but with capacity `cap`.This
-  ## procedure exists only for optimization purposes; the same effect can 
+  ## procedure exists only for optimization purposes; the same effect can
   ## be achieved with the ``&`` operator or with ``add``.
 
 proc `&` * (x: string, y: char): string {.
@@ -982,7 +982,7 @@ proc `&` * (x: char, y: string): string {.
   ##   assert('a' & "bc" == "abc")
 
 # implementation note: These must all have the same magic value "ConStrStr" so
-# that the merge optimization works properly. 
+# that the merge optimization works properly.
 
 proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
   ## Appends `y` to `x` in place
@@ -1039,15 +1039,15 @@ proc compileOption*(option: string): bool {.
   ## can be used to determine an on|off compile-time option. Example:
   ##
   ## .. code-block:: nim
-  ##   when compileOption("floatchecks"): 
+  ##   when compileOption("floatchecks"):
   ##     echo "compiled with floating point NaN and Inf checks"
-  
+
 proc compileOption*(option, arg: string): bool {.
   magic: "CompileOptionArg", noSideEffect.}
   ## can be used to determine an enum compile-time option. Example:
   ##
   ## .. code-block:: nim
-  ##   when compileOption("opt", "size") and compileOption("gc", "boehm"): 
+  ##   when compileOption("opt", "size") and compileOption("gc", "boehm"):
   ##     echo "compiled with optimization for size and uses Boehm's GC"
 
 const
@@ -1056,16 +1056,16 @@ const
   taintMode = compileOption("taintmode")
 
 when taintMode:
-  type TaintedString* = distinct string ## a distinct string type that 
+  type TaintedString* = distinct string ## a distinct string type that
                                         ## is `tainted`:idx:. It is an alias for
                                         ## ``string`` if the taint mode is not
                                         ## turned on. Use the ``-d:taintMode``
                                         ## command line switch to turn the taint
                                         ## mode on.
-  
+
   proc len*(s: TaintedString): int {.borrow.}
 else:
-  type TaintedString* = string          ## a distinct string type that 
+  type TaintedString* = string          ## a distinct string type that
                                         ## is `tainted`:idx:. It is an alias for
                                         ## ``string`` if the taint mode is not
                                         ## turned on. Use the ``-d:taintMode``
@@ -1136,25 +1136,25 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
 proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
   ## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
   ## only changes the semantics for sequences and strings (and types which
-  ## contain those). Be careful with the changed semantics though! There 
+  ## contain those). Be careful with the changed semantics though! There
   ## is a reason why the default assignment does a deep copy of sequences
   ## and strings.
 
-proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = 
+proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
   ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
   ## This is an O(1) operation.
   let xl = x.len
   shallowCopy(x[i], x[xl-1])
   setLen(x, xl-1)
-  
-proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = 
+
+proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
   ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
   ## This is an O(n) operation.
   let xl = x.len
-  for j in i..xl-2: shallowCopy(x[j], x[j+1]) 
+  for j in i..xl-2: shallowCopy(x[j], x[j+1])
   setLen(x, xl-1)
-  
-proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = 
+
+proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
   ## inserts `item` into `x` at position `i`.
   let xl = x.len
   setLen(x, xl+1)
@@ -1233,7 +1233,7 @@ type # these work for most platforms:
     ## This is binary compatible to the type ``char**`` in *C*. The array's
     ## high value is large enough to disable bounds checking in practice.
     ## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
-  
+
   PFloat32* = ptr float32 ## an alias for ``ptr float32``
   PFloat64* = ptr float64 ## an alias for ``ptr float64``
   PInt64* = ptr int64 ## an alias for ``ptr int64``
@@ -1280,7 +1280,7 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
 proc copy*(s: string, first = 0): string {.
   magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
 proc copy*(s: string, first, last: int): string {.
-  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect, 
+  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
   deprecated.}
   ## copies a slice of `s` into a new string and returns this new
   ## string. The bounds `first` and `last` denote the indices of
@@ -1358,7 +1358,7 @@ when not defined(nimrodVM):
       ## The allocated memory belongs to its allocating thread!
       ## Use `createShared` to allocate from a shared heap.
       cast[ptr T](alloc0(T.sizeof * size))
-    proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [], 
+    proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
                                                        benign.}
       ## grows or shrinks a given memory block. If p is **nil** then a new
       ## memory block is returned. In either way the block has at least
@@ -1381,7 +1381,7 @@ when not defined(nimrodVM):
       ## ``realloc``. This procedure is dangerous! If one forgets to
       ## free the memory a leak occurs; if one tries to access freed
       ## memory (or just freeing it twice!) a core dump may happen
-      ## or other memory may be corrupted. 
+      ## or other memory may be corrupted.
       ## The freed memory must belong to its allocating thread!
       ## Use `deallocShared` to deallocate from a shared heap.
     proc free*[T](p: ptr T) {.inline, benign.} =
@@ -1390,30 +1390,30 @@ when not defined(nimrodVM):
       ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
-      ## is not initialized, so reading from it before writing to it is 
+      ## is not initialized, so reading from it before writing to it is
       ## undefined behaviour!
-    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, 
+    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
                                                                  benign.} =
       ## allocates a new memory block on the shared heap with at
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
       ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
-      ## is not initialized, so reading from it before writing to it is 
+      ## is not initialized, so reading from it before writing to it is
       ## undefined behaviour!
       cast[ptr T](allocShared(T.sizeof * size))
     proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
-      ## allocates a new memory block on the shared heap with at 
+      ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``allocShared``.
     proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
-      ## allocates a new memory block on the shared heap with at 
+      ## allocates a new memory block on the shared heap with at
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
       ## ``resizeShared(block, 0)`` or ``freeShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``createSharedU``.
       cast[ptr T](allocShared0(T.sizeof * size))
-    proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl, 
+    proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
                                                              benign.}
       ## grows or shrinks a given memory block on the heap. If p is **nil**
       ## then a new memory block is returned. In either way the block has at
@@ -1525,7 +1525,7 @@ const
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
     ## is the version of Nim as a string.
 
-{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion, 
+{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
     NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
 
 # GC interface:
@@ -1556,30 +1556,51 @@ when not defined(nimrodVM) and hostOS != "standalone":
       ## returns the number of bytes on the shared heap that are owned by the
       ## process. This is only available when threads are enabled.
 
+when sizeof(int) <= 2:
+  type IntLikeForCount = int|int8|int16|char|bool|uint8
+else:
+  type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16
+
 iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
   ## Counts from ordinal value `a` down to `b` with the given
   ## step count. `T` may be any ordinal type, `step` may only
-  ## be positive.
-  var res = a
-  while res >= b:
-    yield res
-    dec(res, step)
+  ## be positive. **Note**: This fails to count to ``low(int)`` if T = int for
+  ## efficiency reasons.
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res >= int(b):
+      yield T(res)
+      dec(res, step)
+  else:
+    var res = a
+    while res >= b:
+      yield res
+      dec(res, step)
+
+template countupImpl(incr: stmt) {.immediate, dirty.} =
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res <= int(b):
+      yield T(res)
+      incr
+  else:
+    var res: T = T(a)
+    while res <= b:
+      yield res
+      incr
 
 iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
   ## Counts from ordinal value `a` up to `b` with the given
   ## step count. `S`, `T` may be any ordinal type, `step` may only
-  ## be positive.
-  var res: T = T(a)
-  while res <= b:
-    yield res
+  ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
+  ## efficiency reasons.
+  countupImpl:
     inc(res, step)
 
 iterator `..`*[S, T](a: S, b: T): T {.inline.} =
   ## An alias for `countup`.
-  var res: T = T(a)
-  while res <= b:
-    yield res
-    inc res
+  countupImpl:
+    inc(res)
 
 iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
   inline, magic: "OmpParFor", sideEffect.} =
@@ -1805,7 +1826,7 @@ proc `==` *[I, T](x, y: array[I, T]): bool =
       return
   result = true
 
-proc `@`*[T](a: openArray[T]): seq[T] = 
+proc `@`*[T](a: openArray[T]): seq[T] =
   ## turns an openarray into a sequence. This is not as efficient as turning
   ## a fixed length array into a sequence as it always copies every element
   ## of `a`.
@@ -1853,7 +1874,7 @@ when not defined(NimrodVM):
   else:
     proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
       asm """return `x`"""
-  
+
   proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
     ## Generic equals operator for sequences: relies on a equals operator for
     ## the element type `T`.
@@ -1879,7 +1900,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}=
   ## for ``find(a, item) >= 0``.
   return find(a, item) >= 0
 
-proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = 
+proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
   ## returns the last item of `s` and decreases ``s.len`` by one. This treats
   ## `s` as a stack and implements the common *pop* operation.
   var L = s.len-1
@@ -1941,7 +1962,7 @@ iterator fields*[T: tuple|object](x: T): RootObj {.
 iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
   magic: "Fields", noSideEffect.}
   ## iterates over every field of `x` and `y`.
-  ## Warning: This is really transforms the 'for' and unrolls the loop. 
+  ## Warning: This is really transforms the 'for' and unrolls the loop.
   ## The current implementation also has a bug that affects symbol binding
   ## in the loop body.
 iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
@@ -1982,18 +2003,18 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
   a, b: expr] {.
   magic: "FieldPairs", noSideEffect.}
   ## iterates over every field of `x` and `y`.
-  ## Warning: This really transforms the 'for' and unrolls the loop. 
+  ## Warning: This really transforms the 'for' and unrolls the loop.
   ## The current implementation also has a bug that affects symbol binding
   ## in the loop body.
 
-proc `==`*[T: tuple|object](x, y: T): bool = 
+proc `==`*[T: tuple|object](x, y: T): bool =
   ## generic ``==`` operator for tuples that is lifted from the components
   ## of `x` and `y`.
   for a, b in fields(x, y):
     if a != b: return false
   return true
 
-proc `<=`*[T: tuple](x, y: T): bool = 
+proc `<=`*[T: tuple](x, y: T): bool =
   ## generic ``<=`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
@@ -2002,7 +2023,7 @@ proc `<=`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return true
 
-proc `<`*[T: tuple](x, y: T): bool = 
+proc `<`*[T: tuple](x, y: T): bool =
   ## generic ``<`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
@@ -2011,7 +2032,7 @@ proc `<`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return false
 
-proc `$`*[T: tuple|object](x: T): string = 
+proc `$`*[T: tuple|object](x: T): string =
   ## generic ``$`` operator for tuples that is lifted from the components
   ## of `x`. Example:
   ##
@@ -2021,13 +2042,13 @@ proc `$`*[T: tuple|object](x: T): string =
   result = "("
   var firstElement = true
   for name, value in fieldPairs(x):
-    if not(firstElement): result.add(", ")
+    if not firstElement: result.add(", ")
     result.add(name)
     result.add(": ")
     result.add($value)
     firstElement = false
   result.add(")")
-  
+
 proc collectionToString[T](x: T, b, e: string): string =
   result = b
   var firstElement = true
@@ -2037,7 +2058,7 @@ proc collectionToString[T](x: T, b, e: string): string =
     firstElement = false
   result.add(e)
 
-proc `$`*[T](x: set[T]): string = 
+proc `$`*[T](x: set[T]): string =
   ## generic ``$`` operator for sets that is lifted from the components
   ## of `x`. Example:
   ##
@@ -2045,7 +2066,7 @@ proc `$`*[T](x: set[T]): string =
   ##   ${23, 45} == "{23, 45}"
   collectionToString(x, "{", "}")
 
-proc `$`*[T](x: seq[T]): string = 
+proc `$`*[T](x: seq[T]): string =
   ## generic ``$`` operator for seqs that is lifted from the components
   ## of `x`. Example:
   ##
@@ -2056,7 +2077,7 @@ proc `$`*[T](x: seq[T]): string =
 when false:
   # causes bootstrapping to fail as we use array of chars and cstring should
   # match better ...
-  proc `$`*[T, IDX](x: array[IDX, T]): string = 
+  proc `$`*[T, IDX](x: array[IDX, T]): string =
     collectionToString(x, "[", "]")
 
 # ----------------- GC interface ---------------------------------------------
@@ -2098,14 +2119,14 @@ when not defined(nimrodVM) and hostOS != "standalone":
   proc GC_getStatistics*(): string {.rtl, benign.}
     ## returns an informative string about the GC's activity. This may be useful
     ## for tweaking.
-    
+
   proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
   proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
   proc GC_ref*(x: string) {.magic: "GCref", benign.}
     ## marks the object `x` as referenced, so that it will not be freed until
     ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
-    ## n calls to `GC_unref` are needed to unmark `x`. 
-    
+    ## n calls to `GC_unref` are needed to unmark `x`.
+
   proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
   proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
   proc GC_unref*(x: string) {.magic: "GCunref", benign.}
@@ -2141,19 +2162,19 @@ var
     ## application code should never set this hook! You better know what you
     ## do when setting this. If ``localRaiseHook`` returns false, the exception
     ## is caught and does not propagate further through the call stack.
-    
+
   outOfMemHook*: proc () {.nimcall, tags: [], benign.}
-    ## set this variable to provide a procedure that should be called 
+    ## set this variable to provide a procedure that should be called
     ## in case of an `out of memory`:idx: event. The standard handler
     ## writes an error message and terminates the program. `outOfMemHook` can
     ## be used to raise an exception in case of OOM like so:
-    ## 
+    ##
     ## .. code-block:: nim
     ##
     ##   var gOutOfMem: ref EOutOfMemory
     ##   new(gOutOfMem) # need to be allocated *before* OOM really happened!
     ##   gOutOfMem.msg = "out of memory"
-    ## 
+    ##
     ##   proc handleOOM() =
     ##     raise gOutOfMem
     ##
@@ -2210,7 +2231,7 @@ proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect],
   ## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
   ## instead.
 
-proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, 
+proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
                                            tags: [], raises: [].}
   ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
   ## pretends to be free of side effects, so that it can be used for debugging
@@ -2262,7 +2283,7 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} =
 proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
   if x < 0: -x else: x
 proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
-  ## returns the absolute value of `x`. If `x` is ``low(x)`` (that 
+  ## returns the absolute value of `x`. If `x` is ``low(x)`` (that
   ## is -MININT for its type), an overflow exception is thrown (if overflow
   ## checking is turned on).
   if x < 0: -x else: x
@@ -2318,14 +2339,14 @@ when not defined(JS): #and not defined(NimrodVM):
       # we use binary mode in Windows:
       setmode(fileno(c_stdin), O_BINARY)
       setmode(fileno(c_stdout), O_BINARY)
-    
+
     when defined(endb):
       proc endbStep()
 
   # ----------------- IO Part ------------------------------------------------
   when hostOS != "standalone":
     type
-      CFile {.importc: "FILE", header: "<stdio.h>", 
+      CFile {.importc: "FILE", header: "<stdio.h>",
               final, incompletestruct.} = object
       File* = ptr CFile ## The type representing a file handle.
 
@@ -2375,9 +2396,9 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Creates a ``TFile`` from a `filehandle` with given `mode`.
       ##
       ## Default mode is readonly. Returns true iff the file could be opened.
-      
+
     proc open*(filename: string,
-               mode: FileMode = fmRead, bufSize: int = -1): File = 
+               mode: FileMode = fmRead, bufSize: int = -1): File =
       ## Opens a file named `filename` with given `mode`.
       ##
       ## Default mode is readonly. Raises an ``IO`` exception if the file
@@ -2387,7 +2408,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
       tags: [], benign.}
-      ## reopens the file `f` with given `filename` and `mode`. This 
+      ## reopens the file `f` with given `filename` and `mode`. This
       ## is often used to redirect the `stdin`, `stdout` or `stderr`
       ## file variables.
       ##
@@ -2398,7 +2419,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     proc endOfFile*(f: File): bool {.tags: [], benign.}
       ## Returns true iff `f` is at the end.
-      
+
     proc readChar*(f: File): char {.
       importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
       ## Reads a single character from the stream `f`.
@@ -2411,7 +2432,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##
       ## Raises an IO exception in case of an error. It is an error if the
       ## current file position is not at the beginning of the file.
-    
+
     proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
       ## Opens a file named `filename` for reading.
       ##
@@ -2440,8 +2461,8 @@ when not defined(JS): #and not defined(NimrodVM):
       ## reads a line of text from the file `f`. May throw an IO exception.
       ## A line of text may be delimited by ``CR``, ``LF`` or
       ## ``CRLF``. The newline character(s) are not part of the returned string.
-    
-    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], 
+
+    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
                   benign.}
       ## reads a line of text from the file `f` into `line`. `line` must not be
       ## ``nil``! May throw an IO exception.
@@ -2450,7 +2471,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Returns ``false`` if the end of the file has been reached, ``true``
       ## otherwise. If ``false`` is returned `line` contains no new data.
 
-    proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, 
+    proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
                              tags: [WriteIOEffect], benign.}
       ## writes the values `x` to `f` and then writes "\n".
       ## May throw an IO exception.
@@ -2544,11 +2565,11 @@ when not defined(JS): #and not defined(NimrodVM):
       dealloc(a)
 
   when not defined(NimrodVM):
-    proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, 
+    proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
       discardable, benign.}
       ## atomic increment of `memLoc`. Returns the value after the operation.
-    
-    proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, 
+
+    proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
       discardable, benign.}
       ## atomic decrement of `memLoc`. Returns the value after the operation.
 
@@ -2562,7 +2583,7 @@ when not defined(JS): #and not defined(NimrodVM):
       context: C_JmpBuf
       hasRaiseAction: bool
       raiseAction: proc (e: ref Exception): bool {.closure.}
-  
+
   when declared(initAllocator):
     initAllocator()
   when hasThreadSupport:
@@ -2576,7 +2597,7 @@ when not defined(JS): #and not defined(NimrodVM):
     proc setControlCHook*(hook: proc () {.noconv.} not nil)
       ## allows you to override the behaviour of your application when CTRL+C
       ## is pressed. Only one such hook is supported.
-      
+
     proc writeStackTrace*() {.tags: [WriteIOEffect].}
       ## writes the current stack trace to ``stderr``. This is only works
       ## for debug builds.
@@ -2587,20 +2608,20 @@ when not defined(JS): #and not defined(NimrodVM):
       proc getStackTrace*(e: ref Exception): string
         ## gets the stack trace associated with `e`, which is the stack that
         ## lead to the ``raise`` statement. This only works for debug builds.
-        
+
     {.push stack_trace: off, profiler:off.}
     when hostOS == "standalone":
       include "system/embedded"
     else:
       include "system/excpt"
     include "system/chcks"
-      
+
     # we cannot compile this with stack tracing on
     # as it would recurse endlessly!
     include "system/arithm"
     {.pop.} # stack trace
   {.pop.} # stack trace
-      
+
   when hostOS != "standalone" and not defined(NimrodVM):
     include "system/dyncalls"
   when not defined(NimrodVM):
@@ -2608,7 +2629,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     const
       GenericSeqSize = (2 * sizeof(int))
-      
+
     proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
       sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
       var d: int
@@ -2728,7 +2749,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##       process(value)
       ##     else:
       ##       echo "Value too big!"
-    
+
     proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
       ## Hints the optimizer that `val` is likely going to be false.
       ##
@@ -2742,7 +2763,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##       echo "Value too big!"
       ##     else:
       ##       process(value)
-      
+
     proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
       ## retrieves the raw proc pointer of the closure `x`. This is
       ## useful for interfacing closures with C.
@@ -2774,7 +2795,7 @@ elif defined(JS):
   proc GC_enableMarkAndSweep() = discard
   proc GC_disableMarkAndSweep() = discard
   proc GC_getStatistics(): string = return ""
-  
+
   proc getOccupiedMem(): int = return -1
   proc getFreeMem(): int = return -1
   proc getTotalMem(): int = return -1
@@ -2797,7 +2818,7 @@ elif defined(JS):
       if x == y: return 0
       if x < y: return -1
       return 1
-  
+
   when defined(nimffi):
     include "system/sysio"
 
@@ -2831,14 +2852,14 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
     # cut down:
     setLen(s, newLen)
   # fill the hole:
-  for i in 0 .. <b.len: s[i+a] = b[i]  
+  for i in 0 .. <b.len: s[i+a] = b[i]
 
 when hostOS != "standalone":
   proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
     ## slice operation for strings. Negative indexes are supported.
     result = s.substr(x.a-|s, x.b-|s)
 
-  proc `[]=`*(s: var string, x: Slice[int], b: string) = 
+  proc `[]=`*(s: var string, x: Slice[int], b: string) =
     ## slice assignment for strings. Negative indexes are supported. If
     ## ``b.len`` is not exactly the number of elements that are referred to
     ## by `x`, a `splice`:idx: is performed:
@@ -2880,7 +2901,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
   var L = ord(x.b) - ord(x.a) + 1
   newSeq(result, L)
   var j = x.a
-  for i in 0.. <L: 
+  for i in 0.. <L:
     result[i] = a[j]
     inc(j)
 
@@ -2890,23 +2911,23 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
   var L = ord(x.b) - ord(x.a) + 1
   if L == b.len:
     var j = x.a
-    for i in 0 .. <L: 
+    for i in 0 .. <L:
       a[j] = b[i]
       inc(j)
   else:
     sysFatal(RangeError, "different lengths for slice assignment")
 
-proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = 
+proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
   ## slice operation for sequences. Negative indexes are supported.
   var a = x.a-|s
   var L = x.b-|s - a + 1
   newSeq(result, L)
   for i in 0.. <L: result[i] = s[i + a]
 
-proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = 
+proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
   ## slice assignment for sequences. Negative indexes are supported. If
   ## ``b.len`` is not exactly the number of elements that are referred to
-  ## by `x`, a `splice`:idx: is performed. 
+  ## by `x`, a `splice`:idx: is performed.
   var a = x.a-|s
   var L = x.b-|s - a + 1
   if L == b.len:
@@ -2937,7 +2958,7 @@ proc staticExec*(command: string, input = ""): string {.
   ## to the executed program.
   ##
   ## .. code-block:: nim
-  ##     const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & 
+  ##     const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
   ##                       "\nCompiled on " & staticExec("uname -v")
   ##
   ## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
@@ -2979,7 +3000,7 @@ proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
 proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
   ## converts the AST of `x` into a string representation. This is very useful
   ## for debugging.
-  
+
 proc instantiationInfo*(index = -1, fullPaths = false): tuple[
   filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
   ## provides access to the compiler's instantiation stack line information.
@@ -3090,16 +3111,16 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
   ## Sets an assertion failure handler that will intercept any assert
   ## statements following `onFailedAssert` in the current lexical scope.
   ## Can be defined multiple times in a single function.
-  ##  
+  ##
   ## .. code-block:: nim
   ##
   ##   proc example(x: int): TErrorCode =
   ##     onFailedAssert(msg):
   ##       log msg
   ##       return E_FAIL
-  ## 
+  ##
   ##     assert(...)
-  ##     
+  ##
   ##     onFailedAssert(msg):
   ##       raise newException(EMyException, msg)
   ##
@@ -3111,7 +3132,7 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
 
 proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
   ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
-  ## perform deep copies of `s`. This is only useful for optimization 
+  ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
   when not defined(JS) and not defined(NimrodVM):
     var s = cast[PGenericSeq](s)
@@ -3119,7 +3140,7 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
 
 proc shallow*(s: var string) {.noSideEffect, inline.} =
   ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
-  ## perform deep copies of `s`. This is only useful for optimization 
+  ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
   when not defined(JS) and not defined(NimrodVM):
     var s = cast[PGenericSeq](s)
@@ -3141,13 +3162,13 @@ else:
 when false:
   template eval*(blk: stmt): stmt =
     ## executes a block of code at compile time just as if it was a macro
-    ## optionally, the block can return an AST tree that will replace the 
+    ## optionally, the block can return an AST tree that will replace the
     ## eval expression
     macro payload: stmt {.gensym.} = blk
     payload()
 
 when hostOS != "standalone":
-  proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = 
+  proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
     ## inserts `item` into `x` at position `i`.
     var xl = x.len
     setLen(x, xl+item.len)
diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim
index 7a26a17c5..093c0f3a7 100644
--- a/lib/system/deepcopy.nim
+++ b/lib/system/deepcopy.nim
@@ -34,9 +34,9 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
 
 proc copyDeepString(src: NimString): NimString {.inline.} =
   if src != nil:
-    result = rawNewString(src.space)
+    result = rawNewStringNoInit(src.len)
     result.len = src.len
-    c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
+    c_memcpy(result.data, src.data, src.len + 1)
 
 proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
   var
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 1f4279c8f..c4374d00c 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.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.
@@ -48,7 +48,7 @@ type
   TWalkOp = enum
     waMarkGlobal,    # part of the backup/debug mark&sweep
     waMarkPrecise,   # part of the backup/debug mark&sweep
-    waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, 
+    waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
     waCollectWhite #, waDebug
 
   TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
@@ -61,9 +61,9 @@ type
     maxThreshold: int        # max threshold that has been set
     maxStackSize: int        # max stack size
     maxStackCells: int       # max stack cells in ``decStack``
-    cycleTableSize: int      # max entries in cycle table  
+    cycleTableSize: int      # max entries in cycle table
     maxPause: int64          # max measured GC pause in nanoseconds
-  
+
   TGcHeap {.final, pure.} = object # this contains the zero count and
                                    # non-zero count table
     stackBottom: pointer
@@ -88,11 +88,11 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: TGcHeap) = 
+template acquire(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
 
-template release(gch: TGcHeap) = 
+template release(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     releaseSys(HeapLock)
 
@@ -117,7 +117,7 @@ proc usrToCell(usr: pointer): PCell {.inline.} =
   # convert pointer to userdata to object (=pointer to refcount)
   result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
 
-proc canbeCycleRoot(c: PCell): bool {.inline.} =
+proc canBeCycleRoot(c: PCell): bool {.inline.} =
   result = ntfAcyclic notin c.typ.flags
 
 proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
@@ -163,7 +163,7 @@ when hasThreadSupport and hasSharedHeap:
   template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
   template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
 else:
-  template `--`(x: expr): expr = 
+  template `--`(x: expr): expr =
     dec(x, rcIncrement)
     x <% rcIncrement
   template `++`(x: expr): stmt = inc(x, rcIncrement)
@@ -181,7 +181,7 @@ proc prepareDealloc(cell: PCell) =
     (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
     dec(gch.recGcLock)
 
-proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = 
+proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
   # we MUST access gch as a global here, because this crosses DLL boundaries!
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
@@ -211,7 +211,7 @@ proc decRef(c: PCell) {.inline.} =
     rtlAddCycleRoot(c)
     #writeCell("decRef", c)
 
-proc incRef(c: PCell) {.inline.} = 
+proc incRef(c: PCell) {.inline.} =
   gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
   c.refcount = c.refcount +% rcIncrement
   # and not colorMask
@@ -246,12 +246,12 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
   dest[] = src
 
 proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
-  # the code generator calls this proc if it is known at compile time that no 
+  # the code generator calls this proc if it is known at compile time that no
   # cycle is possible.
   if src != nil:
     var c = usrToCell(src)
     ++c.refcount
-  if dest[] != nil: 
+  if dest[] != nil:
     var c = usrToCell(dest[])
     if --c.refcount:
       rtlAddZCT(c)
@@ -269,7 +269,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
     if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
   else:
     # can't be an interior pointer if it's a stack location!
-    gcAssert(interiorAllocatedPtr(gch.region, dest) == nil, 
+    gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
              "stack loc AND interior pointer")
   dest[] = src
 
@@ -321,7 +321,7 @@ when useMarkForDebug or useBackupGc:
       echo "[GC] cannot register global variable; too many global variables"
       quit 1
 
-proc cellsetReset(s: var TCellSet) = 
+proc cellsetReset(s: var TCellSet) =
   deinit(s)
   init(s)
 
@@ -336,7 +336,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
         if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
           doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
         else:
-          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), 
+          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
                             n.sons[i].typ, op)
       else:
         forAllSlotsAux(dest, n.sons[i], op)
@@ -384,7 +384,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
   # we check the last 8 entries (cache line) for a slot that could be reused.
   # In 63% of all cases we succeed here! But we have to optimize the heck
   # out of this small linear search so that ``newObj`` is not slowed down.
-  # 
+  #
   # Slots to try          cache hit
   # 1                     32%
   # 4                     59%
@@ -461,6 +461,10 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
 
 {.pop.}
 
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  when defined(memProfiler): nimProfile(size)
+
 proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
   result = rawNewObj(typ, size, gch)
   zeroMem(result, size)
@@ -481,7 +485,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch)
   sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
-  
+
   var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
   sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
@@ -510,7 +514,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
   when defined(memProfiler): nimProfile(size)
-  
+
 proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   acquire(gch)
   collectCT(gch)
@@ -522,7 +526,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
   var elemSize = 1
   if ol.typ.kind != tyString: elemSize = ol.typ.base.size
-  
+
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(TCell))
   zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
@@ -536,7 +540,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
     writeCell("growObj new cell", res)
   gcTrace(ol, csZctFreed)
   gcTrace(res, csAllocated)
-  when reallyDealloc: 
+  when reallyDealloc:
     sysAssert(allocInv(gch.region), "growObj before dealloc")
     if ol.refcount shr rcShift <=% 1:
       # free immediately to save space:
@@ -580,7 +584,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
   prepareDealloc(c)
   gcTrace(c, csCycFreed)
   when logGC: writeCell("cycle collector dealloc cell", c)
-  when reallyDealloc: 
+  when reallyDealloc:
     sysAssert(allocInv(gch.region), "free cyclic cell")
     rawDealloc(gch.region, c)
   else:
@@ -767,7 +771,7 @@ proc collectCycles(gch: var TGcHeap) =
       gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
       gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
       if canBeCycleRoot(c):
-        #if c notin gch.cycleRoots: 
+        #if c notin gch.cycleRoots:
         inc cycleRootsLen
         incl(gch.cycleRoots, c)
       gcAssert c.typ != nil, "addBackStackRoots 2"
@@ -794,12 +798,12 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
         add(gch.decStack, cell)
   sysAssert(allocInv(gch.region), "gcMark end")
 
-proc markThreadStacks(gch: var TGcHeap) = 
+proc markThreadStacks(gch: var TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     {.error: "not fully implemented".}
     var it = threadList
     while it != nil:
-      # mark registers: 
+      # mark registers:
       for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
       var sp = cast[TAddress](it.stackBottom)
       var max = cast[TAddress](it.stackTop)
@@ -933,7 +937,7 @@ else:
       while sp <=% max:
         gcMark(gch, cast[PPointer](sp)[])
         sp = sp +% sizeof(pointer)
-    
+
 proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
   forEachStackSlot(gch, gcMark)
 
@@ -946,13 +950,13 @@ when useMarkForDebug or useBackupGc:
 # ----------------------------------------------------------------------------
 
 proc collectZCT(gch: var TGcHeap): bool =
-  # Note: Freeing may add child objects to the ZCT! So essentially we do 
-  # deep freeing, which is bad for incremental operation. In order to 
+  # Note: Freeing may add child objects to the ZCT! So essentially we do
+  # deep freeing, which is bad for incremental operation. In order to
   # avoid a deep stack, we move objects to keep the ZCT small.
   # This is performance critical!
   const workPackage = 100
   var L = addr(gch.zct.len)
-  
+
   when withRealTime:
     var steps = workPackage
     var t0: TTicks
@@ -962,15 +966,15 @@ proc collectZCT(gch: var TGcHeap): bool =
     sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
     # remove from ZCT:
     gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
-    
+
     c.refcount = c.refcount and not ZctFlag
     gch.zct.d[0] = gch.zct.d[L[] - 1]
     dec(L[])
     when withRealTime: dec steps
-    if c.refcount <% rcIncrement: 
+    if c.refcount <% rcIncrement:
       # It may have a RC > 0, if it is in the hardware stack or
       # it has not been removed yet from the ZCT. This is because
-      # ``incref`` does not bother to remove the cell from the ZCT 
+      # ``incref`` does not bother to remove the cell from the ZCT
       # as this might be too slow.
       # In any case, it should be removed from the ZCT. But not
       # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
@@ -983,7 +987,7 @@ proc collectZCT(gch: var TGcHeap): bool =
       # access invalid memory. This is done by prepareDealloc():
       prepareDealloc(c)
       forAllChildren(c, waZctDecRef)
-      when reallyDealloc: 
+      when reallyDealloc:
         sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
         rawDealloc(gch.region, c)
       else:
@@ -994,7 +998,7 @@ proc collectZCT(gch: var TGcHeap): bool =
         steps = workPackage
         if gch.maxPause > 0:
           let duration = getticks() - t0
-          # the GC's measuring is not accurate and needs some cleanup actions 
+          # the GC's measuring is not accurate and needs some cleanup actions
           # (stack unmarking), so subtract some short amount of time in
           # order to miss deadlines less often:
           if duration >= gch.maxPause - 50_000:
@@ -1017,7 +1021,7 @@ proc collectCTBody(gch: var TGcHeap) =
   when withRealTime:
     let t0 = getticks()
   sysAssert(allocInv(gch.region), "collectCT: begin")
-  
+
   gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
   sysAssert(gch.decStack.len == 0, "collectCT")
   prepareForInteriorPointerChecking(gch.region)
@@ -1036,7 +1040,7 @@ proc collectCTBody(gch: var TGcHeap) =
         gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
   unmarkStackAndRegisters(gch)
   sysAssert(allocInv(gch.region), "collectCT: end")
-  
+
   when withRealTime:
     let duration = getticks() - t0
     gch.stat.maxPause = max(gch.stat.maxPause, duration)
@@ -1050,8 +1054,12 @@ when useMarkForDebug or useBackupGc:
     markGlobals(gch)
 
 proc collectCT(gch: var TGcHeap) =
-  if (gch.zct.len >= ZctThreshold or (cycleGC and
-      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and 
+  # stackMarkCosts prevents some pathological behaviour: Stack marking
+  # becomes more expensive with large stacks and large stacks mean that
+  # cells with RC=0 are more likely to be kept alive by the stack.
+  let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
+  if (gch.zct.len >= stackMarkCosts or (cycleGC and
+      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
       gch.recGcLock == 0:
     when useMarkForDebug:
       prepareForInteriorPointerChecking(gch.region)
@@ -1070,7 +1078,7 @@ when withRealTime:
     acquire(gch)
     gch.maxPause = us.toNano
     if (gch.zct.len >= ZctThreshold or (cycleGC and
-        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or 
+        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
         strongAdvice:
       collectCTBody(gch)
     release(gch)
@@ -1078,13 +1086,13 @@ when withRealTime:
   proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
 
 when not defined(useNimRtl):
-  proc GC_disable() = 
+  proc GC_disable() =
     when hasThreadSupport and hasSharedHeap:
       discard atomicInc(gch.recGcLock, 1)
     else:
       inc(gch.recGcLock)
   proc GC_enable() =
-    if gch.recGcLock > 0: 
+    if gch.recGcLock > 0:
       when hasThreadSupport and hasSharedHeap:
         discard atomicDec(gch.recGcLock, 1)
       else:
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
index ae2d2c85d..4e3dee51c 100644
--- a/lib/system/gc2.nim
+++ b/lib/system/gc2.nim
@@ -593,7 +593,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
         return
     add(gch.zct, res)
 
-proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
+proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
   # generates a new object and sets its reference counter to 0
   acquire(gch)
   sysAssert(allocInv(gch.region), "rawNewObj begin")
@@ -634,8 +634,6 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
   gcTrace(res, csAllocated)
   release(gch)
   result = cellToUsr(res)
-  zeroMem(result, size)
-  when defined(memProfiler): nimProfile(size)
   sysAssert(allocInv(gch.region), "rawNewObj end")
 
 {.pop.}
@@ -670,23 +668,31 @@ template trimAt(roots: var TCellSeq, at: int): stmt =
 proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
   setStackTop(gch)
   result = rawNewObj(typ, size, gch, false)
-  
+  zeroMem(result, size)
+  when defined(memProfiler): nimProfile(size)
+
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  setStackTop(gch)
+  result = rawNewObj(typ, size, gch, false)
+  when defined(memProfiler): nimProfile(size)
+
 proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
   setStackTop(gch)
-  # `rawNewObj` already uses locks, so no need for them here.
+  # `newObj` already uses locks, so no need for them here.
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
-  result = rawNewObj(typ, size, gch, false)
+  result = newObj(typ, size)
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
 
 proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   setStackTop(gch)
   result = rawNewObj(typ, size, gch, true)
+  when defined(memProfiler): nimProfile(size)
 
 proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   setStackTop(gch)
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
-  result = rawNewObj(typ, size, gch, true)
+  result = newObjRC1(typ, size)
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
 
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 6fbe94239..12eb97b1e 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -7,13 +7,13 @@
 #    distribution, for details about the copyright.
 #
 
-# A simple mark&sweep garbage collector for Nim. Define the 
+# A simple mark&sweep garbage collector for Nim. Define the
 # symbol ``gcUseBitvectors`` to generate a variant of this GC.
 {.push profiler:off.}
 
 const
   InitialThreshold = 4*1024*1024 # X MB because marking&sweeping is slow
-  withBitvectors = defined(gcUseBitvectors) 
+  withBitvectors = defined(gcUseBitvectors)
   # bitvectors are significantly faster for GC-bench, but slower for
   # bootstrapping and use more memory
   rcWhite = 0
@@ -29,21 +29,21 @@ type
   TWalkOp = enum
     waMarkGlobal,  # we need to mark conservatively for global marker procs
                    # as these may refer to a global var and not to a thread
-                   # local 
+                   # local
     waMarkPrecise  # fast precise marking
 
   TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
     # A ref type can have a finalizer that is called before the object's
     # storage is freed.
-  
+
   TGlobalMarkerProc = proc () {.nimcall, benign.}
 
   TGcStat = object
     collections: int         # number of performed full collections
     maxThreshold: int        # max threshold that has been set
     maxStackSize: int        # max stack size
-    freedObjects: int        # max entries in cycle table  
-  
+    freedObjects: int        # max entries in cycle table
+
   TGcHeap = object           # this contains the zero count and
                              # non-zero count table
     stackBottom: pointer
@@ -64,11 +64,11 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: TGcHeap) = 
+template acquire(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
 
-template release(gch: TGcHeap) = 
+template release(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     releaseSys(HeapLock)
 
@@ -134,7 +134,7 @@ proc prepareDealloc(cell: PCell) =
     (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
     dec(gch.recGcLock)
 
-proc nimGCref(p: pointer) {.compilerProc.} = 
+proc nimGCref(p: pointer) {.compilerProc.} =
   # we keep it from being collected by pretending it's not even allocated:
   when false:
     when withBitvectors: excl(gch.allocated, usrToCell(p))
@@ -261,6 +261,10 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
   zeroMem(result, size)
   when defined(memProfiler): nimProfile(size)
 
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  when defined(memProfiler): nimProfile(size)
+
 proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
   # `newObj` already uses locks, so no need for them here.
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
@@ -273,25 +277,25 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   result = rawNewObj(typ, size, gch)
   zeroMem(result, size)
   when defined(memProfiler): nimProfile(size)
-  
+
 proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
   result = newObj(typ, size)
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
   when defined(memProfiler): nimProfile(size)
-  
+
 proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   acquire(gch)
   collectCT(gch)
   var ol = usrToCell(old)
   sysAssert(ol.typ != nil, "growObj: 1")
   gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
-  
+
   var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
   var elemSize = 1
   if ol.typ.kind != tyString: elemSize = ol.typ.base.size
-  
+
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(TCell))
   zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
@@ -401,7 +405,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
     var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
     if objStart != nil:
       mark(gch, objStart)
-  
+
 # ----------------- stack management --------------------------------------
 #  inspired from Smart Eiffel
 
@@ -536,7 +540,7 @@ proc collectCTBody(gch: var TGcHeap) =
   markStackAndRegisters(gch)
   markGlobals(gch)
   sweep(gch)
-  
+
   inc(gch.stat.collections)
   when withBitvectors:
     deinit(gch.marked)
@@ -544,19 +548,19 @@ proc collectCTBody(gch: var TGcHeap) =
   gch.cycleThreshold = max(InitialThreshold, getOccupiedMem().mulThreshold)
   gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
   sysAssert(allocInv(gch.region), "collectCT: end")
-  
+
 proc collectCT(gch: var TGcHeap) =
   if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
     collectCTBody(gch)
 
 when not defined(useNimRtl):
-  proc GC_disable() = 
+  proc GC_disable() =
     when hasThreadSupport and hasSharedHeap:
       atomicInc(gch.recGcLock, 1)
     else:
       inc(gch.recGcLock)
   proc GC_enable() =
-    if gch.recGcLock > 0: 
+    if gch.recGcLock > 0:
       when hasThreadSupport and hasSharedHeap:
         atomicDec(gch.recGcLock, 1)
       else:
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index a1a0353ca..84e532049 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.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.
@@ -23,7 +23,7 @@ const
   leakDetector = false
   overwriteFree = false
   trackAllocationSource = leakDetector
-  
+
   cycleGC = true # (de)activate the cycle GC
   reallyDealloc = true # for debugging purposes this can be set to false
   reallyOsDealloc = true
@@ -71,13 +71,13 @@ when defined(boehmgc):
     const boehmLib = "libgc.dylib"
   else:
     const boehmLib = "/usr/lib/libgc.so.1"
-    
+
   proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
-  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} 
-  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} 
+  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
+  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
   proc boehmGCincremental {.
-    importc: "GC_enable_incremental", dynlib: boehmLib.} 
-  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}  
+    importc: "GC_enable_incremental", dynlib: boehmLib.}
+  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
   proc boehmAlloc(size: int): pointer {.
     importc: "GC_malloc", dynlib: boehmLib.}
   proc boehmAllocAtomic(size: int): pointer {.
@@ -85,7 +85,7 @@ when defined(boehmgc):
   proc boehmRealloc(p: pointer, size: int): pointer {.
     importc: "GC_realloc", dynlib: boehmLib.}
   proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
-  
+
   proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
     ## Return the number of bytes in the heap.  Excludes collector private
     ## data structures. Includes empty blocks and fragmentation loss.
@@ -108,7 +108,7 @@ when defined(boehmgc):
     zeroMem(result, size)
 
   when not defined(useNimRtl):
-    
+
     proc alloc(size: int): pointer =
       result = boehmAlloc(size)
       if result == nil: raiseOutOfMem()
@@ -119,7 +119,7 @@ when defined(boehmgc):
       result = boehmRealloc(p, newsize)
       if result == nil: raiseOutOfMem()
     proc dealloc(p: pointer) = boehmDealloc(p)
-    
+
     proc allocShared(size: int): pointer =
       result = boehmAlloc(size)
       if result == nil: raiseOutOfMem()
@@ -148,14 +148,14 @@ when defined(boehmgc):
     proc GC_enableMarkAndSweep() = discard
     proc GC_disableMarkAndSweep() = discard
     proc GC_getStatistics(): string = return ""
-    
+
     proc getOccupiedMem(): int = return boehmGetHeapSize()-boehmGetFreeBytes()
     proc getFreeMem(): int = return boehmGetFreeBytes()
     proc getTotalMem(): int = return boehmGetHeapSize()
 
     proc setStackBottom(theStackBottom: pointer) = discard
 
-  proc initGC() = 
+  proc initGC() =
     when defined(macosx): boehmGCinit()
 
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
@@ -171,7 +171,7 @@ when defined(boehmgc):
 
   proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
   proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
-  
+
   proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
@@ -181,20 +181,20 @@ when defined(boehmgc):
 
   type
     TMemRegion = object {.final, pure.}
-  
+
   proc alloc(r: var TMemRegion, size: int): pointer =
     result = boehmAlloc(size)
     if result == nil: raiseOutOfMem()
   proc alloc0(r: var TMemRegion, size: int): pointer =
     result = alloc(size)
     zeroMem(result, size)
-  proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)  
+  proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
   proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
   proc deallocOsPages() {.inline.} = discard
 
   include "system/cellsets"
 elif defined(nogc) and defined(useMalloc):
-  
+
   when not defined(useNimRtl):
     proc alloc(size: int): pointer =
       result = cmalloc(size)
@@ -206,7 +206,7 @@ elif defined(nogc) and defined(useMalloc):
       result = crealloc(p, newsize)
       if result == nil: raiseOutOfMem()
     proc dealloc(p: pointer) = cfree(p)
-    
+
     proc allocShared(size: int): pointer =
       result = cmalloc(size)
       if result == nil: raiseOutOfMem()
@@ -225,11 +225,11 @@ elif defined(nogc) and defined(useMalloc):
     proc GC_enableMarkAndSweep() = discard
     proc GC_disableMarkAndSweep() = discard
     proc GC_getStatistics(): string = return ""
-    
+
     proc getOccupiedMem(): int = discard
     proc getFreeMem(): int = discard
     proc getTotalMem(): int = discard
-    
+
     proc setStackBottom(theStackBottom: pointer) = discard
 
   proc initGC() = discard
@@ -240,13 +240,15 @@ elif defined(nogc) and defined(useMalloc):
     result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
     cast[PGenericSeq](result).len = len
     cast[PGenericSeq](result).reserved = len
+  proc newObjNoInit(typ: PNimType, size: int): pointer =
+    result = alloc(size)
 
   proc growObj(old: pointer, newsize: int): pointer =
     result = realloc(old, newsize)
 
   proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
   proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
-  
+
   proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
@@ -256,7 +258,7 @@ elif defined(nogc) and defined(useMalloc):
 
   type
     TMemRegion = object {.final, pure.}
-  
+
   proc alloc(r: var TMemRegion, size: int): pointer =
     result = alloc(size)
   proc alloc0(r: var TMemRegion, size: int): pointer =
@@ -272,9 +274,9 @@ elif defined(nogc):
   # object, because C does not support this operation... Even though every
   # possible implementation has to have a way to determine the object's size.
   # C just sucks.
-  when appType == "lib": 
+  when appType == "lib":
     {.warning: "nogc in a library context may not work".}
-  
+
   include "system/alloc"
 
   proc initGC() = discard
@@ -285,10 +287,14 @@ elif defined(nogc):
   proc GC_enableMarkAndSweep() = discard
   proc GC_disableMarkAndSweep() = discard
   proc GC_getStatistics(): string = return ""
-  
-  
+
+
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
     result = alloc0(size)
+
+  proc newObjNoInit(typ: PNimType, size: int): pointer =
+    result = alloc(size)
+
   proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
     result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
     cast[PGenericSeq](result).len = len
@@ -299,7 +305,7 @@ elif defined(nogc):
   proc setStackBottom(theStackBottom: pointer) = discard
   proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
   proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
-  
+
   proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
@@ -327,6 +333,6 @@ else:
     include "system/gc"
   else:
     include "system/gc"
-  
+
 {.pop.}
 
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 48adb895d..468af1713 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -154,7 +154,7 @@ proc readAll(file: File): TaintedString =
 proc readFile(filename: string): TaintedString =
   var f = open(filename)
   try:
-    result = readAllFile(f).TaintedString
+    result = readAll(f).TaintedString
   finally:
     close(f)
 
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index cfbc24f0c..5b4020c8c 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -30,18 +30,30 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
   if a == b: return true
   if a == nil or b == nil: return false
   return a.len == b.len and
-    c_memcmp(a.data, b.data, a.len * sizeof(char)) == 0'i32
+    c_memcmp(a.data, b.data, a.len) == 0'i32
 
 when declared(allocAtomic):
   template allocStr(size: expr): expr =
     cast[NimString](allocAtomic(size))
+
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](boehmAllocAtomic(size))
 else:
   template allocStr(size: expr): expr =
     cast[NimString](newObj(addr(strDesc), size))
 
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](newObjNoInit(addr(strDesc), size))
+
+proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
+  var s = space
+  if s < 7: s = 7
+  result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
+  result.reserved = s
+
 proc rawNewString(space: int): NimString {.compilerProc.} =
   var s = space
-  if s < 8: s = 7
+  if s < 7: s = 7
   result = allocStr(sizeof(TGenericSeq) + s + 1)
   result.reserved = s
 
@@ -53,10 +65,10 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
   var start = max(start, 0)
   var len = min(last, s.len-1) - start + 1
   if len > 0:
-    result = rawNewString(len)
+    result = rawNewStringNoInit(len)
     result.len = len
-    c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
-    #result.data[len] = '\0'
+    c_memcpy(result.data, addr(s.data[start]), len)
+    result.data[len] = '\0'
   else:
     result = rawNewString(len)
 
@@ -64,10 +76,9 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
   result = copyStrLast(s, start, s.len-1)
 
 proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
-  result = rawNewString(len)
+  result = rawNewStringNoInit(len)
   result.len = len
-  c_memcpy(result.data, str, (len+1) * sizeof(char))
-  #result.data[len] = '\0' # readline relies on this!
+  c_memcpy(result.data, str, len + 1)
 
 proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
   result = toNimStr(str, c_strlen(str))
@@ -77,23 +88,24 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
     if (src.reserved and seqShallowFlag) != 0:
       result = src
     else:
-      result = rawNewString(src.space)
+      result = rawNewStringNoInit(src.len)
       result.len = src.len
-      c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
+      c_memcpy(result.data, src.data, src.len + 1)
 
 proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
   if src != nil:
-    var s = src.space
-    if s < 8: s = 7
     when declared(newObjRC1):
+      var s = src.len
+      if s < 7: s = 7
       result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
                                s+1))
+      result.reserved = s
     else:
-      result = allocStr(sizeof(TGenericSeq) + s + 1)
-    result.reserved = s
+      result = rawNewStringNoInit(src.len)
     result.len = src.len
     c_memcpy(result.data, src.data, src.len + 1)
 
+
 proc hashString(s: string): int {.compilerproc.} =
   # the compiler needs exactly the same hash function!
   # this used to be used for efficient generation of string case statements
@@ -113,7 +125,7 @@ proc addChar(s: NimString, c: char): NimString =
   if result.len >= result.space:
     result.reserved = resize(result.space)
     result = cast[NimString](growObj(result,
-      sizeof(TGenericSeq) + (result.reserved+1) * sizeof(char)))
+      sizeof(TGenericSeq) + result.reserved + 1))
   result.data[result.len] = c
   result.data[result.len+1] = '\0'
   inc(result.len)
@@ -157,7 +169,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
     result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
     result.reserved = sp
     #result = rawNewString(sp)
-    #copyMem(result, dest, dest.len * sizeof(char) + sizeof(TGenericSeq))
+    #copyMem(result, dest, dest.len + sizeof(TGenericSeq))
     # DO NOT UPDATE LEN YET: dest.len = newLen
 
 proc appendString(dest, src: NimString) {.compilerproc, inline.} =
@@ -203,7 +215,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
                                GenericSeqSize))
   elif newLen < result.len:
     # we need to decref here, otherwise the GC leaks!
-    when not defined(boehmGC) and not defined(nogc) and 
+    when not defined(boehmGC) and not defined(nogc) and
          not defined(gcMarkAndSweep):
       when compileOption("gc", "v2"):
         for i in newLen..result.len-1:
@@ -220,7 +232,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
           forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
                             GenericSeqSize +% (i*%elemSize)),
                             extGetCellType(result).base, waZctDecRef)
-      
+
     # XXX: zeroing out the memory can still result in crashes if a wiped-out
     # cell is aliased by another pointer (ie proc parameter or a let variable).
     # This is a tought problem, because even if we don't zeroMem here, in the
@@ -258,7 +270,7 @@ proc nimFloatToStr(f: float): string {.compilerproc.} =
     if buf[i] == ',':
       buf[i] = '.'
       hasDot = true
-    elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: 
+    elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
       hasDot = true
   if not hasDot:
     buf[n] = '.'
@@ -309,7 +321,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
   template addToBuf(c) =
     if ti < t.high:
       t[ti] = c; inc(ti)
-  
+
   # Sign?
   if s[i] == '+' or s[i] == '-':
     if s[i] == '-':
@@ -330,7 +342,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
   if s[i] == 'I' or s[i] == 'i':
     if s[i+1] == 'N' or s[i+1] == 'n':
       if s[i+2] == 'F' or s[i+2] == 'f':
-        if s[i+3] notin IdentChars: 
+        if s[i+3] notin IdentChars:
           number = Inf*sign
           return i+3 - start
     return 0
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index 29fe3a921..03729dbab 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -50,7 +50,7 @@ when useWinVersion:
   from winlean import SocketHandle
 else:
   const
-    versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
+    versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
   when defined(macosx):
     const
       DLLSSLName = "libssl" & versions & ".dylib"
@@ -141,6 +141,14 @@ const
   SSL_CTRL_GET_MAX_CERT_LIST* = 50
   SSL_CTRL_SET_MAX_CERT_LIST* = 51 #* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
                                    # * when just a single record has been written): *
+  SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53
+  SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54
+  SSL_CTRL_SET_TLSEXT_HOSTNAME = 55
+  TLSEXT_NAMETYPE_host_name* = 0
+  SSL_TLSEXT_ERR_OK* = 0
+  SSL_TLSEXT_ERR_ALERT_WARNING* = 1
+  SSL_TLSEXT_ERR_ALERT_FATAL* = 2
+  SSL_TLSEXT_ERR_NOACK* = 3
   SSL_MODE_ENABLE_PARTIAL_WRITE* = 1 #* Make it possible to retry SSL_write() with changed buffer location
                                      # * (buffer contents must stay the same!); this is not the default to avoid
                                      # * the misconception that non-blocking SSL_write() behaves like
@@ -290,15 +298,47 @@ when not useWinVersion:
     if p != nil: dealloc(p)
 
 proc CRYPTO_malloc_init*() =
-  when not useWinVersion:
+  when not useWinVersion and not defined(macosx):
     CRYPTO_set_mem_functions(allocWrapper, reallocWrapper, deallocWrapper)
 
 proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{.
   cdecl, dynlib: DLLSSLName, importc.}
 
+proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cInt, fp: PFunction): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
 proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int =
   result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
 
+proc SSL_ctrl*(ssl: SslPtr, cmd: cInt, larg: int, parg: pointer): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSL_set_tlsext_host_name*(ssl: SslPtr, name: cstring): int =
+  result = SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name)
+  ## Set the SNI server name extension to be used in a client hello.
+  ## Returns 1 if SNI was set, 0 if current SSL configuration doesn't support SNI.
+
+
+proc SSL_get_servername*(ssl: SslPtr, typ: cInt = TLSEXT_NAMETYPE_host_name): cstring {.cdecl, dynlib: DLLSSLName, importc.}
+  ## Retrieve the server name requested in the client hello. This can be used
+  ## in the callback set in `SSL_CTX_set_tlsext_servername_callback` to
+  ## implement virtual hosting. May return `nil`.
+
+proc SSL_CTX_set_tlsext_servername_callback*(ctx: SslCtx, cb: proc(ssl: SslPtr, cb_id: int, arg: pointer): int {.cdecl.}): int =
+  ## Set the callback to be used on listening SSL connections when the client hello is received.
+  ##
+  ## The callback should return one of:
+  ## * SSL_TLSEXT_ERR_OK
+  ## * SSL_TLSEXT_ERR_ALERT_WARNING
+  ## * SSL_TLSEXT_ERR_ALERT_FATAL
+  ## * SSL_TLSEXT_ERR_NOACK
+  result = SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cast[PFunction](cb))
+
+proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int =
+  ## Set the pointer to be used in the callback registered to ``SSL_CTX_set_tlsext_servername_callback``.
+  result = SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg)
+
+
 proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".}
 proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
 proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
@@ -341,8 +381,6 @@ else:
       dynlib: DLLSSLName, importc.}
 
   proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
-  proc SslCtrl*(ssl: PSSL, cmd: cInt, larg: int, parg: Pointer): int{.cdecl, 
-      dynlib: DLLSSLName, importc.}
   proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
       cdecl, dynlib: DLLSSLName, importc.}
 
diff --git a/readme.md b/readme.md
index e716c0d0d..740296f4f 100644
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,5 @@
 # Nim Compiler
-This repo contains the Nim compiler, Nim's stdlib, tools and 
+This repo contains the Nim compiler, Nim's stdlib, tools and
 documentation.
 
 ## Compiling
@@ -8,17 +8,13 @@ the Nim compiler itself is written in the Nim programming language
 the C source of an older version of the compiler are needed to bootstrap the
 latest version. The C sources are available in a separate repo [here](http://github.com/nim-lang/csources).
 
-Pre-compiled snapshots of the compiler are also available on
-[Nimbuild](http://build.nim-lang.org/). Your platform however may not 
-currently be built for.
-
-The compiler currently supports the following platform and architecture 
+The compiler currently supports the following platform and architecture
 combinations:
-  
+
   * Windows (Windows XP or greater) - x86 and x86_64
   * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l
   * Mac OS X 10.04 or higher - x86, x86_64 and ppc64
-  
+
 In reality a lot more are supported, however they are not tested regularly.
 
 To build from source you will need:
@@ -54,9 +50,9 @@ questions, and you can also get help in the IRC channel on
 tag](http://stackoverflow.com/questions/tagged/nim).
 
 ## License
-The compiler and the standard library are licensed under the MIT license, 
-except for some modules where the documentation suggests otherwise. This means 
-that you can use any license for your own programs developed with Nim, 
+The compiler and the standard library are licensed under the MIT license,
+except for some modules where the documentation suggests otherwise. This means
+that you can use any license for your own programs developed with Nim,
 allowing you to create commercial applications.
 
 Read copying.txt for more details.
diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim
index 16769f529..729cdcac7 100644
--- a/tests/assert/tfailedassert.nim
+++ b/tests/assert/tfailedassert.nim
@@ -3,7 +3,7 @@ discard """
 WARNING: false first assertion from bar
 ERROR: false second assertion from bar
 -1
-tfailedassert.nim:27 false assertion from foo
+tests/assert/tfailedassert.nim:27 false assertion from foo
 '''
 """
 
diff --git a/tests/ccgbugs/tstringslice.nim b/tests/ccgbugs/tstringslice.nim
new file mode 100644
index 000000000..00c1adf74
--- /dev/null
+++ b/tests/ccgbugs/tstringslice.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''1
+1234
+1234
+2
+234
+234
+3
+34
+34
+4
+4
+4'''
+"""
+
+# bug #794
+type TRange = range[0..3]
+
+const str = "123456789"
+
+for i in TRange.low .. TRange.high:
+  echo str[i]                          #This works fine
+  echo str[int(i) .. int(TRange.high)] #So does this
+  echo str[i .. TRange.high]           #The compiler complains about this
diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim
new file mode 100644
index 000000000..960e2aae9
--- /dev/null
+++ b/tests/ccgbugs/tuple_canon.nim
@@ -0,0 +1,80 @@
+# bug #2250
+
+import
+    math, strutils
+
+type
+    Meters = float
+    Point2[T] = tuple[x, y: T]
+
+    HexState* = enum
+        hsOn, hsOff
+
+    Index = uint16
+
+    HexGrid* = object
+        w, h: int                       ## Width and height of the hex grid.
+        radius: Meters                  ## Radius of circle that circumscribes a hexagon.
+        grid: seq[HexState]             ## Information on what hexes are drawn.
+
+    HexVtxIndex = enum
+        hiA, hiB, hiC, hiD, hiE, hiF
+
+    HexCoord* = Point2[int]
+
+const
+    HexDY = sqrt(1.0 - (0.5 * 0.5))     # dy from center to midpoint of 1-2
+    HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5)
+
+
+let
+    hexOffsets : array[HexVtxIndex, Point2[float]] = [
+                  (-1.0, 0.0),
+                  (-HexDX, -HexDY),
+                  (HexDX, -HexDY),
+                  (1.0, 0.0),
+                  (HexDX, HexDY),
+                  (-HexDX, HexDY)]
+
+    evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,-1), hiA),
+            ((1,0), hiB),
+            ((1,0), hiA),
+            ((0,1), hiB)]
+
+    oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,0), hiA),
+            ((1,1), hiB),
+            ((1,1), hiA),
+            ((0,1), hiB)]
+
+template odd*(i: int) : expr =
+    (i and 1) != 0
+
+proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index =
+    #NOTE: this variation compiles
+    #var offset : type(evenSharingOffsets[i])
+    #
+    #if odd(col):
+    #    offset = oddSharingOffsets[i]
+    #else:
+    #    offset = evenSharingOffsets[i]
+
+    let
+        #NOTE: this line generates the bad code
+        offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i])
+        x = col + 1 + offset.hc.x
+        y = row + 1 + offset.hc.y
+
+    result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx))
+
+proc go() =
+    var hg : HexGrid
+
+    echo "vidx ", $vidx(hg, 1, 2, hiC)
+
+go()
diff --git a/tests/deprecated/tdeprecated.nim b/tests/deprecated/tdeprecated.nim
index ed3d2733a..955a7f6ad 100644
--- a/tests/deprecated/tdeprecated.nim
+++ b/tests/deprecated/tdeprecated.nim
@@ -1,9 +1,9 @@
 discard """
-  nimout: "'a' is deprecated [Deprecated]"
+  nimout: "a is deprecated [Deprecated]"
 """
 
 var
   a {.deprecated.}: array[0..11, int]
-  
+
 a[8] = 1
 
diff --git a/tests/enum/tenumitems.nim b/tests/enum/tenumitems.nim
index b92cff6bf..04737fa9e 100644
--- a/tests/enum/tenumitems.nim
+++ b/tests/enum/tenumitems.nim
@@ -1,6 +1,6 @@
 discard """
   line: 7
-  errormsg: "expression 'items' cannot be called"
+  errormsg: "undeclared identifier: 'items'"
 """
 
 type a = enum b,c,d
diff --git a/tests/exprs/tresultwarning.nim b/tests/exprs/tresultwarning.nim
new file mode 100644
index 000000000..32934408e
--- /dev/null
+++ b/tests/exprs/tresultwarning.nim
@@ -0,0 +1,6 @@
+discard """
+  nimout: "Special variable 'result' is shadowed. [ResultShadowed]"
+"""
+
+proc test(): string =
+  var result = "foo"
diff --git a/tests/generics/tunique_type.nim b/tests/generics/tunique_type.nim
index f8901d3bd..29367181c 100644
--- a/tests/generics/tunique_type.nim
+++ b/tests/generics/tunique_type.nim
@@ -1,5 +1,11 @@
 # Bug #2022
 
+discard """
+  output: '''@[97, 45]
+@[true, false]
+@[false, false]'''
+"""
+
 ## The goal of this snippet is to provide and test a construct for general-
 ## purpose, random-access mapping. I use an AST-manipulation-based approach
 ## because it's more efficient than using procedure pointers and less
@@ -31,6 +37,7 @@ type Mapped[Input; predicate: static[string]] = object
   input: Input
 
 macro map(input, predicate: expr): expr =
+  let predicate = callsite()[2]
   newNimNode(nnkObjConstr).add(
     newNimNode(nnkBracketExpr).add(
       ident"Mapped",
diff --git a/tests/init/tuninit2.nim b/tests/init/tuninit2.nim
new file mode 100644
index 000000000..950895c02
--- /dev/null
+++ b/tests/init/tuninit2.nim
@@ -0,0 +1,54 @@
+# bug #2316
+
+type
+    EventType = enum
+      QuitEvent = 5
+    AppMain* = ref object of RootObj
+        width: int
+        height: int
+        title: string
+        running: bool
+        event_type: EventType
+    App* = ref object of AppMain
+        draw_proc: proc(app: AppMain): void {.closure.}
+        events_proc: proc(app: AppMain): void {.closure.}
+        update_proc: proc(app: AppMain, dt: float): void {.closure.}
+        load_proc: proc(app: AppMain): void {.closure.}
+
+
+proc initApp*(t: string, w, h: int): App =
+    App(width: w, height: h, title: t, event_type: EventType.QuitEvent)
+
+
+method getTitle*(self: AppMain): string = self.title
+method getWidth*(self: AppMain): int = self.width
+method getHeight*(self: AppMain): int = self.height
+
+
+method draw*(self: App, draw: proc(app: AppMain)): void =
+    self.draw_proc = draw
+
+method load*(self: App, load: proc(a: AppMain)): void =
+    self.load_proc = load
+
+method events*(self: App, events: proc(app: AppMain)): void =
+    self.events_proc = events
+
+method update*(self: App, update: proc(app: AppMain, delta: float)): void =
+    self.update_proc = update
+
+method run*(self: App): void = discard
+
+var mygame = initApp("Example", 800, 600)
+
+mygame.load(proc(app: AppMain): void =
+    echo app.getTitle()
+    echo app.getWidth()
+    echo app.getHeight()
+)
+
+mygame.events(proc(app: AppMain): void =
+    discard
+)
+
+mygame.run()
diff --git a/tests/manyloc/argument_parser/ex_wget.nim b/tests/manyloc/argument_parser/ex_wget.nim
index d36947b34..625a6f595 100644
--- a/tests/manyloc/argument_parser/ex_wget.nim
+++ b/tests/manyloc/argument_parser/ex_wget.nim
@@ -8,8 +8,8 @@ const
   PARAM_BACKGROUND = @["-b", "--background"]
   PARAM_OUTPUT = @["-o", "--output"]
   PARAM_NO_CLOBBER = @["-nc", "--no-clobber"]
-  PARAM_PROGRESS = "--progress"
-  PARAM_NO_PROXY = "--no-proxy"
+  PARAM_PROGRESS = @["--progress"]
+  PARAM_NO_PROXY = @["--no-proxy"]
 
 
 template P(tnames: varargs[string], thelp: string, ttype = PK_EMPTY,
@@ -77,8 +77,8 @@ proc process_commandline(): Tcommandline_results =
       quit()
     echo "Will download to $1" % [result.options[PARAM_OUTPUT[0]].str_val]
 
-  if result.options.hasKey(PARAM_PROGRESS):
-    echo "Will use progress type $1" % [result.options[PARAM_PROGRESS].str_val]
+  if result.options.hasKey(PARAM_PROGRESS[0]):
+    echo "Will use progress type $1" % [result.options[PARAM_PROGRESS[0]].str_val]
 
 
 when isMainModule:
diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim
new file mode 100644
index 000000000..68a61373f
--- /dev/null
+++ b/tests/misc/parsecomb.nim
@@ -0,0 +1,105 @@
+type Input[T] = object
+  toks: seq[T]
+  index: int
+
+type
+  ResultKind* = enum rkSuccess, rkFailure
+  Result*[T, O] = object
+    case kind*: ResultKind
+    of rkSuccess:
+      output*: O
+      input: Input[T]
+    of rkFailure:
+      nil
+
+type
+  Parser*[T, O] = distinct proc (input: Input[T]): Result[T, O]
+
+proc unit*[T, O](v: O): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    Result[T, O](kind: rkSuccess, output: v, input: inp))
+
+proc fail*[T, O](): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    Result(kind: rkFailure))
+
+method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] =
+  # hmmm ..
+  type tmp = proc (input: Input[T]): Result[T, O]
+  # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C.
+  tmp(self)(inp)
+
+method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] =
+  self.runInput(Input[T](toks: toks, index: 0))
+
+method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] =
+  Parser(proc (inp: Input[T]): Result[T, O2] =
+    let r = self.runInput(inp)
+    case r.kind:
+    of rkSuccess:
+      nextp(r.output).runInput(r.input)
+    of rkFailure:
+      Result[T, O2](kind: rkFailure))
+
+method skip[T](self: Input[T], n: int): Input[T] =
+  Input[T](toks: self.toks, index: self.index + n)
+
+proc pskip*[T](n: int): Parser[T, tuple[]] =
+  Parser(proc (inp: Input[T]): Result[T, tuple[]] =
+    if inp.index + n <= inp.toks.len:
+      Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n))
+    else:
+      Result[T, tuple[]](kind: rkFailure))
+
+proc tok*[T](t: T): Parser[T, T] =
+  Parser(proc (inp: Input[T]): Result[T, T] =
+    if inp.index < inp.toks.len and inp.toks[inp.index] == t:
+      pskip[T](1).then(unit[T, T](t)).runInput(inp)
+    else:
+      Result[T, T](kind: rkFailure))
+
+proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    let r = first.runInput(inp)
+    case r.kind
+    of rkSuccess:
+      r
+    else:
+      second.runInput(inp))
+
+# end of primitives (definitions involving Parser(..))
+
+method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    unit[T, O2](p(v)))
+
+method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    next)
+
+proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] =
+  first.chain(proc (v1: O1): Parser[T, (O1, O2)] =
+    second.map(proc (v2: O2): (O1, O2) =
+      (v1, v2)))
+
+proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  var nothing = unit[T, seq[O]](@[])
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs)) + nothing
+
+proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs))
+
+proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] =
+  (inner*repeat0(after)).map(proc(ias: (O, seq[A])): O =
+    var (i, asx) = ias
+    for a in asx:
+      i = fold(i, a)
+    i)
+
+proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] =
+  unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] =
+    inner())
diff --git a/tests/misc/tissue710.nim b/tests/misc/tissue710.nim
index 9e8735eb3..ecfdf653e 100644
--- a/tests/misc/tissue710.nim
+++ b/tests/misc/tissue710.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tissue710.nim"
   line: 8
-  errorMsg: "expression '||' cannot be called"
+  errorMsg: "undeclared identifier: '||'"
 """
 var sum = 0
 for x in 3..1000:
diff --git a/tests/misc/tnoop.nim b/tests/misc/tnoop.nim
index c79403e11..10c2eb2ec 100644
--- a/tests/misc/tnoop.nim
+++ b/tests/misc/tnoop.nim
@@ -1,12 +1,11 @@
 discard """
   file: "tnoop.nim"
   line: 11
-  errormsg: "expression \'a()\' cannot be called"
+  errormsg: "undeclared identifier: 'a'"
 """
-# Tests the new check in the semantic pass
+
 
 var
   a: int
 
-a()  #ERROR_MSG expression 'a()' cannot be called
-
+a()
diff --git a/tests/misc/tparsecombnum.nim b/tests/misc/tparsecombnum.nim
new file mode 100644
index 000000000..6fe539813
--- /dev/null
+++ b/tests/misc/tparsecombnum.nim
@@ -0,0 +1,55 @@
+import parsecomb
+
+discard """
+  output: "-289096"
+"""
+
+type Num = int
+
+# forward stuff
+var exp3: Parser[string, Num]
+var exp = lazy(proc(): Parser[string, Num] = exp3)
+
+var digit = (proc(): Parser[string, Num] =
+  result = tok("0").then(unit[string, Num](Num(0)))
+  for n in 1..9:
+    result = result + tok($n).then(unit[string, Num](Num(n)))
+)()
+
+var num = repeat1(digit).map(proc(ds: seq[Num]): Num =
+  result = 0
+  for d in ds:
+    result = result*10 + d)
+
+type Op = proc(a, b: Num): Num
+
+var plusOp = tok("+").then(unit[string, Op](proc(a, b: Num): Num = a + b))
+var minusOp = tok("-").then(unit[string, Op](proc(a, b: Num): Num = a - b))
+var timesOp = tok("*").then(unit[string, Op](proc(a, b: Num): Num = a*b))
+var divideOp = tok("/").then(unit[string, Op](proc(a, b: Num): Num = a div b))
+
+var paren = (tok("(") * exp * tok(")")).map(proc(ler: ((string, Num), string)): Num =
+  var (le, r) = ler
+  var (l, e) = le
+  e)
+
+proc foldOp(a: Num, ob: (Op, Num)): Num =
+  var (o, b) = ob
+  o(a, b)
+
+var exp0 = paren + num
+var exp1 = exp0.leftRec((timesOp + divideOp)*exp0, foldOp)
+var exp2 = exp1.leftRec((plusOp + minusOp)*exp1, foldOp)
+exp3 = exp2
+
+proc strsplit(s: string): seq[string] =
+  result = @[]
+  for i in 0 .. s.len - 1:
+    result.add($s[i])
+
+var r = exp.run("523-(1243+411/744*1642/1323)*233".strsplit)
+case r.kind:
+of rkSuccess:
+  echo r.output
+of rkFailure:
+  echo "failed"
diff --git a/tests/modules/trecinca.nim b/tests/modules/trecinca.nim
index bedea8d7e..14a91ba5c 100644
--- a/tests/modules/trecinca.nim
+++ b/tests/modules/trecinca.nim
@@ -1,11 +1,11 @@
 discard """
   file: "tests/reject/trecincb.nim"
   line: 9
-  errormsg: "recursive dependency: 'trecincb.nim'"
+  errormsg: "recursive dependency: 'tests/modules/trecincb.nim'"
 """
 # Test recursive includes
 
-include trecincb #ERROR_MSG recursive dependency: 'tests/trecincb.nim'
+include trecincb
 
 echo "trecina"
 
diff --git a/tests/modules/trecincb.nim b/tests/modules/trecincb.nim
index eb0f72db0..299a242e1 100644
--- a/tests/modules/trecincb.nim
+++ b/tests/modules/trecincb.nim
@@ -1,12 +1,12 @@
 discard """
   file: "trecincb.nim"
   line: 9
-  errormsg: "recursive dependency: 'trecincb.nim'"
+  errormsg: "recursive dependency: 'tests/modules/trecincb.nim'"
 """
 # Test recursive includes
 
 
-include trecincb #ERROR_MSG recursive dependency: 'tests/trecincb.nim'
+include trecincb
 
 echo "trecinb"
 
diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim
index 3bd785728..226fe98f7 100644
--- a/tests/objects/tobjconstr.nim
+++ b/tests/objects/tobjconstr.nim
@@ -1,14 +1,14 @@
 discard """
-  output: '''(k: kindA, a: (x: abc, z: [1, 1, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 2, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 3, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 4, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 5, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 6, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 7, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 8, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 9, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 10, 3]), empty: ())'''
+  output: '''(k: kindA, a: (x: abc, z: [1, 1, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 2, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 3, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 4, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 5, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 6, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 7, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 8, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 9, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 10, 3]), method: ())'''
 """
 
 type
@@ -20,9 +20,9 @@ type
   TDummy = ref object
     case k: TKind
     of kindXY: x, y: int
-    of kindA: 
+    of kindA:
       a: TArg
-      empty: TEmpty
+      `method`: TEmpty # bug #1791
 
 proc `$`[T](s: seq[T]): string =
   # XXX why is that not in the stdlib?
@@ -34,7 +34,7 @@ proc `$`[T](s: seq[T]): string =
 
 proc main() =
   for i in 1..10:
-    let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), empty: TEmpty())
+    let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), `method`: TEmpty())
     echo d[]
 
 main()
diff --git a/tests/overload/toverprc.nim b/tests/overload/toverprc.nim
index 22b64ed48..78831f744 100644
--- a/tests/overload/toverprc.nim
+++ b/tests/overload/toverprc.nim
@@ -1,14 +1,19 @@
+discard """
+  output: '''another number: 123
+yay'''
+"""
+
 # Test overloading of procs when used as function pointers
 
 import strutils
 
-proc parseInt(x: float): int {.noSideEffect.} = nil
-proc parseInt(x: bool): int {.noSideEffect.} = nil
-proc parseInt(x: float32): int {.noSideEffect.} = nil
-proc parseInt(x: int8): int {.noSideEffect.} = nil
-proc parseInt(x: TFile): int {.noSideEffect.} = nil
-proc parseInt(x: char): int {.noSideEffect.} = nil
-proc parseInt(x: int16): int {.noSideEffect.} = nil
+proc parseInt(x: float): int {.noSideEffect.} = discard
+proc parseInt(x: bool): int {.noSideEffect.} = discard
+proc parseInt(x: float32): int {.noSideEffect.} = discard
+proc parseInt(x: int8): int {.noSideEffect.} = discard
+proc parseInt(x: TFile): int {.noSideEffect.} = discard
+proc parseInt(x: char): int {.noSideEffect.} = discard
+proc parseInt(x: int16): int {.noSideEffect.} = discard
 
 proc parseInt[T](x: T): int = echo x; 34
 
@@ -19,12 +24,13 @@ var
   q = TParseInt(parseInt)
   p: TParseInt = parseInt
 
-proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int = 
+proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int =
   result = x("123")
-  
-echo "Give a list of numbers (separated by spaces): "
-var x = stdin.readline.split.map(parseInt).max
-echo x, " is the maximum!"
+
+if false:
+  echo "Give a list of numbers (separated by spaces): "
+  var x = stdin.readline.split.map(parseInt).max
+  echo x, " is the maximum!"
 echo "another number: ", takeParseInt(parseInt)
 
 
diff --git a/tests/overload/tprefer_specialized_generic.nim b/tests/overload/tprefer_specialized_generic.nim
new file mode 100644
index 000000000..2b41502d1
--- /dev/null
+++ b/tests/overload/tprefer_specialized_generic.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''ref ref T ptr S'''
+"""
+
+proc foo[T](x: T) =
+  echo "only T"
+
+proc foo[T](x: ref T) =
+  echo "ref T"
+
+proc foo[T, S](x: ref ref T; y: ptr S) =
+  echo "ref ref T ptr S"
+
+proc foo[T, S](x: ref T; y: ptr S) =
+  echo "ref T ptr S"
+
+proc foo[T](x: ref T; default = 0) =
+  echo "ref T; default"
+
+var x: ref ref int
+var y: ptr ptr int
+foo(x, y)
diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim
index 2700bed5e..9787af06b 100644
--- a/tests/overload/tprefer_tygenericinst.nim
+++ b/tests/overload/tprefer_tygenericinst.nim
@@ -1,17 +1,42 @@
 discard """
-  output: "Version 2 was called."
-  disabled: true
+  output: '''Version 2 was called.
+This has the highest precedence.
+This has the second-highest precedence.
+This has the lowest precedence.'''
 """
 
 # bug #2220
+when true:
+  type A[T] = object
+  type B = A[int]
 
-type A[T] = object
-type B = A[int]
+  proc q[X](x: X) =
+    echo "Version 1 was called."
 
-proc p[X](x: X) =
-  echo "Version 1 was called."
+  proc q(x: B) =
+    echo "Version 2 was called."
 
-proc p(x: B) =
-  echo "Version 2 was called."
+  q(B()) # This call reported as ambiguous.
 
-p(B()) # This call reported as ambiguous.
+# bug #2219
+template testPred(a: expr) =
+  block:
+    type A = object of RootObj
+    type B = object of A
+    type SomeA = A|A # A hack to make "A" a typeclass.
+
+    when a >= 3:
+      proc p[X](x: X) =
+        echo "This has the highest precedence."
+    when a >= 2:
+      proc p[X: A](x: X) =
+        echo "This has the second-highest precedence."
+    when a >= 1:
+      proc p[X: SomeA](x: X) =
+        echo "This has the lowest precedence."
+
+    p(B())
+
+testPred(3)
+testPred(2)
+testPred(1)
diff --git a/tests/overload/tsymtabchange_during_or.nim b/tests/overload/tsymtabchange_during_or.nim
new file mode 100644
index 000000000..b5551bcc7
--- /dev/null
+++ b/tests/overload/tsymtabchange_during_or.nim
@@ -0,0 +1,24 @@
+
+# bug #2229
+
+type Type1 = object
+        id: int
+
+type Type2 = object
+    id: int
+
+proc init(self: var Type1, a: int, b: ref Type2) =
+    echo "1"
+
+proc init(self: var Type2, a: int) =
+    echo """
+        Works when this proc commented out
+        Otherwise error:
+        test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2)
+    """
+
+var a: Type1
+init(a, 1, (
+    var b = new(Type2);
+    b
+))
diff --git a/tests/overload/tsystemcmp.nim b/tests/overload/tsystemcmp.nim
index 54dff0c46..9bfca35d7 100644
--- a/tests/overload/tsystemcmp.nim
+++ b/tests/overload/tsystemcmp.nim
@@ -7,3 +7,12 @@ import algorithm
 # bug #1657
 var modules = @["hi", "ho", "ha", "huu"]
 sort(modules, system.cmp)
+
+type
+  MyType = object
+    x: string
+
+proc cmp(a, b: MyType): int = cmp(a.x, b.x)
+
+var modulesB = @[MyType(x: "ho"), MyType(x: "ha")]
+sort(modulesB, cmp)
diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim
index d7e4f7716..dffe5339b 100644
--- a/tests/parallel/tconvexhull.nim
+++ b/tests/parallel/tconvexhull.nim
@@ -6,7 +6,7 @@ true
 true
 true'''
 
-ccodeCheck: "!'deepcopy('"
+ccodeCheck: "\\i ! @'deepCopy(' .*"
 """
 
 # parallel convex hull for Nim bigbreak
diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim
new file mode 100644
index 000000000..53481e4df
--- /dev/null
+++ b/tests/parallel/tmissing_deepcopy.nim
@@ -0,0 +1,40 @@
+discard """
+  ccodeCheck: "\\i @'deepCopy(' .*"
+"""
+
+# bug #2286
+
+import threadPool
+
+type
+  Person = ref object
+    name: string
+    friend: Person
+
+var
+  people: seq[Person] = @[]
+
+proc newPerson(name:string): Person =
+  result.new()
+  result.name = name
+
+proc greet(p:Person) =
+  p.friend.name &= "-MUT" # this line crashes the program
+  echo "Person {",
+    " name:", p.name, "(", cast[int](addr p.name),"),",
+    " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }"
+
+proc setup =
+  for i in 0 .. <20:
+    people.add newPerson("Person" & $(i + 1))
+  for i in 0 .. <20:
+    people[i].friend = people[19-i]
+
+proc update =
+  parallel:
+    for i in 0 .. people.high:
+      spawn people[i].greet()
+
+when isMainModule:
+  setup()
+  update()
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
new file mode 100644
index 000000000..9874d3299
--- /dev/null
+++ b/tests/parallel/tsimple_array_checks.nim
@@ -0,0 +1,41 @@
+# bug #2287
+
+import threadPool
+
+# If `nums` is an array instead of seq,
+# NONE of the iteration ways below work (including high / len-1)
+let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+proc log(n:int) =
+  echo n
+
+proc main =
+  parallel:
+    for n in nums: # Error: cannot prove: i <= len(nums) + -1
+      spawn log(n)
+    #for i in 0 .. <nums.len: # Error: cannot prove: i <= len(nums) + -1
+    #for i in 0 .. nums.len-1: # WORKS!
+    #for i in 0 .. <nums.len: # WORKS!
+    #  spawn log(nums[i])
+
+# Array needs explicit size to work, probably related to issue #2287
+#const a: array[0..5, int] = [1,2,3,4,5,6]
+
+#const a = [1,2,3,4,5,6] # Doesn't work
+const a = @[1,2,3,4,5,6] # Doesn't work
+proc f(n: int) = echo "Hello ", n
+
+proc maino =
+  parallel:
+    # while loop doesn't work:
+    var i = 0
+    while i < a.high:
+      #for i in countup(0, a.high-1, 2):
+      spawn f(a[i])
+      spawn f(a[i+1])
+      i += 2
+
+maino() # Doesn't work outside a proc
+
+when isMainModule:
+  main()
diff --git a/tests/stdlib/tcount.nim b/tests/stdlib/tcount.nim
new file mode 100644
index 000000000..ce1d14b6c
--- /dev/null
+++ b/tests/stdlib/tcount.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''1
+2
+3
+4
+5
+done'''
+"""
+
+# bug #1845, #2224
+
+var arr = [3,2,1,5,4]
+
+# bubble sort
+for i in low(arr)..high(arr):
+  for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeError]
+    if arr[i] > arr[j]:
+      let tmp = arr[i]
+      arr[i] = arr[j]
+      arr[j] = tmp
+
+for i in low(arr)..high(arr):
+  echo arr[i]
+
+# check this terminates:
+for x in countdown('\255', '\0'):
+  discard
+
+echo "done"
diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim
index c8e496cc1..8a0538a5f 100644
--- a/tests/stdlib/tgetfileinfo.nim
+++ b/tests/stdlib/tgetfileinfo.nim
@@ -65,13 +65,13 @@ proc testGetFileInfo =
     try:
       discard getFileInfo(testFile)
       #echo("Handle : Valid File : Success")
-    except EIO:
+    except IOError:
       echo("Handle : Valid File : Failure")
 
     try:
       discard getFileInfo(testHandle)
       #echo("Handle : Valid File : Success")
-    except EIO:
+    except IOError:
       echo("Handle : Valid File : Failure")
 
   # Case 6 and 8
@@ -82,14 +82,14 @@ proc testGetFileInfo =
     try:
       discard getFileInfo(testFile)
       echo("Handle : Invalid File : Failure")
-    except EIO, EOS:
+    except IOError, OSError:
       discard
       #echo("Handle : Invalid File : Success")
 
     try:
       discard getFileInfo(testHandle)
       echo("Handle : Invalid File : Failure")
-    except EIO, EOS:
+    except IOError, OSError:
       discard
       #echo("Handle : Invalid File : Success")
 
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
new file mode 100644
index 000000000..e8ada05e7
--- /dev/null
+++ b/tests/stdlib/tnet.nim
@@ -0,0 +1,47 @@
+import net
+import unittest
+
+suite "isIpAddress tests":
+  test "127.0.0.1 is valid":
+    check isIpAddress("127.0.0.1") == true
+
+  test "ipv6 localhost is valid":
+    check isIpAddress("::1") == true
+
+  test "fqdn is not an ip address":
+    check isIpAddress("example.com") == false
+
+  test "random string is not an ipaddress":
+    check isIpAddress("foo bar") == false
+
+  test "5127.0.0.1 is invalid":
+    check isIpAddress("5127.0.0.1") == false
+
+  test "ipv6 is valid":
+    check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true
+
+  test "invalid ipv6":
+    check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false
+
+
+suite "parseIpAddress tests":
+  test "127.0.0.1 is valid":
+    discard parseIpAddress("127.0.0.1")
+
+  test "ipv6 localhost is valid":
+    discard parseIpAddress("::1")
+
+  test "fqdn is not an ip address":
+    expect(ValueError):
+      discard parseIpAddress("example.com")
+
+  test "random string is not an ipaddress":
+    expect(ValueError):
+      discard parseIpAddress("foo bar")
+
+  test "ipv6 is valid":
+    discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652")
+
+  test "invalid ipv6":
+    expect(ValueError):
+      discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652")
diff --git a/tests/template/texponential_eval.nim b/tests/template/texponential_eval.nim
new file mode 100644
index 000000000..32af9e8f7
--- /dev/null
+++ b/tests/template/texponential_eval.nim
@@ -0,0 +1,47 @@
+# bug #1940
+
+discard """
+  nimout: '''===
+merge (A) with (B)
+merge (A B) with (C)
+merge (A B C) with (D)
+merge (A B C D) with (E)
+merge (A B C D E) with (F)
+==='''
+"""
+
+type SqlStmt = tuple
+  sql: string
+  parts: int
+
+proc sql(q: string): SqlStmt =
+  result.sql = q
+  result.parts = 1
+
+template `&%%`(x, y: SqlStmt): SqlStmt =
+  const a = x
+  const b = y
+
+  static:
+    #echo "some merge"
+    echo "merge (", a.sql, ") with (", b.sql, ")"
+
+
+  const newSql = a.sql & " " & b.sql
+  const newParts = a.parts + b.parts
+
+  SqlStmt((sql: newSql, parts: newParts))
+
+static:
+  echo "==="
+
+let c =(sql("A") &%%
+        sql("B")) &%%
+        sql("C")  &%%
+        sql("D") &%%
+        sql("E") &%%
+        sql("F")
+echo c.sql
+
+static:
+  echo "==="
diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim
index 4b3e1553f..bca1292b8 100644
--- a/tests/template/twrongmapit.nim
+++ b/tests/template/twrongmapit.nim
@@ -1,7 +1,7 @@
 discard """
   errormsg: "'"
   file: "sequtils.nim"
-  line: 416
+  line: 435
 """
 # unfortunately our tester doesn't support multiple lines of compiler
 # error messages yet...
diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim
index 38ad4f515..8b9ae5d26 100644
--- a/tests/template/utemplates.nim
+++ b/tests/template/utemplates.nim
@@ -12,7 +12,7 @@ test "previous definitions can be further overloaded or hidden in local scopes":
 
   check t(true) == "bool"
   check t(10) == "int"
-  
+
   template t(a: int): expr = "inner int"
   check t(10) == "inner int"
   check t("test") == "string"
@@ -21,12 +21,12 @@ test "templates can be redefined multiple times":
   template customAssert(cond: bool, msg: string): stmt {.immediate, dirty.} =
     if not cond: fail(msg)
 
-  template assertion_failed(body: stmt) {.immediate.} =
+  template assertion_failed(body: stmt) {.immediate, dirty.} =
     template fail(msg: string): stmt = body
 
   assertion_failed: check msg == "first fail path"
   customAssert false, "first fail path"
 
-  assertion_failed: check msg == "second fail path"  
+  assertion_failed: check msg == "second fail path"
   customAssert false, "second fail path"
 
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index ab1e46d6f..c293be7e8 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -86,9 +86,9 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
     safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
   else:
     # posix relies on crappy LD_LIBRARY_PATH (ugh!):
-    var libpath = getenv"LD_LIBRARY_PATH".string
-    if peg"\i '/nim' (!'/')* '/lib'" notin libpath:
-      echo "[Warning] insufficient LD_LIBRARY_PATH"
+    var libpath = getEnv"LD_LIBRARY_PATH".string
+    # Temporarily add the lib directory to LD_LIBRARY_PATH:
+    putEnv("LD_LIBRARY_PATH", "lib:" & libpath)
     var serverDll = DynlibFormat % "server"
     safeCopyFile("tests/dll" / serverDll, "lib" / serverDll)
   
@@ -302,8 +302,7 @@ proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
         continue
 
       let
-        buildPath = getPackageDir(name)[0.. -3]
-      let
+        buildPath = getPackageDir(name).strip
         buildProcess = startProcess(nimbleExe, buildPath, ["build"])
         buildStatus = waitForExitEx(buildProcess)
       buildProcess.close
@@ -318,7 +317,7 @@ proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
 
 # ----------------------------------------------------------------------------
 
-const AdditionalCategories = ["debugger", "examples", "lib", "nimble-core"]
+const AdditionalCategories = ["debugger", "examples", "lib"]
 
 proc `&.?`(a, b: string): string =
   # candidate for the stdlib?
diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim
index 04a1835d7..a9f739995 100644
--- a/tests/testament/htmlgen.nim
+++ b/tests/testament/htmlgen.nim
@@ -20,7 +20,7 @@ const
                           <td>Success</td></tr>"""
   TableFooter = "</table>"
   HtmlBegin = """<html>
-    <head> 
+    <head>
       <title>Test results</title>
       <style type="text/css">
       <!--""" & slurp("css/boilerplate.css") & "\n" &
@@ -28,13 +28,13 @@ const
       """
 ul#tabs { list-style-type: none; margin: 30px 0 0 0; padding: 0 0 0.3em 0; }
 ul#tabs li { display: inline; }
-ul#tabs li a { color: #42454a; background-color: #dedbde; 
-               border: 1px solid #c9c3ba; border-bottom: none; 
+ul#tabs li a { color: #42454a; background-color: #dedbde;
+               border: 1px solid #c9c3ba; border-bottom: none;
                padding: 0.3em; text-decoration: none; }
 ul#tabs li a:hover { background-color: #f1f0ee; }
-ul#tabs li a.selected { color: #000; background-color: #f1f0ee; 
+ul#tabs li a.selected { color: #000; background-color: #f1f0ee;
                         font-weight: bold; padding: 0.7em 0.3em 0.38em 0.3em; }
-div.tabContent { border: 1px solid #c9c3ba; 
+div.tabContent { border: 1px solid #c9c3ba;
                  padding: 0.5em; background-color: #f1f0ee; }
 div.tabContent.hide { display: none; }
       -->
@@ -43,7 +43,7 @@ div.tabContent.hide { display: none; }
 
     var tabLinks = new Array();
     var contentDivs = new Array();
-    
+
     function init() {
       // Grab the tab links and content divs from the page
       var tabListItems = document.getElementById('tabs').childNodes;
@@ -103,7 +103,7 @@ div.tabContent.hide { display: none; }
 
     </head>
     <body onload="init()">"""
-  
+
   HtmlEnd = "</body></html>"
 
 proc td(s: string): string =
@@ -115,8 +115,8 @@ proc getCommit(db: TDbConn, c: int): string =
     if commit == 0: result = thisCommit[0]
     inc commit
 
-proc generateHtml*(filename: string, commit: int) =
-  const selRow = """select name, category, target, action, 
+proc generateHtml*(filename: string, commit: int; onlyFailing: bool) =
+  const selRow = """select name, category, target, action,
                            expected, given, result
                     from TestResult
                     where [commit] = ? and machine = ?
@@ -140,17 +140,20 @@ proc generateHtml*(filename: string, commit: int) =
   for m in db.rows(sql"select id, name, os, cpu from Machine order by id"):
     outfile.writeln """<li><a href="#$#">$#: $#, $#</a></li>""" % m
   outfile.write("</ul>")
-  
+
   for currentMachine in db.rows(sql"select id from Machine order by id"):
     let m = currentMachine[0]
     outfile.write("""<div class="tabContent" id="$#">""" % m)
 
     outfile.write(TableHeader)
     for row in db.rows(sql(selRow), lastCommit, m):
-      outfile.write("<tr>")
-      for x in row:
-        outfile.write(x.td)
-      outfile.write("</tr>")
+      if onlyFailing and row.len > 0 and row[row.high] == "reSuccess":
+        discard
+      else:
+        outfile.write("<tr>")
+        for x in row:
+          outfile.write(x.td)
+        outfile.write("</tr>")
 
     outfile.write(TableFooter)
     outfile.write("</div>")
@@ -161,7 +164,7 @@ proc generateHtml*(filename: string, commit: int) =
 proc generateJson*(filename: string, commit: int) =
   const
     selRow = """select count(*),
-                           sum(result = 'reSuccess'), 
+                           sum(result = 'reSuccess'),
                            sum(result = 'reIgnored')
                 from TestResult
                 where [commit] = ? and machine = ?
@@ -174,9 +177,9 @@ proc generateJson*(filename: string, commit: int) =
                 on A.name = B.name and A.category = B.category
                 where A.[commit] = ? and B.[commit] = ? and A.machine = ?
                    and A.result != B.result"""
-    selResults = """select 
-                      category || '/' || target || '/' || name, 
-                      category, target, action, result, expected, given 
+    selResults = """select
+                      category || '/' || target || '/' || name,
+                      category, target, action, result, expected, given
                     from TestResult
                     where [commit] = ?"""
   var db = open(connection="testament.db", user="testament", password="",
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 881a41ce6..7cf902704 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -30,6 +30,7 @@ Arguments:
   arguments are passed to the compiler
 Options:
   --print                   also print results to the console
+  --failing                 only show failing/ignored tests
 """ % resultsFile
 
 type
@@ -48,7 +49,7 @@ type
 # ----------------------------------------------------------------------------
 
 let
-  pegLineError = 
+  pegLineError =
     peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error') ':' \s* {.*}"
   pegOtherError = peg"'Error:' \s* {.*}"
   pegSuccess = peg"'Hint: operation successful'.*"
@@ -107,7 +108,7 @@ proc addResult(r: var TResults, test: TTest,
                expected, given: string, success: TResultEnum) =
   let name = test.name.extractFilename & test.options
   backend.writeTestResult(name = name,
-                          category = test.cat.string, 
+                          category = test.cat.string,
                           target = $test.target,
                           action = $test.action,
                           result = $success,
@@ -142,31 +143,50 @@ proc generatedFile(path, name: string, target: TTarget): string =
     name.changeFileExt(ext)
 
 proc codegenCheck(test: TTest, check: string, given: var TSpec) =
-  if check.len > 0:
-    try:
-      let (path, name, ext2) = test.name.splitFile
-      let genFile = generatedFile(path, name, test.target)
-      echo genFile
-      let contents = readFile(genFile).string
-      if contents.find(check.peg) < 0:
+  try:
+    let (path, name, ext2) = test.name.splitFile
+    let genFile = generatedFile(path, name, test.target)
+    echo genFile
+    let contents = readFile(genFile).string
+    if check[0] == '\\':
+      # little hack to get 'match' support:
+      if not contents.match(check.peg):
         given.err = reCodegenFailure
-    except ValueError:
-      given.err = reInvalidPeg
-    except IOError:
-      given.err = reCodeNotFound
+    elif contents.find(check.peg) < 0:
+      given.err = reCodegenFailure
+  except ValueError:
+    given.err = reInvalidPeg
+    echo getCurrentExceptionMsg()
+  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
+  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)
   result = join(x, "\n")
 
+proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec;
+                         r: var TResults) =
+  var expectedmsg: string = ""
+  var givenmsg: string = ""
+  if given.err == reSuccess:
+    if expected.ccodeCheck.len > 0:
+      codegenCheck(test, expected.ccodeCheck, given)
+      expectedmsg = expected.ccodeCheck
+      givenmsg = given.msg
+    if expected.nimout.len > 0:
+      expectedmsg = expected.nimout
+      givenmsg = given.nimout.strip
+      nimoutCheck(test, expectedmsg, given)
+  if given.err == reSuccess: inc(r.passed)
+  r.addResult(test, expectedmsg, givenmsg, given.err)
+
 proc testSpec(r: var TResults, test: TTest) =
   # major entry point for a single test
   let tname = test.name.addFileExt(".nim")
@@ -179,13 +199,9 @@ proc testSpec(r: var TResults, test: TTest) =
   else:
     case expected.action
     of actionCompile:
-      var given = callCompiler(expected.cmd, test.name, test.options,
-                               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)
+      var given = callCompiler(expected.cmd, test.name,
+        test.options & " --hint[Path]:off --hint[Processing]:off", test.target)
+      compilerOutputTests(test, given, expected, r)
     of actionRun:
       var given = callCompiler(expected.cmd, test.name, test.options,
                                test.target)
@@ -215,11 +231,7 @@ proc testSpec(r: var TResults, test: TTest) =
             if bufB != strip(expected.outp):
               if not (expected.substr and expected.outp in bufB):
                 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)
+            compilerOutputTests(test, given, expected, r)
         else:
           r.addResult(test, expected.outp, "executable not found", reExeNotFound)
     of actionReject:
@@ -255,11 +267,13 @@ proc main() =
 
   backend.open()
   var optPrintResults = false
+  var optFailing = false
   var p = initOptParser()
   p.next()
-  if p.kind == cmdLongoption:
+  while p.kind == cmdLongoption:
     case p.key.string.normalize
     of "print", "verbose": optPrintResults = true
+    of "failing": optFailing = true
     else: quit Usage
     p.next()
   if p.kind != cmdArgument: quit Usage
@@ -283,7 +297,7 @@ proc main() =
   of "html":
     var commit = 0
     discard parseInt(p.cmdLineRest.string, commit)
-    generateHtml(resultsFile, commit)
+    generateHtml(resultsFile, commit, optFailing)
     generateJson(jsonFile, commit)
   else:
     quit Usage
diff --git a/todo.txt b/todo.txt
index 1d180f737..31c3a46db 100644
--- a/todo.txt
+++ b/todo.txt
@@ -4,7 +4,6 @@ version 0.10.4
 - improve GC-unsafety warnings
 - make 'nil' work for 'add' and 'len'
 - get rid of 'mget'; aka priority of 'var' needs to be 'var{lvalue}'
-- 'result' shadowing warning
 - disallow negative indexing
 - improve the parser; deal with  echo $foo  gotcha
 
@@ -53,8 +52,8 @@ Bugs
 - VM: Pegs do not work at compile-time
 - VM: ptr/ref T cannot work in general
 - scopes are still broken for generic instantiation!
-- compilation of niminst takes way too long. looks like a regression
 - blocks can "export" an identifier but the CCG generates {} for them ...
+- ConcreteTypes in a 'case' means we don't check for duplicated case branches
 
 
 version 0.9.x
diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl
index 191c39282..980915be3 100644
--- a/tools/niminst/buildsh.tmpl
+++ b/tools/niminst/buildsh.tmpl
@@ -62,7 +62,7 @@ case $uos in
     myos="freebsd"
     CC="clang"
     LINKER="clang"
-    LINK_FLAGS="$LINK_FLAGS -ldl -lm"
+    LINK_FLAGS="$LINK_FLAGS -lm"
     ;;
   *openbsd* )
     myos="openbsd" 
diff --git a/web/question.txt b/web/question.txt
index 28c7ece14..0733a2455 100644
--- a/web/question.txt
+++ b/web/question.txt
@@ -105,12 +105,13 @@ General FAQ
   --------------------------
 
   - Nim IDE: https://github.com/nim-lang/Aporia
-  - Emacs: https://github.com/Tass/nim-mode
+  - Emacs: https://github.com/reactormonk/nim-mode
   - Vim: https://github.com/zah/nimrod.vim/
   - Scite: Included
-  - Gedit: The `Aporia .lang file <https://github.com/nim-lang/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nimrod.lang>`_
+  - Gedit: The `Aporia .lang file <https://github.com/nim-lang/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nim.lang>`_
   - jEdit: https://github.com/exhu/nimrod-misc/tree/master/jedit
   - TextMate: Available in bundle installer (`Repository <https://github.com/textmate/nim.tmbundle>`_)
+  - Sublime Text: Available via Package Control (`Repository <https://github.com/Varriount/NimLime>`_)
 
 
 .. container:: standout
diff --git a/web/website.ini b/web/website.ini
index 696829764..6266f05bb 100644
--- a/web/website.ini
+++ b/web/website.ini
@@ -59,6 +59,7 @@ srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
 srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
 srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
 srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
+srcdoc2: "pure/asyncfile"
 srcdoc2: "pure/md5"
 srcdoc2: "posix/posix"
 srcdoc2: "pure/fenv"