summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim20
-rw-r--r--compiler/ccgcalls.nim11
-rw-r--r--compiler/guards.nim104
-rw-r--r--compiler/lowerings.nim51
-rw-r--r--compiler/renderer.nim474
-rw-r--r--compiler/semparallel.nim4
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/transf.nim1
-rw-r--r--lib/pure/algorithm.nim21
-rw-r--r--lib/pure/asyncdispatch.nim13
-rw-r--r--lib/pure/asyncfile.nim16
-rw-r--r--tests/init/tuninit2.nim54
-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/testament/tester.nim6
-rw-r--r--todo.txt1
-rw-r--r--web/question.txt5
18 files changed, 533 insertions, 333 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 8448c2a8f..ab315877a 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -807,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
 
@@ -1318,7 +1318,7 @@ 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}:
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/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/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/renderer.nim b/compiler/renderer.nim
index ccf3837ed..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,7 +394,7 @@ 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")
@@ -403,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
@@ -412,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)
@@ -426,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_:_")
@@ -447,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_")
@@ -470,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)
@@ -523,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
@@ -590,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)
@@ -626,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, ":")
@@ -636,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)
@@ -664,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)
@@ -685,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
@@ -733,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:
@@ -742,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!
@@ -750,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)
@@ -770,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)
@@ -789,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
@@ -827,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])
@@ -842,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])
@@ -851,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)
@@ -861,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
@@ -906,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, "}")
@@ -925,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")
@@ -950,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)
@@ -987,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])
@@ -1004,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])
@@ -1052,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])
@@ -1068,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])
@@ -1098,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")
@@ -1110,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)
@@ -1130,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")
@@ -1159,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:
@@ -1219,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)
@@ -1248,50 +1250,50 @@ 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)
@@ -1309,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
@@ -1339,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/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/semstmts.nim b/compiler/semstmts.nim
index db0b9b67f..19514263f 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -410,7 +410,7 @@ 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:
+            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 '=':
diff --git a/compiler/transf.nim b/compiler/transf.nim
index e5e3bbe63..7e56f09dc 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -152,6 +152,7 @@ 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:
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 05fcc9584..08d224dfd 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -196,7 +196,7 @@ proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
     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
@@ -204,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)
   ##
-  ##     echo users.sortByIt(it.name)
+  ##   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 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 bf905ed49..a8caf809e 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1323,14 +1323,25 @@ macro async*(prc: stmt): stmt {.immediate.} =
       newLit(prc[0].getName)))) # Get type from return type of this proc
 
   # -> 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)
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index 844c2ab55..25e121183 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -24,7 +24,7 @@
 
 import asyncdispatch, os
 
-when defined(windows):
+when defined(windows) or defined(nimdoc):
   import winlean
 else:
   import posix
@@ -34,7 +34,7 @@ type
     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/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/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/testament/tester.nim b/tests/testament/tester.nim
index 54ab67d85..7cf902704 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -148,7 +148,11 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) =
     let genFile = generatedFile(path, name, test.target)
     echo genFile
     let contents = readFile(genFile).string
-    if contents.find(check.peg) < 0:
+    if check[0] == '\\':
+      # little hack to get 'match' support:
+      if not contents.match(check.peg):
+        given.err = reCodegenFailure
+    elif contents.find(check.peg) < 0:
       given.err = reCodegenFailure
   except ValueError:
     given.err = reInvalidPeg
diff --git a/todo.txt b/todo.txt
index 69674f019..47180aaf1 100644
--- a/todo.txt
+++ b/todo.txt
@@ -54,6 +54,7 @@ Bugs
 - VM: ptr/ref T cannot work in general
 - scopes are still broken for generic instantiation!
 - 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/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